--- 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: 7bitReceived 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