Compare commits

...

4 Commits

@ -1,73 +0,0 @@
1.8 (2018-02-04):
- prevent nick collisions by only setting the nick after the server
accepted it and print a message about change to server log.
- remove query.sh.
- add OpenBSD pledge(2) support.
- fix QUIT message string.
- raw IRC output to stdout.
- add quit command (/q [string]).
- write timestamp in outfile as UNIX timestamp (UTC+0).
- server host (-s) doesn't default to irc.freenode and is now required.
- add option (-u) to connect directly to a UNIX domain socket, this
is useful for tunneling connections.
- remove "in" file when leaving a channel (enabled commented code).
- remove "in" files on exit.
- use IRC_MAX (512), instead of PIPE_BUF (4096) on most systems.
PIPE_BUF is guaranteed to be atleast 512 bytes for atomic operations.
- Makefile: always be verbose.
- use C99 and -D_DEFAULT_SOURCE
- remove obsolete gethostbyname, use getaddrinfo.
- IPV6 support.
- timeout now uses separate exit statuscode 2.
- cleanup:
- use arg.h for command-line option parsing.
- use sbase util functions (estrtol, eprintf).
- use and import OpenBSD strlcpy().
- man page typos.
- style:
- linewrap to 79 characters.
- coding style fixes.
- non-roman numerals for LICENSE period.
1.7 (2013-01-05)
- -k now specifies an environment variable that contains the
server key. This behaviour has been changed in order to not
expose the password in the process list.
- Fix parsing of JOIN messages for certain servers.
Thanks Ivan Kanakarakis!
- Use , rather than _ for slash characters in channel names.
As per RFC , is not allowed in a channel name, while _ is.
Thanks plomplomplom and Nils Dagsson Moskopp!
1.6 (2011-01-31):
- fix regression introduced for handling unknown commands
1.5 (2011-01-24):
- fix channel name comparison in add_channel(), compare lowercase
to prevent leaking file descriptors in the long run => Thanks samurai!
- only handle commands ii explicitely understands and treat the rest
as raw irc (only worked for raw commands in capital lettersin the past) => Thanks samurai!
- create in FIFO on receiving a privmsg directly instead of requiring a new
/j command first => Thanks Evan Gates
this also implies that in FIFOs aren't deleted on channel leaves any longer because
this itself creates a channel event again which in turn would recreate the file
- minor changes
1.4 (2008-08-09):
- fix directory traversal on servers that support SAJOIN
NOTE: not marking as security relevant as it is only possible to
create directories outside (which is of course annoying) of the irc
hierarchy but not overwriting arbitrary files with the channel name.
- documentation fixes
- general cleanup
1.3 (2007-07-14):
- server messages about users (QUIT,JOIN) will no longer
go to the user directories but to the server out file to
give an easy method to monitor it and to prevent spamming
the irc directory.
1.2 (2007-06-23):
- Exit on channel creation failure, thanks Michael Prokop
- Implemented joining of password protected channels
- Removed -v option from the manpage since it's not implemented

19
FAQ

@ -6,6 +6,7 @@ Where is IRC command xy (ignore etc.)?
ii is for advanced users, please use standard tools like awk, sed and grep for
this. This can be done easily and will not bloat the code.
Where is a graphical interface?
-------------------------------
Basically ii follows the UNIX philosophy so it is only file based. But it
@ -14,12 +15,14 @@ the FIFOs and output files. Feel free to implement or wait until we have done
this. Actually I use ii in combination with vim, multitail and screen and it works
like a charm.
Which commands are supported?
-----------------------------
j (join or msg), t (topic), a (away), n (nick), l (leave). The missing are
obsolete or can be easily used by typing the IRC commands itself (i.e. /WHO
instead of /who).
How can I recognize queries?
----------------------------
ii itself doesn't support this but the queries.sh script is an example
@ -28,9 +31,23 @@ To get an instant notice of a new file other mechanisms like inotify/dnotify
could be used as well but I was too lazy to try it out since the script
is enough for me.
What other fancy stuff can I do with ii?
----------------------------------------
It is very easy to write irc bots in ii:
tail -f \#/out | while read foo; do name=echo $foo | awk '{print $2}' | sed 's,<\\(.*\\)>,\\1,'; if 0 -eq expr $RANDOM % 10 then echo "$name: WHAT??" ; fi; done
#!/bin/sh
chan="#yourchannel"
tail -f "${chan}/out" | while read -r line; do
cmd=$(printf '%s\n' "$line" | cut -d ' ' -f 4-)
name=$(printf '%s\n' "$line" | cut -d ' ' -f 3 | tr -d '<>')
if [ "$cmd" = "!rand" ]; then
r="$RANDOM"
if expr "$r" "%" "10"; then
echo "$name: $r" >> "${chan}/in"
fi
fi
done
This will just spam a channel but think about using nagios2irc or you can
use ii to generate channel stats. Your imagination should be boundless.

@ -1,7 +1,8 @@
MIT/X Consortium License
(C)opyright MMV-MMVI Anselm R. Garbe <garbeam@wmii.de>
(C)opyright MMV-MMVIII Nico Golde <nico at ngolde dot de>
(C)opyright 2014-2022 Hiltjo Posthuma <hiltjo at codemadness dot org>
(C)opyright 2005-2006 Anselm R. Garbe <garbeam@wmii.de>
(C)opyright 2005-2011 Nico Golde <nico at ngolde dot de>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

@ -1,55 +1,60 @@
# ii - irc it - simple but flexible IRC client
# (C)opyright MMV-MMVI Anselm R. Garbe
# (C)opyright MMV-MMVII Anselm R. Garbe, Nico Golde
.POSIX:
include config.mk
VERSION = 2.0
SRC = ii.c
OBJ = ${SRC:.c=.o}
# paths
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
DOCPREFIX = $(PREFIX)/share/doc
all: options ii
@echo built ii
SRC = ii.c
OBJ = $(SRC:.c=.o)
# use system flags.
II_CFLAGS = $(CFLAGS)
II_LDFLAGS = $(LDFLAGS) -lssl -lcrypto
# on systems which provide strlcpy(3),
# remove NEED_STRLCPY from CPPFLAGS and
# remove strlcpy.o from LIBS
II_CPPFLAGS = $(CPPFLAGS) -DVERSION=\"$(VERSION)\" -D_DEFAULT_SOURCE -DNEED_STRLCPY
LIBS = strlcpy.o
all: ii
options:
@echo ii build options:
@echo "LIBS = ${LIBS}"
@echo "INCLUDES = ${INCLUDES}"
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
@echo "CFLAGS = $(CFLAGS)"
@echo "LDFLAGS = $(LDFLAGS)"
@echo "CC = $(CC)"
.c.o:
@echo CC $<
@${CC} -c ${CFLAGS} $<
$(CC) -c $< $(II_CFLAGS) $(II_CPPFLAGS)
dist: clean
@mkdir -p ii-${VERSION}
@cp -R query.sh Makefile CHANGES README FAQ LICENSE config.mk ii.c ii.1 ii-${VERSION}
@tar -cf ii-${VERSION}.tar ii-${VERSION}
@gzip ii-${VERSION}.tar
@rm -rf ii-${VERSION}
@echo created distribution ii-${VERSION}.tar.gz
ii: $(OBJ) $(LIBS)
$(CC) -o $@ $(OBJ) $(LIBS) $(II_LDFLAGS)
ii: ${OBJ}
@echo LD $@
@${CC} -o $@ ${OBJ} ${LDFLAGS}
$(OBJ): arg.h
install: all
@mkdir -p ${DESTDIR}${DOCDIR}
@mkdir -p ${DESTDIR}${BINDIR}
@mkdir -p ${DESTDIR}${MAN1DIR}
@install -d ${DESTDIR}${BINDIR} ${DESTDIR}${MAN1DIR}
@install -m 644 CHANGES README query.sh FAQ LICENSE ${DESTDIR}${DOCDIR}
@install -m 775 ii ${DESTDIR}${BINDIR}
@install -m 444 ii.1 ${DESTDIR}${MAN1DIR}
@echo "installed ii"
mkdir -p $(DESTDIR)$(PREFIX)/bin
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
mkdir -p $(DESTDIR)$(DOCPREFIX)/ii
install -m 644 README FAQ LICENSE $(DESTDIR)$(DOCPREFIX)/ii
install -m 775 ii $(DESTDIR)$(PREFIX)/bin
sed "s/VERSION/$(VERSION)/g" < ii.1 > $(DESTDIR)$(MANPREFIX)/man1/ii.1
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/ii.1
uninstall: all
@rm -f ${DESTDIR}${MAN1DIR}/ii.1
@rm -rf ${DESTDIR}${DOCDIR}
@rm -f ${DESTDIR}${BINDIR}/ii
@echo "uninstalled ii"
rm -f $(DESTDIR)$(MANPREFIX)/man1/ii.1 $(DESTDIR)$(PREFIX)/bin/ii
rm -rf $(DESTDIR)$(DOCPREFIX)/ii
dist: clean
mkdir -p ii-$(VERSION)
cp -R Makefile README FAQ LICENSE strlcpy.c arg.h \
ii.c ii.1 ii-$(VERSION)
tar -cf - ii-$(VERSION) | gzip -c > ii-$(VERSION).tar.gz
rm -rf ii-$(VERSION)
clean:
rm -f ii *~ *.o *core *.tar.gz
rm -f ii *.o

@ -1,8 +1,16 @@
# ii
This is my patched version of ii, a commandline irc client.
The base version is directly from suckless.org.
Due to problems with newer version it uses the version 1.7.
This is my patched version of ii. The base version is directly from suckless.org.
## Patches
The list below shows the currently applied patches to this build.
- ii-1.7-ssl.diff
The list below shows the currently applied patches to the master branch.
- ii-2.0-ssl.diff (adds SSL compatibility)
## Installation
The most basic way is to clone the repository and then invoke make.
- `git clone https://github.com/tiyn/ii`
- `make clean install`

50
arg.h

@ -0,0 +1,50 @@
/*
* Copy me if you can.
* by 20h
*/
#ifndef ARG_H__
#define ARG_H__
extern char *argv0;
/* use main(int argc, char *argv[]) */
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
argv[0] && argv[0][0] == '-'\
&& argv[0][1];\
argc--, argv++) {\
char argc_;\
char **argv_;\
int brk_;\
if (argv[0][1] == '-' && argv[0][2] == '\0') {\
argv++;\
argc--;\
break;\
}\
int i_;\
for (i_ = 1, brk_ = 0, argv_ = argv;\
argv[0][i_] && !brk_;\
i_++) {\
if (argv_ != argv)\
break;\
argc_ = argv[0][i_];\
switch (argc_)
#define ARGEND }\
}
#define ARGC() argc_
#define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
((x), abort(), (char *)0) :\
(brk_ = 1, (argv[0][i_+1] != '\0')?\
(&argv[0][i_+1]) :\
(argc--, argv++, argv[0])))
#define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
(char *)0 :\
(brk_ = 1, (argv[0][i_+1] != '\0')?\
(&argv[0][i_+1]) :\
(argc--, argv++, argv[0])))
#endif

@ -1,27 +0,0 @@
# Customize to fit your system
# paths
PREFIX = /usr/local
BINDIR = ${PREFIX}/bin
MANDIR = ${PREFIX}/share/man
MAN1DIR = ${MANDIR}/man1
DOCDIR = ${PREFIX}/share/doc/ii
# Set the following to install to a different root
DESTDIR =
INCDIR = ${PREFIX}/include
LIBDIR = ${PREFIX}/lib
VERSION = 1.7
# includes and libs
INCLUDES = -I. -I${INCDIR} -I/usr/include
LIBS = -L${LIBDIR} -L/usr/lib -lc -lssl -lcrypto
# uncomment and comment other variables for compiling on Solaris
#LIBS = -L${LIBDIR} -L/usr/lib -lc -lsocket -lnsl
#CFLAGS = -g ${INCLUDES} -DVERSION=\"${VERSION}\"
# compiler
CC = cc
CFLAGS = -g -O0 -W -Wall ${INCLUDES} -DVERSION=\"${VERSION}\"
LDFLAGS = ${LIBS}

@ -1,225 +0,0 @@
diff -up a/config.mk b/config.mk
--- a/config.mk 2013-01-05 08:26:47.000000000 -0500
+++ b/config.mk 2013-02-15 15:27:10.183075163 -0500
@@ -16,7 +16,7 @@ VERSION = 1.7
# includes and libs
INCLUDES = -I. -I${INCDIR} -I/usr/include
-LIBS = -L${LIBDIR} -L/usr/lib -lc
+LIBS = -L${LIBDIR} -L/usr/lib -lc -lssl -lcrypto
# uncomment and comment other variables for compiling on Solaris
#LIBS = -L${LIBDIR} -L/usr/lib -lc -lsocket -lnsl
#CFLAGS = -g ${INCLUDES} -DVERSION=\"${VERSION}\"
diff -up a/ii.1 b/ii.1
--- a/ii.1 2013-01-05 08:26:47.000000000 -0500
+++ b/ii.1 2013-02-15 15:28:42.739074771 -0500
@@ -25,6 +25,8 @@ and ii creates a new channel directory w
.IR servername ]
.RB [ \-p
.IR port ]
+.RB [ \-e
+.IR ssl ]
.RB [ \-k
.IR environment variable ]
.RB [ \-i
@@ -42,6 +44,9 @@ lets you override the default servername
.BI \-p " port"
lets you override the default port (6667)
.TP
+.BI \-e " ssl"
+lets you connect using ssl encryption. The default ssl port is 6697.
+.TP
.BI \-k " environment variable"
lets you specify an environment variable that contains your IRC password, e.g. IIPASS="foobar" ii -k IIPASS.
This is done in order to prevent other users from eavesdropping the server password via the process list.
diff -up a/ii.c b/ii.c
--- a/ii.c 2013-01-05 08:26:47.000000000 -0500
+++ b/ii.c 2013-02-15 15:33:39.603075095 -0500
@@ -18,12 +18,23 @@
#include <ctype.h>
#include <time.h>
#include <unistd.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
#ifndef PIPE_BUF /* FreeBSD don't know PIPE_BUF */
#define PIPE_BUF 4096
#endif
#define PING_TIMEOUT 300
#define SERVER_PORT 6667
+#define SSL_SERVER_PORT 6697
+#define WRITE(con, mes, len) (use_ssl ? SSL_write(irc->sslHandle, mes, len) : write(con->irc, mes, len))
+#define READ(fd, buf, size) (from_server && use_ssl ? SSL_read(irc->sslHandle, buf, size) : read(fd, buf, size))
+typedef struct {
+ int irc;
+ SSL *sslHandle;
+ SSL_CTX *sslContext;
+} conn;
enum { TOK_NICKSRV = 0, TOK_USER, TOK_CMD, TOK_CHAN, TOK_ARG, TOK_TEXT, TOK_LAST };
typedef struct Channel Channel;
@@ -33,7 +44,8 @@ struct Channel {
Channel *next;
};
-static int irc;
+conn *irc;
+static int use_ssl;
static time_t last_response;
static Channel *channels = NULL;
static char *host = "irc.freenode.net";
@@ -45,7 +57,7 @@ static void usage() {
fputs("ii - irc it - " VERSION "\n"
"(C)opyright MMV-MMVI Anselm R. Garbe\n"
"(C)opyright MMV-MMXI Nico Golde\n"
- "usage: ii [-i <irc dir>] [-s <host>] [-p <port>]\n"
+ "usage: ii [-i <irc dir>] [-s <host>] [-p <port>] [-e ssl]\n"
" [-n <nick>] [-k <password>] [-f <fullname>]\n", stderr);
exit(EXIT_FAILURE);
}
@@ -148,11 +160,12 @@ static void login(char *key, char *fulln
nick, nick, host, fullname ? fullname : nick);
else snprintf(message, PIPE_BUF, "NICK %s\r\nUSER %s localhost %s :%s\r\n",
nick, nick, host, fullname ? fullname : nick);
- write(irc, message, strlen(message)); /* login */
+ WRITE(irc, message, strlen(message)); /* login */
}
-static int tcpopen(unsigned short port) {
+conn *tcpopen(unsigned short port) {
int fd;
+ conn *c;
struct sockaddr_in sin;
struct hostent *hp = gethostbyname(host);
@@ -172,7 +185,22 @@ static int tcpopen(unsigned short port)
perror("ii: cannot connect to host");
exit(EXIT_FAILURE);
}
- return fd;
+ c = malloc(sizeof(conn));
+ c->irc = fd;
+ if(use_ssl) {
+ c->sslHandle = NULL;
+ c->sslContext = NULL;
+ SSL_load_error_strings();
+ SSL_library_init();
+ c->sslContext = SSL_CTX_new(SSLv23_client_method());
+ if(c->sslContext == NULL)
+ ERR_print_errors_fp(stderr);
+ c->sslHandle = SSL_new(c->sslContext);
+ if(!SSL_set_fd(c->sslHandle, c->irc)
+ || (SSL_connect(c->sslHandle) != 1))
+ ERR_print_errors_fp(stderr);
+ }
+ return c;
}
static size_t tokenize(char **result, size_t reslen, char *str, char delim) {
@@ -219,7 +247,7 @@ static void proc_channels_privmsg(char *
snprintf(message, PIPE_BUF, "<%s> %s", nick, buf);
print_out(channel, message);
snprintf(message, PIPE_BUF, "PRIVMSG %s :%s\r\n", channel, buf);
- write(irc, message, strlen(message));
+ WRITE(irc, message, strlen(message));
}
static void proc_channels_input(Channel *c, char *buf) {
@@ -273,7 +301,7 @@ static void proc_channels_input(Channel
else
snprintf(message, PIPE_BUF,
"PART %s :ii - 500 SLOC are too much\r\n", c->name);
- write(irc, message, strlen(message));
+ WRITE(irc, message, strlen(message));
close(c->fd);
/*create_filepath(infile, sizeof(infile), c->name, "in");
unlink(infile); */
@@ -288,7 +316,7 @@ static void proc_channels_input(Channel
snprintf(message, PIPE_BUF, "%s\r\n", &buf[1]);
if (message[0] != '\0')
- write(irc, message, strlen(message));
+ WRITE(irc, message, strlen(message));
}
static void proc_server_cmd(char *buf) {
@@ -339,7 +367,7 @@ static void proc_server_cmd(char *buf) {
return;
} else if(!strncmp("PING", argv[TOK_CMD], 5)) {
snprintf(message, PIPE_BUF, "PONG %s\r\n", argv[TOK_TEXT]);
- write(irc, message, strlen(message));
+ WRITE(irc, message, strlen(message));
return;
} else if(!argv[TOK_NICKSRV] || !argv[TOK_USER]) { /* server command */
snprintf(message, PIPE_BUF, "%s%s", argv[TOK_ARG] ? argv[TOK_ARG] : "", argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
@@ -373,11 +401,11 @@ static void proc_server_cmd(char *buf) {
print_out(argv[TOK_CHAN], message);
}
-static int read_line(int fd, size_t res_len, char *buf) {
+static int read_line(int fd, size_t res_len, char *buf, int from_server) {
size_t i = 0;
char c = 0;
do {
- if(read(fd, &c, sizeof(char)) != sizeof(char))
+ if(READ(fd, &c, sizeof(char)) != sizeof(char))
return -1;
buf[i++] = c;
}
@@ -388,7 +416,7 @@ static int read_line(int fd, size_t res_
static void handle_channels_input(Channel *c) {
static char buf[PIPE_BUF];
- if(read_line(c->fd, PIPE_BUF, buf) == -1) {
+ if(read_line(c->fd, PIPE_BUF, buf, 0) == -1) {
close(c->fd);
int fd = open_channel(c->name);
if(fd != -1)
@@ -402,7 +430,7 @@ static void handle_channels_input(Channe
static void handle_server_output() {
static char buf[PIPE_BUF];
- if(read_line(irc, PIPE_BUF, buf) == -1) {
+ if(read_line(irc->irc, PIPE_BUF, buf, 1) == -1) {
perror("ii: remote host closed connection");
exit(EXIT_FAILURE);
}
@@ -419,8 +447,8 @@ static void run() {
snprintf(ping_msg, sizeof(ping_msg), "PING %s\r\n", host);
for(;;) {
FD_ZERO(&rd);
- maxfd = irc;
- FD_SET(irc, &rd);
+ maxfd = irc->irc;
+ FD_SET(irc->irc, &rd);
for(c = channels; c; c = c->next) {
if(maxfd < c->fd)
maxfd = c->fd;
@@ -440,10 +468,10 @@ static void run() {
print_out(NULL, "-!- ii shutting down: ping timeout");
exit(EXIT_FAILURE);
}
- write(irc, ping_msg, strlen(ping_msg));
+ WRITE(irc, ping_msg, strlen(ping_msg));
continue;
}
- if(FD_ISSET(irc, &rd)) {
+ if(FD_ISSET(irc->irc, &rd)) {
handle_server_output();
last_response = time(NULL);
}
@@ -475,10 +503,13 @@ int main(int argc, char *argv[]) {
case 'p': port = strtol(argv[++i], NULL, 10); break;
case 'n': snprintf(nick,sizeof(nick),"%s", argv[++i]); break;
case 'k': key = getenv(argv[++i]); break;
+ case 'e': use_ssl = 1; ++i; break;
case 'f': fullname = argv[++i]; break;
default: usage(); break;
}
}
+ if(use_ssl)
+ port = port == SERVER_PORT ? SSL_SERVER_PORT : port;
irc = tcpopen(port);
if(!snprintf(path, sizeof(path), "%s/%s", prefix, host)) {
fputs("ii: path to irc directory too long\n", stderr);

@ -0,0 +1,400 @@
From 20b47a9dbf4c8299f01d0d73f112ece58da8cabb Mon Sep 17 00:00:00 2001
From: Jon Eskin <eskinjp@gmail.com>
Date: Wed, 4 Jan 2023 06:20:19 -0500
Subject: [PATCH] porting ssl patch to 2.0
---
Makefile | 2 +-
ii.1 | 5 ++
ii.c | 156 ++++++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 125 insertions(+), 38 deletions(-)
diff --git a/Makefile b/Makefile
index 28c7781..23db7c1 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ OBJ = $(SRC:.c=.o)
# use system flags.
II_CFLAGS = $(CFLAGS)
-II_LDFLAGS = $(LDFLAGS)
+II_LDFLAGS = $(LDFLAGS) -lssl -lcrypto
# on systems which provide strlcpy(3),
# remove NEED_STRLCPY from CPPFLAGS and
diff --git a/ii.1 b/ii.1
index 59fd798..3ddc376 100644
--- a/ii.1
+++ b/ii.1
@@ -7,6 +7,8 @@ ii - irc it or irc improved
.I host
.RB [ -p
.I port
+.RB [ \-e
+.IR ssl ]
|
.B -u
.IR sockname ]
@@ -40,6 +42,9 @@ server/host to connect to, for example: irc.freenode.net
.BI -p " port"
lets you override the default port (6667)
.TP
+.BI \-e " ssl"
+lets you connect using ssl encryption. The default ssl port is 6697.
+.TP
.BI -u " sockname"
connect to a UNIX domain socket instead of directly to a server.
If set, the
diff --git a/ii.c b/ii.c
index c402a87..6de4157 100644
--- a/ii.c
+++ b/ii.c
@@ -20,6 +20,10 @@
#include <time.h>
#include <unistd.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
char *argv0;
#include "arg.h"
@@ -43,6 +47,14 @@ struct Channel {
Channel *next;
};
+typedef struct {
+ int use_ssl;
+ int irc;
+ SSL *sslHandle;
+ SSL_CTX *sslContext;
+} conn;
+
+
static Channel * channel_add(const char *);
static Channel * channel_find(const char *);
static Channel * channel_join(const char *);
@@ -57,21 +69,24 @@ static void channel_rm(Channel *);
static void cleanup(void);
static void create_dirtree(const char *);
static void create_filepath(char *, size_t, const char *, const char *, const char *);
+static int swrite(conn *, const char *, size_t);
+static void ewritestr(conn *, const char *);
+static void handle_channels_input(conn *, Channel *);
+static void handle_server_output(conn *);
static void die(const char *, ...);
-static void ewritestr(int, const char *);
-static void handle_channels_input(int, Channel *);
-static void handle_server_output(int);
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 int read_line(int, char *, size_t);
-static void run(int, const char *);
+static void loginkey(conn *, const char *);
+static void loginuser(conn *, const char *, const char *);
+static void proc_channels_input(conn *, Channel *, char *);
+static void proc_channels_privmsg(conn *, Channel *, char *);
+static void proc_server_cmd(conn *, char *);
+static int sread(conn *, char *, size_t);
+static int read_line(conn *, char *, size_t);
+static int read_line_from_channel(int, char *, size_t);
+static void run(conn *, const char *);
static void setup(void);
static void sighandler(int);
-static int tcpopen(const char *, const char *);
+static void tcpopen(conn *ircfd, const char *, const char *);
static size_t tokenize(char **, size_t, char *, int);
static int udsopen(const char *);
static void usage(void);
@@ -102,18 +117,27 @@ static void
usage(void)
{
die("usage: %s -s host [-p port | -u sockname] [-i ircdir]\n"
- " [-n nickname] [-f fullname] [-k env_pass]\n", argv0);
+ " [-e <ssl>] [-n nickname] [-f fullname] [-k env_pass]\n", argv0);
+}
+
+static int
+swrite(conn *ircfd, const char *msg, size_t len)
+{
+ if (ircfd->use_ssl)
+ return SSL_write(ircfd->sslHandle, msg, len);
+
+ return write(ircfd->irc, msg, len);
}
static void
-ewritestr(int fd, const char *s)
+ewritestr(conn *fd, 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 = swrite(fd, s + off, len - off)) == -1)
break;
}
if (w == -1)
@@ -185,6 +209,7 @@ cleanup(void)
tmp = c->next;
channel_leave(c);
}
+
}
static void
@@ -341,14 +366,14 @@ channel_leave(Channel *c)
}
static void
-loginkey(int ircfd, const char *key)
+loginkey(conn *ircfd, const char *key)
{
snprintf(msg, sizeof(msg), "PASS %s\r\n", key);
ewritestr(ircfd, msg);
}
static void
-loginuser(int ircfd, const char *host, const char *fullname)
+loginuser(conn *ircfd, const char *host, const char *fullname)
{
snprintf(msg, sizeof(msg), "NICK %s\r\nUSER %s localhost %s :%s\r\n",
nick, nick, host, fullname);
@@ -377,12 +402,15 @@ udsopen(const char *uds)
return fd;
}
-static int
-tcpopen(const char *host, const char *service)
+static void
+tcpopen(conn *ircfd, const char *host, const char *service)
{
struct addrinfo hints, *res = NULL, *rp;
int fd = -1, e;
+ ircfd->sslHandle = NULL;
+ ircfd->sslContext = NULL;
+
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* allow IPv4 or IPv6 */
hints.ai_flags = AI_NUMERICSERV; /* avoid name lookup for port */
@@ -407,7 +435,19 @@ tcpopen(const char *host, const char *service)
argv0, host, service, strerror(errno));
freeaddrinfo(res);
- return fd;
+ ircfd->irc = fd;
+ if (!ircfd->use_ssl)
+ return;
+
+ //SSL_load_error_strings();
+ //SSL_library_init();
+ ircfd->sslContext = SSL_CTX_new(SSLv23_client_method());
+ if (ircfd->sslContext == NULL)
+ ERR_print_errors_fp(stderr);
+ ircfd->sslHandle = SSL_new(ircfd->sslContext);
+ if (!SSL_set_fd(ircfd->sslHandle, ircfd->irc) ||
+ (SSL_connect(ircfd->sslHandle) != 1))
+ ERR_print_errors_fp(stderr);
}
static int
@@ -459,7 +499,7 @@ channel_print(Channel *c, const char *buf)
}
static void
-proc_channels_privmsg(int ircfd, Channel *c, char *buf)
+proc_channels_privmsg(conn *ircfd, Channel *c, char *buf)
{
snprintf(msg, sizeof(msg), "<%s> %s", nick, buf);
channel_print(c, msg);
@@ -468,7 +508,7 @@ proc_channels_privmsg(int ircfd, Channel *c, char *buf)
}
static void
-proc_channels_input(int ircfd, Channel *c, char *buf)
+proc_channels_input(conn *ircfd, Channel *c, char *buf)
{
char *p = NULL;
size_t buflen;
@@ -560,7 +600,7 @@ proc_channels_input(int ircfd, Channel *c, char *buf)
}
static void
-proc_server_cmd(int fd, char *buf)
+proc_server_cmd(conn *fd, char *buf)
{
Channel *c;
const char *channel;
@@ -679,8 +719,33 @@ proc_server_cmd(int fd, char *buf)
channel_print(c, msg);
}
+
+static int
+sread(conn *fd, char *buf, size_t bufsize)
+{
+ if (fd->use_ssl)
+ return SSL_read(fd->sslHandle, buf, bufsize);
+
+ return read(fd->irc, buf, bufsize);
+}
+
static int
-read_line(int fd, char *buf, size_t bufsiz)
+read_line(conn *fd, char *buf, size_t bufsiz)
+{
+ size_t i = 0;
+ char c = '\0';
+
+ do {
+ if (sread(fd, &c, sizeof(char)) != sizeof(char))
+ return -1;
+ buf[i++] = c;
+ } while (c != '\n' && i < bufsiz);
+ buf[i - 1] = '\0'; /* eliminates '\n' */
+ return 0;
+}
+
+static int
+read_line_from_channel(int fd, char *buf, size_t bufsiz)
{
size_t i = 0;
char c = '\0';
@@ -695,7 +760,7 @@ read_line(int fd, char *buf, size_t bufsiz)
}
static void
-handle_channels_input(int ircfd, Channel *c)
+handle_channels_input(conn *ircfd, Channel *c)
{
/*
* Do not allow to read this fully, since commands will be
@@ -706,7 +771,7 @@ handle_channels_input(int ircfd, Channel *c)
*/
char buf[IRC_MSG_MAX-64];
- if (read_line(c->fdin, buf, sizeof(buf)) == -1) {
+ if (read_line_from_channel(c->fdin, buf, sizeof(buf)) == -1) {
if (channel_reopen(c) == -1)
channel_rm(c);
return;
@@ -715,7 +780,7 @@ handle_channels_input(int ircfd, Channel *c)
}
static void
-handle_server_output(int ircfd)
+handle_server_output(conn *ircfd)
{
char buf[IRC_MSG_MAX];
@@ -746,7 +811,7 @@ setup(void)
}
static void
-run(int ircfd, const char *host)
+run(conn *ircfd, const char *host)
{
Channel *c, *tmp;
fd_set rdset;
@@ -756,9 +821,9 @@ run(int ircfd, const char *host)
snprintf(ping_msg, sizeof(ping_msg), "PING %s\r\n", host);
while (isrunning) {
- maxfd = ircfd;
+ maxfd = ircfd->irc;
FD_ZERO(&rdset);
- FD_SET(ircfd, &rdset);
+ FD_SET(ircfd->irc, &rdset);
for (c = channels; c; c = c->next) {
if (c->fdin > maxfd)
maxfd = c->fdin;
@@ -780,7 +845,7 @@ run(int ircfd, const char *host)
ewritestr(ircfd, ping_msg);
continue;
}
- if (FD_ISSET(ircfd, &rdset)) {
+ if (FD_ISSET(ircfd->irc, &rdset)) {
handle_server_output(ircfd);
last_response = time(NULL);
}
@@ -797,9 +862,12 @@ main(int argc, char *argv[])
{
struct passwd *spw;
const char *key = NULL, *fullname = NULL, *host = "";
- const char *uds = NULL, *service = "6667";
+ const char *uds = NULL;
+ const char *service = "6667";
+ const char *sservice = "6697";
char prefix[PATH_MAX];
- int ircfd, r;
+ int r, defaultPort = 1;
+ conn ircfd;
/* use nickname and home dir of user by default */
if (!(spw = getpwuid(getuid())))
@@ -823,6 +891,7 @@ main(int argc, char *argv[])
break;
case 'p':
service = EARGF(usage());
+ defaultPort = 0;
break;
case 's':
host = EARGF(usage());
@@ -830,6 +899,11 @@ main(int argc, char *argv[])
case 'u':
uds = EARGF(usage());
break;
+ case 'e':
+ if (defaultPort)
+ service = sservice;
+ ircfd.use_ssl = 1;
+ break;
default:
usage();
break;
@@ -839,9 +913,9 @@ main(int argc, char *argv[])
usage();
if (uds)
- ircfd = udsopen(uds);
+ ircfd.irc = udsopen(uds);
else
- ircfd = tcpopen(host, service);
+ tcpopen(&ircfd, host, service);
#ifdef __OpenBSD__
/* OpenBSD pledge(2) support */
@@ -856,11 +930,19 @@ main(int argc, char *argv[])
channelmaster = channel_add(""); /* master channel */
if (key)
- loginkey(ircfd, key);
- loginuser(ircfd, host, fullname && *fullname ? fullname : nick);
+ loginkey(&ircfd, key);
+ loginuser(&ircfd, host, fullname && *fullname ? fullname : nick);
setup();
- run(ircfd, host);
+ run(&ircfd, host);
cleanup();
+ if (ircfd.use_ssl) {
+ SSL_shutdown(ircfd.sslHandle);
+ SSL_free(ircfd.sslHandle);
+ SSL_CTX_free(ircfd.sslContext);
+ }
+
+ close(ircfd.irc);
+
return 0;
}
--
2.39.0

152
ii.1

@ -1,16 +1,31 @@
.de FN
\fI\|\\$1\|\fP\\$2
..
.TH ii 1
.TH II 1 ii-VERSION
.SH NAME
ii \- irc it or irc improved
ii - irc it or irc improved
.SH SYNOPSIS
.B ii
.B -s
.I host
.RB [ -p
.I port
.RB [ \-e
.IR ssl ]
|
.B -u
.IR sockname ]
.RB [ -i
.IR ircdir ]
.RB [ -n
.IR nickname ]
.RB [ -f
.IR realname ]
.RB [ -k
.IR env_pass ]
.SH DESCRIPTION
.B ii
is a minimalistic FIFO and filesystem based IRC client.
It creates an irc directory tree with server, channel and
nick name directories.
In every directory a FIFO file (in) and and normal file (out)
In every directory a FIFO file (in) and normal file (out)
is placed. This will be for example ~/irc/irc.freenode.net/.
The in file is used to communicate with the servers and the out
files includes the server messages. For every channel and every nick
@ -19,84 +34,93 @@ 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.
.SH SYNOPSIS
.B ii
.RB [ \-s
.IR servername ]
.RB [ \-p
.IR port ]
.RB [ \-e
.IR ssl ]
.RB [ \-k
.IR environment variable ]
.RB [ \-i
.IR prefix ]
.RB [ \-n
.IR nickname ]
.RB [ \-f
.IR realname ]
.SH OPTIONS
.TP
.BI \-s " servername"
lets you override the default servername (irc.freenode.net)
.BI -s " host"
server/host to connect to, for example: irc.freenode.net
.TP
.BI \-p " port"
.BI -p " port"
lets you override the default port (6667)
.TP
.BI \-e " ssl"
lets you connect using ssl encryption. The default ssl port is 6697.
.TP
.BI \-k " environment variable"
lets you specify an environment variable that contains your IRC password, e.g. IIPASS="foobar" ii -k IIPASS.
This is done in order to prevent other users from eavesdropping the server password via the process list.
.BI -u " sockname"
connect to a UNIX domain socket instead of directly to a server.
If set, the
.B -p
option will be ignored.
.TP
.BI \-i " prefix"
.BI -i " ircdir"
lets you override the default irc path (~/irc)
.TP
.BI \-n " nickname"
.BI -n " nickname"
lets you override the default nick ($USER)
.TP
.BI \-f " realname"
.BI -f " realname"
lets you specify your real name associated with your nick
.TP
.BI -k " env_pass"
lets you specify an environment variable that contains your IRC password,
e.g. IIPASS="foobar" ii -k IIPASS.
This is done in order to prevent other users from eavesdropping the server
password via the process list.
.SH DIRECTORIES
.TP
.FN ~/irc
.B ~/irc
In this directory the irc tree will be created. In this directory you
will find a directory for your server (default: irc.freenode.net) in
which the FIFO and the output file will be stored.
If you join a channel a new directory with the name of the channel
will be created in the ~/irc/$servername/ directory.
will be created in the
.BI ~/irc/ servername /
directory.
.SH COMMANDS
.TP
.FN /a " [<message>]"
mark yourself as away
.TP
.FN /j " #channel/nickname [<message>]"
join a channel or open private conversation with user
.TP
.FN /l " #channel/nickname"
leave a channel or query
.TP
.FN /n " nick"
change the nick name
.TP
.FN /t " topic"
set the topic of a channel
.TP
Everything which is not a command will simply be posted into the channel or to the server.
So if you need /who just write /WHO as described in the RFC to the server in FIFO.
.TP
.FN "out file usage"
Write wrappers, pagers or use your tools of choice to display the out file contents (loco, multitail, etc.).
.SH CONTACT
.TP
Write to ii (at) modprobe (dot) de for suggestions, fixes, 7|-|>< ;) etc.
.SH AUTHORS
Copyright \(co 2005-2006 by Anselm R. Garbe <garbeam (at) gmail (dot) com> and
Copyright \(co 2005-2008 by Nico Golde <nico (at) ngolde (dot) de>
.BI /a " [message]"
mark yourself as away,
with the optional
.I message
as an away reason.
.TP
.BI /j " #channel [password]"
join a
.IR #channel ,
with the optional
.IR password .
.TP
.BI /j " nickname [message]"
open private conversation with user
.I nickname
and directly send the optional
.IR message .
.TP
.BI /l " [reason]"
leave a channel or query,
giving the optional
.I reason
message.
.TP
.BI /n " nick"
change the nick name to
.IR nick .
.TP
.BI /q " [reason]"
quit ii,
giving the optional
.I reason
message.
.TP
.BI /t " topic"
set the topic of a channel with
.IR topic.
.SH RAW COMMANDS
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/TLS PROTOCOL SUPPORT
For SSL/TLS protocol support you can connect to a local tunnel, for example
with stunnel or socat.
.SH SEE ALSO
.BR echo (1),
.BR tail (1),
.BR tail (1)

1163
ii.c

File diff suppressed because it is too large Load Diff

@ -1,29 +0,0 @@
#!/bin/sh
# ----------------------------------------------------
# Nico Golde <nico@ngolde.de>
# License: do whatever you want with this code
# Purpose: locate new queries for the ii irc client
# ----------------------------------------------------
IRCPATH=$HOME/irc
TMPFILE=$IRCPATH/queries.tmp
if [ ! -f $TMPFILE ]; then
touch $TMPFILE
fi
echo "searching new query data"
for i in `find $IRCPATH -newer $TMPFILE -name 'out'`
do
grep -v '\-!\-' $i > /dev/null 2>&1 # if file doesnt just contain server stuff
if [ $? -ne 1 ]; then
# strip server, nickserv and channel out files
echo $i | egrep -v -i "nickserv|#|$IRCPATH/(irc\.freenode\.net|irc\.oftc\.net)/out" > /dev/null 2>&1
if [ $? -ne 1 ]; then
printf "new data in: %s\n========================================================\n" "$i"
tail -5 $i
fi
fi
done
touch $TMPFILE

@ -0,0 +1,32 @@
/* Taken from OpenBSD */
#include <sys/types.h>
#include <string.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
Loading…
Cancel
Save