245 lines
6.2 KiB
C
245 lines
6.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#include <netinet/in.h>
|
|
#include <errno.h>
|
|
|
|
#include "libircclient/include/libircclient.h"
|
|
|
|
#include "configfile.h"
|
|
#include "list.h"
|
|
#include "logging.h"
|
|
|
|
#define DEFAULT_CONFIG "irclogbot.conf"
|
|
#define DEFAULT_LOGFILE "irclogbot.log"
|
|
|
|
static struct option opts[] = {
|
|
{"config", 1, 0, 'c'},
|
|
{"debug", 0, 0, 'd'},
|
|
{"help", 0, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
struct irc_client {
|
|
struct list_head list;
|
|
|
|
irc_session_t *session;
|
|
const char *server;
|
|
const char *nickname;
|
|
const char *channel;
|
|
const char *channelkey;
|
|
|
|
struct in_addr addr;
|
|
};
|
|
|
|
static LIST_HEAD(client_list);
|
|
static irc_callbacks_t irc_cbs;
|
|
|
|
static int add_client(const char *parameter, void *privdata)
|
|
{
|
|
struct irc_client *entry = malloc(sizeof(struct irc_client));
|
|
if (entry == NULL) {
|
|
log_print(LOG_ERROR, "add_client(): out of memory");
|
|
return -1;
|
|
}
|
|
|
|
if (inet_pton(AF_INET, parameter, &entry->addr) <= 0) {
|
|
log_print(LOG_ERROR, "add_client(): inet_pton()");
|
|
free(entry);
|
|
return -1;
|
|
}
|
|
|
|
const char *defserver = config_get_string("global", "server", NULL);
|
|
entry->server = config_get_string(parameter, "server", defserver);
|
|
if (entry->server == NULL) {
|
|
log_print(LOG_ERROR, "add_client(): client %s: no server given", parameter);
|
|
free(entry);
|
|
return -1;
|
|
}
|
|
|
|
const char *defchannel = config_get_string("global", "channel", NULL);
|
|
entry->channel = config_get_string(parameter, "channel", defchannel);
|
|
if (entry->channel == NULL) {
|
|
log_print(LOG_ERROR, "add_client(): client %s: no channel given", parameter);
|
|
free(entry);
|
|
return -1;
|
|
}
|
|
|
|
const char *defchannelkey = config_get_string("global", "channelkey", NULL);
|
|
entry->channelkey = config_get_string(parameter, "channelkey", defchannelkey);
|
|
|
|
entry->nickname = config_get_string(parameter, "nickname", NULL);
|
|
if (entry->nickname == NULL) {
|
|
log_print(LOG_ERROR, "add_client(): client %s: no nickname given", parameter);
|
|
free(entry);
|
|
return -1;
|
|
}
|
|
|
|
entry->session = irc_create_session(&irc_cbs);
|
|
if (entry->session == NULL) {
|
|
log_print(LOG_ERROR, "add_client(): irc_create_session()");
|
|
free(entry);
|
|
return -1;
|
|
}
|
|
|
|
irc_set_ctx(entry->session, entry);
|
|
irc_option_set(entry->session, LIBIRC_OPTION_STRIPNICKS);
|
|
|
|
int ret = irc_connect(entry->session, entry->server, 6667, NULL, entry->nickname, NULL, NULL);
|
|
if (ret != 0) {
|
|
log_print(LOG_ERROR, "add_client(): irc_connect(): %s", irc_strerror(irc_errno(entry->session)));
|
|
irc_destroy_session(entry->session);
|
|
free(entry);
|
|
return -1;
|
|
}
|
|
|
|
/* HACK: irc_connect() sets errno */
|
|
errno = 0;
|
|
|
|
log_print(LOG_DEBUG, "added client %s (server: %s chan: %s nickname: %s)",
|
|
parameter, entry->server, entry->channel, entry->nickname);
|
|
|
|
list_add(&entry->list, &client_list);
|
|
return 0;
|
|
}
|
|
|
|
static void event_connect(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
|
|
{
|
|
struct irc_client *entry = (struct irc_client *) irc_get_ctx(session);
|
|
irc_cmd_join(session, entry->channel, entry->channelkey);
|
|
}
|
|
|
|
static void event_join(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
|
|
{
|
|
struct irc_client *entry = (struct irc_client *) irc_get_ctx(session);
|
|
irc_cmd_user_mode(session, "+i");
|
|
|
|
char buf[32] = { "forwarding from " };
|
|
inet_ntop(AF_INET, &entry->addr, buf +16, 16);
|
|
|
|
irc_cmd_msg(session, params[0], buf);
|
|
}
|
|
|
|
static void event_numeric(irc_session_t *session, unsigned int event, const char *origin, const char **params, unsigned int count)
|
|
{
|
|
if (event < 400)
|
|
return;
|
|
|
|
log_print(LOG_INFO, "EVENT %d: %s: %s %s %s %s",
|
|
event, (origin ? origin : "unknown"), params[0],
|
|
count > 1 ? params[1] : "",
|
|
count > 2 ? params[2] : "",
|
|
count > 3 ? params[3] : "");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char *config = DEFAULT_CONFIG;
|
|
int code, arg = 0, debug = 0;
|
|
|
|
do {
|
|
code = getopt_long(argc, argv, "c:dh", opts, &arg);
|
|
|
|
switch (code) {
|
|
case 'c': /* config */
|
|
config = optarg;
|
|
break;
|
|
|
|
case 'd': /* debug */
|
|
debug = 1;
|
|
break;
|
|
|
|
case 'h': /* help */
|
|
printf("Usage: ctstat [options]\n"
|
|
"Options: \n"
|
|
" --config -c configfile use this configfile\n"
|
|
" --debug -d do not fork and log to stderr\n"
|
|
" --help -h this help\n"
|
|
"\n");
|
|
exit(0);
|
|
break;
|
|
|
|
case '?': /* error */
|
|
exit(-1);
|
|
break;
|
|
|
|
default: /* unknown / all options parsed */
|
|
break;
|
|
}
|
|
} while (code != -1);
|
|
|
|
/* parse config file */
|
|
if (config_parse(config))
|
|
exit(1);
|
|
|
|
int sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
if (sock < 0) {
|
|
log_print(LOG_ERROR, "socket()");
|
|
return -1;
|
|
}
|
|
|
|
struct sockaddr_in addr = {
|
|
.sin_family = AF_INET,
|
|
.sin_port = htons(514),
|
|
.sin_addr.s_addr = INADDR_ANY,
|
|
};
|
|
|
|
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
log_print(LOG_ERROR, "bind()");
|
|
return -1;
|
|
}
|
|
|
|
irc_cbs.event_connect = event_connect;
|
|
irc_cbs.event_join = event_join;
|
|
irc_cbs.event_numeric = event_numeric;
|
|
|
|
int cnt = config_get_strings("global", "client", add_client, NULL);
|
|
if (cnt == 0) {
|
|
log_print(LOG_ERROR, "no clients defined");
|
|
close(sock);
|
|
exit(1);
|
|
}
|
|
|
|
char buf[1500];
|
|
while (1) {
|
|
fd_set rd_fds, wr_fds;
|
|
FD_ZERO(&rd_fds);
|
|
FD_ZERO(&wr_fds);
|
|
|
|
FD_SET(sock, &rd_fds);
|
|
|
|
int maxfd = sock;
|
|
struct irc_client *entry;
|
|
list_for_each_entry(entry, &client_list, list) {
|
|
int ret = irc_add_select_descriptors(entry->session, &rd_fds, &wr_fds, &maxfd);
|
|
if (ret != 0)
|
|
log_print(LOG_WARN, "irc_add_select_descriptors(): %s", irc_strerror(irc_errno(entry->session)));
|
|
}
|
|
|
|
select(maxfd +1, &rd_fds, &wr_fds, NULL, NULL);
|
|
|
|
int len = 0;
|
|
if (FD_ISSET(sock, &rd_fds)) {
|
|
unsigned int i = sizeof(addr);
|
|
len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &i);
|
|
}
|
|
|
|
list_for_each_entry(entry, &client_list, list) {
|
|
if (len > 0 && (entry->addr.s_addr == addr.sin_addr.s_addr))
|
|
irc_cmd_msg(entry->session, entry->channel, buf);
|
|
|
|
int ret = irc_process_select_descriptors(entry->session, &rd_fds, &wr_fds);
|
|
if (ret != 0)
|
|
log_print(LOG_WARN, "irc_process_select_descriptors(): %s", irc_strerror(irc_errno(entry->session)));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|