2020-07-17 13:47:25 +00:00
|
|
|
/*
|
|
|
|
* This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd)
|
|
|
|
* Copyright (c) 2019, 2020 Alex-David Denes
|
|
|
|
*
|
|
|
|
* uIRCd is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* uIRCd is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
|
2020-08-01 17:45:14 +00:00
|
|
|
sig_atomic_t volatile run = true;
|
2020-07-29 14:49:59 +00:00
|
|
|
int loglevel = LOG_FATAL;
|
2020-07-17 13:47:25 +00:00
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
2020-08-17 20:13:17 +00:00
|
|
|
char *quitmsg = "uIRC indev beta", c, *pos = NULL;
|
|
|
|
unsigned int totcon = 0, actcon = 0, delay = 10;
|
2020-08-01 17:45:14 +00:00
|
|
|
Connection cons[MAXCONN] = {0};
|
2020-08-17 20:13:17 +00:00
|
|
|
setvbuf(stderr, NULL, _IOLBF, 0); /* Threads may want to print incomplete messages to the log at the same that, avoid that. */
|
|
|
|
|
|
|
|
/* Arguments:
|
|
|
|
* -c Connection in format: nick [ '!' user ] [ '@' host ] [ '/' [ '+' ] port ] [ ',' channel [ ',' channel ... ] ]
|
|
|
|
* -l Starting directory for message tree
|
|
|
|
* -m Message sent on closing the bouncer gracefully
|
|
|
|
* -d Reconnection delay (seconds)
|
|
|
|
* -V Log level: 0 being FATAL and 5 being DEBUG
|
|
|
|
* -C Configuration file path
|
|
|
|
* -v Version and license information
|
|
|
|
* -h Help/Usage
|
|
|
|
*/
|
2020-08-19 13:01:30 +00:00
|
|
|
while ((c = getopt(argc, argv, /* "C:" */
|
|
|
|
"m:"
|
|
|
|
"c:"
|
|
|
|
"l:"
|
|
|
|
"j:"
|
|
|
|
"V:"
|
|
|
|
"v"
|
|
|
|
"h"))
|
|
|
|
!= -1) {
|
2020-07-17 13:47:25 +00:00
|
|
|
switch (c) {
|
|
|
|
case 'c': {
|
2020-07-21 20:13:37 +00:00
|
|
|
cons[totcon].data.chans = point_after(optarg, ',');
|
|
|
|
if ((cons[totcon].data.port = point_after(optarg, '/')) != NULL) {
|
|
|
|
if (*cons[totcon].data.port == '+') {
|
|
|
|
cons[totcon].data.ssl = true;
|
|
|
|
cons[totcon].data.port++;
|
2020-07-17 13:47:25 +00:00
|
|
|
}
|
|
|
|
} else
|
2020-07-21 20:13:37 +00:00
|
|
|
cons[totcon].data.port = "6667";
|
|
|
|
cons[totcon].data.addr = ((pos = point_after(optarg, '@')) == NULL) ? "localhost" : pos;
|
|
|
|
cons[totcon].names.real = ((pos = point_after(optarg, ':')) == NULL) ? "uIRC user" : pos;
|
|
|
|
cons[totcon].names.user = ((pos = point_after(optarg, '!')) == NULL) ? "uIRC-user" : pos;
|
2020-08-17 20:13:17 +00:00
|
|
|
cons[totcon++].names.nick = optarg;
|
2020-07-17 13:47:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-08-02 19:56:48 +00:00
|
|
|
case 'l': {
|
2020-08-17 20:13:17 +00:00
|
|
|
int tmpres;
|
2020-08-02 19:56:48 +00:00
|
|
|
if ((tmpres = chdir(optarg)) != 0) {
|
2020-08-17 20:13:17 +00:00
|
|
|
LOG(LOG_FATAL, "Couldn't change log directory to %s. " ERRNOFMT, optarg, strerror(errno), errno);
|
2020-08-02 19:56:48 +00:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-08-01 17:45:14 +00:00
|
|
|
case 'm': quitmsg = optarg; break;
|
|
|
|
case 'd': delay = atoi(optarg); break;
|
2020-07-17 13:47:25 +00:00
|
|
|
case 'C': break; // TODO: Reserved for config file path
|
2020-08-02 19:56:48 +00:00
|
|
|
case 'V': {
|
2020-07-29 14:49:59 +00:00
|
|
|
loglevel = atoi(optarg);
|
|
|
|
break;
|
2020-08-02 19:56:48 +00:00
|
|
|
}
|
|
|
|
case 'v': {
|
2020-07-17 13:47:25 +00:00
|
|
|
printf("uIRCd version %s\n", VERSION);
|
|
|
|
return EXIT_SUCCESS;
|
2020-08-02 19:56:48 +00:00
|
|
|
}
|
2020-08-19 13:01:30 +00:00
|
|
|
case 'h': print_help(); return EXIT_SUCCESS;
|
2020-07-17 13:47:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-21 20:13:37 +00:00
|
|
|
if (totcon < 1) {
|
2020-08-17 20:13:17 +00:00
|
|
|
LOG(LOG_FATAL, "No connection was provided.");
|
2020-07-17 13:47:25 +00:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2020-08-17 20:13:17 +00:00
|
|
|
|
2020-07-21 20:13:37 +00:00
|
|
|
signal(SIGINT, stop_loop);
|
|
|
|
signal(SIGTERM, stop_loop);
|
2020-08-17 20:13:17 +00:00
|
|
|
pid_t cpid;
|
|
|
|
|
|
|
|
for (actcon = 0; actcon < totcon && run;) {
|
|
|
|
cpid = fork();
|
|
|
|
if (cpid == -1) {
|
|
|
|
if (errno != EAGAIN) {
|
|
|
|
LOG(LOG_FATAL, "Failed to fork child. " ERRNOFMT, strerror(errno), errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (cpid == 0) {
|
2020-08-19 12:44:26 +00:00
|
|
|
return run_main(&cons[actcon], delay, 10, quitmsg);
|
|
|
|
} else {
|
|
|
|
LOG(LOG_VERBOSE, "Successfully forked for connection " ADDRFMT ".", cons[actcon].data.addr, cons[actcon].data.port);
|
|
|
|
actcon++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (; actcon > 0; actcon--) {
|
|
|
|
waitpid(-1, NULL, 0);
|
|
|
|
}
|
2020-08-17 20:13:17 +00:00
|
|
|
|
2020-08-19 12:44:26 +00:00
|
|
|
LOG(LOG_VERBOSE, "Exiting gracefully.");
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
2020-08-02 19:56:48 +00:00
|
|
|
|
2020-08-19 12:44:26 +00:00
|
|
|
int run_main(Connection* conn, unsigned int recon_inter, unsigned int ping_inter, char* quitmsg)
|
|
|
|
{
|
|
|
|
IRC_Message buffer;
|
|
|
|
char sendbuf[MAXLINE + 1], recvbuf[MAXLINE + 1], fifobuf[MAXLINE + 1], /* Buffers */
|
|
|
|
connstr[100], *path[4] = {connstr, NULL, 0}; /* Path buffers */
|
|
|
|
size_t sendbufpos = 0, recvbufpos = 0, fifobufpos = 0; /* Positions */
|
|
|
|
signed int connstate = CONN_PENDING, fds[2] = {-1, -1}; /* Connection state and file descriptors */
|
|
|
|
unsigned int lastping = 0, lastconnect = 0, ctime = 0, /* Timestamps */
|
|
|
|
pinginter = (ping_inter) ? ping_inter : 10, reconinter = (recon_inter) ? recon_inter : 10; /* Intervals */
|
2020-08-17 20:13:17 +00:00
|
|
|
|
2020-08-19 12:44:26 +00:00
|
|
|
get_connstr(connstr, sizeof(connstr), conn);
|
|
|
|
for (;;) {
|
|
|
|
/* Connection manager */
|
|
|
|
ctime = time(NULL);
|
|
|
|
if (!run || connstate == CONN_CLOSING) {
|
|
|
|
if (fds[0] != -1) {
|
|
|
|
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_QUIT(quitmsg), sizeof(sendbuf))) > 0) {
|
|
|
|
LOG(LOG_VERBOSE, "Sending a QUIT message to " ADDRFMT " containing \"%s\".", conn->data.addr, conn->data.port, quitmsg);
|
|
|
|
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1)
|
|
|
|
LOG(LOG_WARN, "Couldn't flush send buffer to " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(fds[0]);
|
|
|
|
close(fds[1]);
|
|
|
|
connstate = CONN_CLOSED;
|
|
|
|
LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", conn->data.addr, conn->data.port);
|
|
|
|
break;
|
|
|
|
} else if (connstate == CONN_CLOSED)
|
|
|
|
break;
|
|
|
|
else if (connstate == CONN_PENDING) {
|
|
|
|
if (ctime - lastconnect < recon_inter)
|
|
|
|
continue;
|
|
|
|
int tmp;
|
|
|
|
if ((tmp = init_conn(conn)) > 0) {
|
|
|
|
fds[0] = tmp;
|
|
|
|
memset(recvbuf, '\0', sizeof(recvbuf));
|
|
|
|
memset(sendbuf, '\0', sizeof(sendbuf));
|
|
|
|
|
|
|
|
int flags;
|
|
|
|
if ((flags = fcntl(fds[0], F_GETFL)) != -1) {
|
|
|
|
if (fcntl(fds[0], F_SETFL, flags | O_NONBLOCK) == -1)
|
|
|
|
LOG(LOG_WARN, "Couldn't set socket to be non-blocking. Messages may be delayed as a result. " ERRNOFMT, strerror(errno), errno);
|
|
|
|
} else
|
|
|
|
LOG(LOG_WARN, "Failed to get socket flags. Messages may be delayed as sockets will block. " ERRNOFMT, strerror(errno), errno);
|
|
|
|
|
|
|
|
/* Create server.port/global for FIFO and open it */
|
|
|
|
path[1] = category[CAT_GLOB];
|
|
|
|
path[2] = NULL;
|
|
|
|
if (mkdir_bottomup(path)) {
|
|
|
|
path[2] = "in";
|
|
|
|
path[3] = NULL;
|
|
|
|
char pbuf[PATH_MAX];
|
|
|
|
int tmp;
|
|
|
|
if (assemble_path(path, pbuf, sizeof(pbuf))) {
|
|
|
|
if ((mkfifo(pbuf, S_IRUSR | S_IWUSR | S_IWGRP)) != 0 && errno != EEXIST) {
|
|
|
|
LOG(LOG_WARN, "Couldn't create FIFO at \"%s\" for input. " ERRNOFMT, pbuf, strerror(errno), errno);
|
|
|
|
} else {
|
|
|
|
LOG(LOG_VERBOSE, "Created a FIFO pipe for input at %s.", pbuf);
|
|
|
|
ssize_t fd;
|
|
|
|
if ((fd = open(pbuf, O_RDONLY | O_NONBLOCK)) != -1)
|
|
|
|
fds[1] = fd;
|
|
|
|
else
|
|
|
|
LOG(LOG_WARN, "Couldn't open FIFO pipe \"%s\" for reading. " ERRNOFMT, pbuf, strerror(errno), errno);
|
2020-08-17 20:13:17 +00:00
|
|
|
}
|
|
|
|
} else
|
2020-08-19 12:44:26 +00:00
|
|
|
LOG(LOG_WARN, "Couldn't assemble path for FIFO.");
|
2020-08-17 20:13:17 +00:00
|
|
|
}
|
2020-08-02 19:56:48 +00:00
|
|
|
|
2020-08-19 12:44:26 +00:00
|
|
|
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_NICK(conn->names.nick), sizeof(sendbuf))) > 0) {
|
|
|
|
LOG(LOG_VERBOSE, "Sending a NICK registration to " ADDRFMT " containing \"%s\".", conn->data.addr, conn->data.port, conn->names.nick);
|
|
|
|
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
|
|
|
|
LOG(LOG_WARN, "Couldn't register nickname on " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_USER(conn->names.user, conn->names.real, 0), sizeof(sendbuf))) > 0) {
|
|
|
|
LOG(LOG_VERBOSE, "Sending a USER registration to " ADDRFMT " containing \"%s\".", conn->data.addr, conn->data.port, conn->names.real);
|
|
|
|
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
|
|
|
|
LOG(LOG_WARN, "Couldn't register user and real name on " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
|
|
|
|
continue;
|
|
|
|
}
|
2020-08-01 17:45:14 +00:00
|
|
|
}
|
2020-08-20 17:51:43 +00:00
|
|
|
connstate = CONN_REGISTERED;
|
2020-08-19 12:44:26 +00:00
|
|
|
lastconnect = ctime;
|
2020-08-20 17:51:43 +00:00
|
|
|
} else if (tmp == INIT_SOFTFAIL)
|
|
|
|
connstate = CONN_PENDING;
|
|
|
|
else if (tmp == INIT_HARDFAIL)
|
|
|
|
connstate = CONN_CLOSED;
|
2020-08-19 12:44:26 +00:00
|
|
|
} else if (connstate == CONN_ACTIVE) {
|
|
|
|
if (ctime - lastping >= ping_inter) {
|
|
|
|
char* mesg = "UIRC PONG";
|
|
|
|
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_PING(mesg, NULL), sizeof(sendbuf))) > 0) {
|
|
|
|
LOG(LOG_DEBUG, "Sending ping to " ADDRFMT " with message \"%s\"", conn->data.addr, conn->data.port, mesg);
|
|
|
|
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
|
|
|
|
LOG(LOG_WARN, "Couldn't ping " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
lastping = ctime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
struct timespec sleep = {0, 10000000L};
|
|
|
|
nanosleep(&sleep, NULL);
|
|
|
|
}
|
2020-08-17 20:13:17 +00:00
|
|
|
|
2020-08-19 12:44:26 +00:00
|
|
|
/* Buffer reader */
|
|
|
|
ssize_t brd;
|
|
|
|
if ((brd = read(fds[0], recvbuf + recvbufpos, sizeof(recvbuf) - recvbufpos - 1)) > 0) {
|
|
|
|
LOG(LOG_DEBUG, "Read %li bytes.", brd);
|
|
|
|
*(recvbuf + (recvbufpos += brd)) = '\0';
|
|
|
|
} else if (brd == 0) {
|
|
|
|
connstate = CONN_PENDING;
|
|
|
|
} else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
|
|
|
LOG(LOG_ERROR, "Failed to read inbound traffic. " ERRNOFMT, strerror(errno), errno);
|
|
|
|
connstate = CONN_PENDING;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* ppoi;
|
|
|
|
if ((ppoi = strchr(recvbuf, '\n')) != NULL) {
|
|
|
|
*ppoi = '\0';
|
|
|
|
if (ppoi > recvbuf && *(ppoi - 1) == '\r')
|
|
|
|
*(ppoi - 1) = '\0';
|
|
|
|
LOG(LOG_DEBUG, "Recieved line: %s", recvbuf);
|
|
|
|
memset((void*)&buffer, '\0', sizeof(IRC_Message));
|
|
|
|
if (Tok_mesg(recvbuf, &buffer) == 1) {
|
2020-08-20 17:51:43 +00:00
|
|
|
LOG(LOG_DEBUG, "Tokenized message successfully.");
|
2020-08-19 12:44:26 +00:00
|
|
|
int categ = get_category(&buffer);
|
|
|
|
path[1] = category[categ];
|
|
|
|
path[2] = NULL;
|
|
|
|
char bufname[MAXPATH + 1], logpath[PATH_MAX], *bprint = "out";
|
|
|
|
FILE* logfile;
|
|
|
|
if (mkdir_bottomup(path)) {
|
|
|
|
if (categ == CAT_CHAN)
|
|
|
|
bprint = buffer.args[0];
|
|
|
|
else if (categ == CAT_USER)
|
|
|
|
bprint = buffer.name.nick;
|
|
|
|
snprintf(bufname, sizeof(bufname), "%s.log", bprint);
|
|
|
|
cleanup_path_names(bufname);
|
|
|
|
path[2] = bufname;
|
|
|
|
path[3] = NULL;
|
|
|
|
if (assemble_path(path, logpath, sizeof(logpath))) {
|
|
|
|
char linebuf[513];
|
|
|
|
if (Assm_mesg(sendbuf, &buffer, sizeof(sendbuf)) > 0) {
|
|
|
|
LOG(LOG_DEBUG, "Assembled line: \"%s\" to write to %s.", sendbuf, bufname);
|
|
|
|
if ((logfile = fopen(logpath, "a")) != NULL) {
|
|
|
|
fprintf(logfile, "%s", sendbuf);
|
|
|
|
fclose(logfile);
|
|
|
|
} else
|
|
|
|
LOG(LOG_WARN, "Couldn't open file \"%s\" for appending.", logpath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (buffer.cmd) {
|
|
|
|
case (PING): {
|
|
|
|
LOG(LOG_VERBOSE, "Auto-replying to ping \"%s\".", buffer.args[0]);
|
|
|
|
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_PONG(buffer.args[0], NULL), sizeof(sendbuf))) > 0)
|
|
|
|
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
|
|
|
|
LOG(LOG_WARN, "Couldn't pong " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
|
|
|
|
continue;
|
2020-08-17 20:13:17 +00:00
|
|
|
}
|
2020-08-19 12:44:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Autojoin channels from current connection on first response from the server */
|
|
|
|
case (RPL_WELCOME): {
|
2020-08-20 17:51:43 +00:00
|
|
|
LOG(LOG_INFO, "Connection established to " ADDRFMT ".", conn->data.addr, conn->data.port);
|
|
|
|
connstate = CONN_ACTIVE;
|
2020-08-19 12:44:26 +00:00
|
|
|
LOG(LOG_INFO, "Auto-joining channels \"%s\" on " ADDRFMT ".", conn->data.chans, conn->data.addr, conn->data.port);
|
|
|
|
IRC_Message* mesg = Assm_cmd_JOIN(conn->data.chans, NULL);
|
|
|
|
if ((sendbufpos = Assm_mesg(sendbuf, mesg, sizeof(sendbuf))) > 0)
|
|
|
|
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
|
|
|
|
LOG(LOG_WARN, "Couldn't auto-join channels \"%s\" " ADDRFMT ". " ERRNOFMT, conn->data.chans, conn->data.addr, conn->data.port, strerror(errno), errno);
|
|
|
|
continue;
|
2020-08-17 20:13:17 +00:00
|
|
|
}
|
2020-08-19 12:44:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case (RPL_BOUNCE): {
|
|
|
|
break; // TODO: Make bounces work
|
|
|
|
}
|
2020-08-20 17:51:43 +00:00
|
|
|
case (ERROR): {
|
|
|
|
LOG(LOG_ERROR, "Received error on connection " ADDRFMT " with the message \"%s\".", conn->data.addr, conn->data.port, buffer.args[0]);
|
|
|
|
}
|
2020-08-19 12:44:26 +00:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
LOG(LOG_WARN, "Log directory couldn't be created. " ERRNOFMT, strerror(errno), errno);
|
|
|
|
} else
|
|
|
|
LOG(LOG_WARN, "Received invalid IRC message (see RFC2812).");
|
|
|
|
for (char* x = (ppoi + 1); *x; x++)
|
|
|
|
*(recvbuf + (x - (ppoi + 1))) = *x;
|
|
|
|
recvbufpos -= (ppoi + 1) - recvbuf;
|
|
|
|
*(recvbuf + recvbufpos) = '\0';
|
|
|
|
}
|
2020-08-17 20:13:17 +00:00
|
|
|
|
2020-08-19 12:44:26 +00:00
|
|
|
/* Buffer writer */
|
|
|
|
if ((brd = read(fds[1], fifobuf + fifobufpos, sizeof(fifobuf) - fifobufpos - 1)) > 0) {
|
|
|
|
LOG(LOG_DEBUG, "Read %li bytes from FIFO.", brd);
|
|
|
|
*(fifobuf + (fifobufpos += brd)) = '\0';
|
|
|
|
} else if (brd == -1 && errno != EAGAIN && errno != EINTR) {
|
|
|
|
LOG(LOG_ERROR, "Failed to read FIFO input for connection " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
|
|
|
|
continue;
|
|
|
|
}
|
2020-08-17 20:13:17 +00:00
|
|
|
|
2020-08-19 12:44:26 +00:00
|
|
|
if ((ppoi = strchr(fifobuf, '\n')) != NULL) {
|
|
|
|
*ppoi = '\0';
|
|
|
|
LOG(LOG_DEBUG, "Current FIFO for " ADDRFMT "is: %s", conn->data.addr, conn->data.port, fifobuf);
|
|
|
|
if (ppoi > fifobuf && *(ppoi - 1) == '\r')
|
|
|
|
*(ppoi - 1) = '\0';
|
|
|
|
LOG(LOG_DEBUG, "Recieved line: %s", fifobuf);
|
|
|
|
memset((void*)&buffer, '\0', sizeof(IRC_Message));
|
|
|
|
if (Tok_mesg(fifobuf, &buffer) == 1) {
|
|
|
|
LOG(LOG_DEBUG, "Tokenized FIFO message successfully.", NULL);
|
|
|
|
if ((fifobufpos = Assm_mesg(fifobuf, &buffer, sizeof(fifobuf))) > 0) {
|
|
|
|
if (flush_buffer(fifobuf, fifobufpos, fds[0]) == -1) {
|
|
|
|
LOG(LOG_WARN, "Couldn't send FIFO input to " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
|
|
|
|
continue;
|
|
|
|
}
|
2020-07-17 13:47:25 +00:00
|
|
|
}
|
2020-08-19 12:44:26 +00:00
|
|
|
} else
|
|
|
|
LOG(LOG_WARN, "Received invalid IRC message (see RFC2812).");
|
|
|
|
for (char* x = (ppoi + 1); *x; x++)
|
|
|
|
*(fifobuf + (x - (ppoi + 1))) = *x;
|
|
|
|
fifobufpos -= (ppoi + 1) - fifobuf;
|
|
|
|
*(fifobuf + fifobufpos) = '\0';
|
2020-07-17 13:47:25 +00:00
|
|
|
}
|
2020-08-17 20:13:17 +00:00
|
|
|
}
|
2020-08-19 12:44:26 +00:00
|
|
|
LOG(LOG_VERBOSE, "Exiting thread with connection " ADDRFMT " gracefully.", conn->data.addr, conn->data.port);
|
2020-07-17 13:47:25 +00:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
2020-08-19 13:01:30 +00:00
|
|
|
void print_help(void)
|
|
|
|
{
|
|
|
|
struct help {
|
|
|
|
char arg;
|
|
|
|
char* desc;
|
|
|
|
char* def;
|
|
|
|
} arg_list[] = {{'c', "Define connection in format \"nick!user:real name@host/+port,#channel1,#channel2\""},
|
|
|
|
{'l', "Directory for logs", "current dir"},
|
|
|
|
{'m', "Quit message", "uIRC indev beta"},
|
|
|
|
{'d', "Reconnection delay", "10 seconds"},
|
|
|
|
{'V', "Log level (0-5)", "0 [LOG_FATAL]"},
|
|
|
|
/* {'C', "Configuration path", "~/.config/uircd/main.conf"}, */
|
|
|
|
{'v', "Print version information", NULL},
|
|
|
|
{'h', "Print this help message", NULL}};
|
|
|
|
printf("usage: uirc -c [connection] [options...]\n");
|
|
|
|
for (int i = 0; i < sizeof(arg_list) / sizeof(*arg_list); i++) {
|
|
|
|
printf("\t-%c\t%s", arg_list[i].arg, arg_list[i].desc);
|
|
|
|
if (arg_list[i].def != NULL)
|
|
|
|
printf(" (default: %s)", arg_list[i].def);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
}
|