---
ii.c | 305 ++++++++++++++++++++++++++++++++++++++++++-----------------------
util.h | 2 +
2 files changed, 200 insertions(+), 107 deletions(-)
diff --git a/ii.c b/ii.c
index 52dae28..a7b9495 100644
--- a/ii.c
+++ b/ii.c
_AT_@ -1,25 +1,25 @@
/* See LICENSE file for license details. */
+#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
#include <netdb.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/stat.h>
#include <netinet/in.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
-#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <time.h>
#include <unistd.h>
-
#include "util.h"
-#define IRC_CHANNEL_MAX 50
+#define IRC_CHANNEL_MAX 200
#define IRC_MSG_MAX 512
#define PING_TIMEOUT 300
_AT_@ -27,29 +27,70 @@ enum { TOK_NICKSRV = 0, TOK_USER, TOK_CMD, TOK_CHAN, TOK_ARG, TOK_TEXT, TOK_LAST
typedef struct Channel Channel;
struct Channel {
- int fd;
+ int fdin;
char name[IRC_CHANNEL_MAX]; /* channel name (normalized) */
char inpath[PATH_MAX]; /* input path */
char outpath[PATH_MAX]; /* output path */
Channel *next;
};
-static time_t last_response = 0;
+static void create_dirtree(const char *);
+static void create_filepath(char *, size_t, const char *, const char *, const char *);
+static Channel * channel_add(const char *);
+static void channel_free(Channel *);
+static Channel * channel_find(const char *);
+static Channel * channel_join(const char *);
+static void channel_leave(Channel *);
+static Channel * channel_new(const char *);
+static void channel_normalize_name(char *);
+static void channel_normalize_path(char *);
+static int channel_open(Channel *);
+static void channel_print(Channel *, const char *);
+static int channel_reopen(Channel *);
+static void channel_rm(Channel *);
+static void * ecalloc(size_t, size_t);
+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_privmsg(int, Channel *, char *);
+static void proc_channels_input(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 int tcpopen(const char *, const char *);
+static size_t tokenize(char **, size_t, char *, int);
+static void usage(void);
+
+static time_t last_response = 0;
static Channel *channels = NULL;
static Channel *channelmaster = NULL;
-static char nick[32]; /* might change while running */
-static char ircpath[PATH_MAX]; /* irc dir (-i) */
-static char msg[IRC_MSG_MAX]; /* message buf used for communication */
+static char nick[32]; /* might change while running */
+static char ircpath[PATH_MAX]; /* irc dir (-i) */
+static char msg[IRC_MSG_MAX]; /* message buf used for communication */
static void
-usage(void) {
+usage(void)
+{
eprintf("ii-" VERSION ", (c) 2005-2014 ii engineers, see LICENSE for details\n"
"usage: %s <-s host> [-i <irc dir>] [-p <port>] "
"[-n <nick>] [-k <password>] [-f <fullname>]\n", argv0);
}
+static void *
+ecalloc(size_t nmemb, size_t size)
+{
+ void *p;
+ if(!(p = calloc(nmemb, size)))
+ eprintf("ii: cannot allocate memory:");
+ return p;
+}
+
static void
-writestr(int fd, const char *s) {
+ewritestr(int fd, const char *s)
+{
size_t len, off = 0;
int w = -1;
_AT_@ -65,9 +106,10 @@ writestr(int fd, const char *s) {
/* creates directories bottom-up, if necessary */
static void
-create_dirtree(const char *dir) {
+create_dirtree(const char *dir)
+{
char tmp[PATH_MAX], *p = NULL;
- struct stat st = { 0 };
+ struct stat st;
size_t len;
strlcpy(tmp, dir, sizeof(tmp));
_AT_@ -89,23 +131,25 @@ create_dirtree(const char *dir) {
}
static void
-channel_normalize_path(char *s) {
+channel_normalize_path(char *s)
+{
for(; *s; s++) {
if(isalpha(*s))
*s = tolower(*s);
- else if(!(isdigit(*s) || *s == '.' || *s == '#' || *s == '&'))
+ else if(!isdigit(*s) && !strchr(".#&", *s))
*s = '_';
}
}
static void
-channel_normalize_name(char *s) {
+channel_normalize_name(char *s)
+{
char *p;
if(*s == '&' || *s == '#')
s++;
for(p = s; *s; s++) {
- if(*s != ' ' && *s != ',' && *s != '&' && *s != '#' && *s != 7) {
+ if(!strchr(" ,&#\x07", *s)) {
*p = *s;
p++;
}
_AT_@ -135,35 +179,51 @@ create_filepath(char *filepath, size_t len, const char *path,
}
}
+static void
+channel_free(Channel *c)
+{
+ free(c);
+}
+
static int
-channel_open(Channel *c) {
+channel_open(Channel *c)
+{
int fd;
+ /* in */
if(access(c->inpath, F_OK) == -1)
mkfifo(c->inpath, S_IRWXU);
+ c->fdin = -1;
fd = open(c->inpath, O_RDONLY | O_NONBLOCK, 0);
- c->fd = fd;
- return fd != -1;
+ if(fd == -1)
+ goto err;
+ c->fdin = fd;
+
+ return 0;
+err:
+ if(c->fdin > 2)
+ close(c->fdin);
+ return -1;
}
static int
-channel_reopen(Channel *c) {
- close(c->fd);
+channel_reopen(Channel *c)
+{
+ close(c->fdin);
return channel_open(c);
}
static Channel *
-channel_new(int fd, const char *name) {
+channel_new(const char *name)
+{
Channel *c;
char channelpath[PATH_MAX];
strlcpy(channelpath, name, sizeof(channelpath));
channel_normalize_path(channelpath);
- if(!(c = calloc(1, sizeof(Channel))))
- eprintf("ii: cannot allocate memory:");
+ c = ecalloc(1, sizeof(Channel));
c->next = NULL;
- c->fd = fd;
strlcpy(c->name, name, sizeof(c->name));
channel_normalize_name(c->name);
_AT_@ -175,7 +235,8 @@ channel_new(int fd, const char *name) {
}
static Channel *
-channel_find(const char *name) {
+channel_find(const char *name)
+{
Channel *c;
char chan[IRC_CHANNEL_MAX];
_AT_@ -189,13 +250,14 @@ channel_find(const char *name) {
}
static Channel *
-channel_add(const char *name) {
+channel_add(const char *name)
+{
Channel *c;
- c = channel_new(-1, name);
- if(!channel_open(c)) {
- weprintf("ii: cannot create in channel: %s:", name);
- free(c);
+ c = channel_new(name);
+ if(channel_open(c) == -1) {
+ weprintf("ii: cannot create channel: %s:", name);
+ channel_free(c);
return NULL;
}
if(!channels) {
_AT_@ -208,7 +270,8 @@ channel_add(const char *name) {
}
static Channel *
-channel_join(const char *name) {
+channel_join(const char *name)
+{
Channel *c;
if(!(c = channel_find(name)))
_AT_@ -217,7 +280,8 @@ channel_join(const char *name) {
}
static void
-channel_rm(Channel *c) {
+channel_rm(Channel *c)
+{
Channel *p;
if(channels == c) {
_AT_@ -227,32 +291,36 @@ channel_rm(Channel *c) {
if(p->next == c)
p->next = c->next;
}
- free(c);
+ channel_free(c);
}
static void
-channel_leave(Channel *c) {
- close(c->fd);
+channel_leave(Channel *c)
+{
+ close(c->fdin);
/* remove "in" file on leaving the channel */
unlink(c->inpath);
channel_rm(c);
}
static void
-loginkey(int ircfd, const char *key) {
+loginkey(int ircfd, const char *key)
+{
snprintf(msg, sizeof(msg), "PASS %s\r\n", key);
- writestr(ircfd, msg);
+ ewritestr(ircfd, msg);
}
static void
-loginuser(int ircfd, const char *host, const char *fullname) {
+loginuser(int 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);
- writestr(ircfd, msg);
+ ewritestr(ircfd, msg);
}
static int
-tcpopen(const char *host, const char *service) {
+tcpopen(const char *host, const char *service)
+{
struct addrinfo hints, *res = NULL, *rp;
int fd, e;
_AT_@ -279,27 +347,25 @@ tcpopen(const char *host, const char *service) {
}
static int
-isnumeric(const char *s) {
- if(!s)
- return 0;
+isnumeric(const char *s)
+{
errno = 0;
strtol(s, NULL, 10);
return errno == 0;
}
static size_t
-tokenize(char **result, size_t reslen, char *str, int delim) {
+tokenize(char **result, size_t reslen, char *str, int delim)
+{
char *p = NULL, *n = NULL;
size_t i = 0;
- if(!str)
- return 0;
for(n = str; *n == ' '; n++);
p = n;
while(*n != '\0') {
if(i >= reslen)
return 0;
- if(i > TOK_CHAN - TOK_CMD && isnumeric(result[0]))
+ if(i > TOK_CHAN - TOK_CMD && result[0] && isnumeric(result[0]))
delim = ':'; /* workaround non-RFC compliant messages */
if(*n == delim) {
*n = '\0';
_AT_@ -316,7 +382,8 @@ tokenize(char **result, size_t reslen, char *str, int delim) {
}
static void
-channel_print(Channel *c, const char *buf) {
+channel_print(Channel *c, const char *buf)
+{
FILE *fp = NULL;
time_t t = time(NULL);
_AT_@ -327,15 +394,17 @@ channel_print(Channel *c, const char *buf) {
}
static void
-proc_channels_privmsg(int ircfd, Channel *c, char *buf) {
+proc_channels_privmsg(int ircfd, 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);
- writestr(ircfd, msg);
+ ewritestr(ircfd, msg);
}
static void
-proc_channels_input(int ircfd, Channel *c, char *buf) {
+proc_channels_input(int ircfd, Channel *c, char *buf)
+{
char *p = NULL;
size_t buflen;
_AT_@ -393,7 +462,7 @@ proc_channels_input(int ircfd, Channel *c, char *buf) {
else
snprintf(msg, sizeof(msg),
"PART %s :leaving\r\n", c->name);
- writestr(ircfd, msg);
+ ewritestr(ircfd, msg);
channel_leave(c);
return;
break;
_AT_@ -402,8 +471,8 @@ proc_channels_input(int ircfd, Channel *c, char *buf) {
snprintf(msg, sizeof(msg), "QUIT %s\r\n", &buf[3]);
else
snprintf(msg, sizeof(msg),
- "QUIT %s\r\n", "leaving");
- writestr(ircfd, msg);
+ "QUIT %s\r\n", "bye");
+ ewritestr(ircfd, msg);
return;
break;
default: /* raw IRC command */
_AT_@ -415,11 +484,12 @@ proc_channels_input(int ircfd, Channel *c, char *buf) {
snprintf(msg, sizeof(msg), "%s\r\n", &buf[1]);
}
if(msg[0] != '\0')
- writestr(ircfd, msg);
+ ewritestr(ircfd, msg);
}
static void
-proc_server_cmd(int fd, char *buf) {
+proc_server_cmd(int fd, char *buf)
+{
Channel *c;
const char *channel;
char *argv[TOK_LAST], *cmd = NULL, *p = NULL;
_AT_@ -432,6 +502,12 @@ proc_server_cmd(int fd, char *buf) {
for(i = 0; i < TOK_LAST; i++)
argv[i] = NULL;
+#if 1
+ /* DEBUG */
+ printf("server cmd str: |%s|\n", buf);
+ fflush(stdout);
+#endif
+
/* check prefix */
if(buf[0] == ':') {
if (!(p = strchr(buf, ' ')))
_AT_@ -461,11 +537,22 @@ proc_server_cmd(int fd, char *buf) {
tokenize(&argv[TOK_CMD], TOK_LAST - TOK_CMD, cmd, ' ');
+#if 1
+ /* DEBUG */
+ printf("server cmd: TOK_NICKSRV |%s|\n", argv[TOK_NICKSRV]);
+ printf("server cmd: TOK_USER |%s|\n", argv[TOK_USER]);
+ printf("server cmd: TOK_CMD |%s|\n", argv[TOK_CMD]);
+ printf("server cmd: TOK_CHAN |%s|\n", argv[TOK_CHAN]);
+ printf("server cmd: TOK_ARG |%s|\n", argv[TOK_ARG]);
+ printf("server cmd: TOK_TEXT |%s|\n", argv[TOK_TEXT]);
+ fflush(stdout);
+#endif
+
if(!argv[TOK_CMD] || !strcmp("PONG", argv[TOK_CMD])) {
return;
} else if(!strcmp("PING", argv[TOK_CMD])) {
snprintf(msg, sizeof(msg), "PONG %s\r\n", argv[TOK_TEXT]);
- writestr(fd, msg);
+ ewritestr(fd, msg);
return;
} else if(!argv[TOK_NICKSRV] || !argv[TOK_USER]) {
/* server command */
_AT_@ -473,7 +560,7 @@ proc_server_cmd(int fd, char *buf) {
argv[TOK_ARG] ? argv[TOK_ARG] : "",
argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
channel_print(channelmaster, msg);
- return;
+ return; /* don't process further */
} else if(!strcmp("ERROR", argv[TOK_CMD]))
snprintf(msg, sizeof(msg), "-!- error %s",
argv[TOK_TEXT] ? argv[TOK_TEXT] : "unknown");
_AT_@ -530,7 +617,8 @@ proc_server_cmd(int fd, char *buf) {
}
static int
-read_line(int fd, char *buf, size_t bufsiz) {
+read_line(int fd, char *buf, size_t bufsiz)
+{
size_t i = 0;
char c = '\0';
_AT_@ -544,11 +632,12 @@ read_line(int fd, char *buf, size_t bufsiz) {
}
static void
-handle_channels_input(int ircfd, Channel *c) {
+handle_channels_input(int ircfd, Channel *c)
+{
char buf[BUFSIZ];
- if(read_line(c->fd, buf, sizeof(buf)) == -1) {
- if(!channel_reopen(c))
+ if(read_line(c->fdin, buf, sizeof(buf)) == -1) {
+ if(channel_reopen(c) == -1)
channel_rm(c);
return;
}
_AT_@ -556,7 +645,8 @@ handle_channels_input(int ircfd, Channel *c) {
}
static void
-handle_server_output(int ircfd) {
+handle_server_output(int ircfd)
+{
char buf[BUFSIZ];
if(read_line(ircfd, buf, sizeof(buf)) == -1)
_AT_@ -567,26 +657,26 @@ handle_server_output(int ircfd) {
}
static void
-run(int ircfd, const char *host) {
+run(int ircfd, const char *host)
+{
Channel *c;
- fd_set rd;
+ fd_set rdset, wrset;
struct timeval tv;
char ping_msg[IRC_MSG_MAX];
int r, maxfd;
snprintf(ping_msg, sizeof(ping_msg), "PING %s\r\n", host);
for(;;) {
- FD_ZERO(&rd);
maxfd = ircfd;
- FD_SET(ircfd, &rd);
+ FD_ZERO(&rdset);
+ FD_SET(ircfd, &rdset);
for(c = channels; c; c = c->next) {
- if(maxfd < c->fd)
- maxfd = c->fd;
- FD_SET(c->fd, &rd);
+ maxfd = MAX(c->fdin, maxfd);
+ FD_SET(c->fdin, &rdset);
}
tv.tv_sec = 120;
tv.tv_usec = 0;
- r = select(maxfd + 1, &rd, 0, 0, &tv);
+ r = select(maxfd + 1, &rdset, &wrset, 0, &tv);
if(r < 0) {
if(errno == EINTR)
continue;
_AT_@ -596,22 +686,23 @@ run(int ircfd, const char *host) {
channel_print(channelmaster, "-!- ii shutting down: ping timeout");
exit(EXIT_FAILURE);
}
- writestr(ircfd, ping_msg);
+ ewritestr(ircfd, ping_msg);
continue;
}
- if(FD_ISSET(ircfd, &rd)) {
+ if(FD_ISSET(ircfd, &rdset)) {
handle_server_output(ircfd);
last_response = time(NULL);
}
for(c = channels; c; c = c->next) {
- if(FD_ISSET(c->fd, &rd))
+ if(FD_ISSET(c->fdin, &rdset))
handle_channels_input(ircfd, c);
}
}
}
int
-main(int argc, char *argv[]) {
+main(int argc, char *argv[])
+{
struct passwd *spw;
const char *key = NULL, *fullname = NULL, *host = "", *service = "6667";
char prefix[PATH_MAX];
_AT_@ -624,28 +715,28 @@ main(int argc, char *argv[]) {
snprintf(prefix, sizeof(prefix), "%s/irc", spw->pw_dir);
ARGBEGIN {
- case 'i':
- strlcpy(prefix, EARGF(usage()), sizeof(prefix));
- break;
- case 's':
- host = EARGF(usage());
- break;
- case 'p':
- service = EARGF(usage());
- estrtol(service, 10);
- break;
- case 'n':
- strlcpy(nick, EARGF(usage()), sizeof(nick));
- break;
- case 'k':
- key = getenv(EARGF(usage()));
- break;
- case 'f':
- fullname = EARGF(usage());
- break;
- default:
- usage();
- break;
+ case 'i':
+ strlcpy(prefix, EARGF(usage()), sizeof(prefix));
+ break;
+ case 's':
+ host = EARGF(usage());
+ break;
+ case 'p':
+ service = EARGF(usage());
+ estrtol(service, 10);
+ break;
+ case 'n':
+ strlcpy(nick, EARGF(usage()), sizeof(nick));
+ break;
+ case 'k':
+ key = getenv(EARGF(usage()));
+ break;
+ case 'f':
+ fullname = EARGF(usage());
+ break;
+ default:
+ usage();
+ break;
} ARGEND;
if(!*host || !*nick)
diff --git a/util.h b/util.h
index df6a3d8..e41d8d8 100644
--- a/util.h
+++ b/util.h
_AT_@ -3,6 +3,8 @@
#include <sys/stat.h>
#include "arg.h"
+#define MAX(A, B) ((A) > (B) ? (A) : (B))
+
extern char *argv0;
void eprintf(const char *, ...);
--
2.4.10
--Multipart=_Mon__9_May_2016_17_21_10_+0200_I.6cpFVydhq75aaE
Content-Type: text/x-diff;
name="0052-cleanup-master-channel-on-quit-or-exit.patch"
Content-Disposition: attachment;
filename="0052-cleanup-master-channel-on-quit-or-exit.patch"
Content-Transfer-Encoding: 7bit
Received on Mon Sep 17 2001 - 00:00:00 CEST
This archive was generated by hypermail 2.3.0 : Mon May 09 2016 - 17:24:22 CEST