first commit
This commit is contained in:
commit
f9cc013c8d
14
LICENSE
Normal file
14
LICENSE
Normal file
@ -0,0 +1,14 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
27
README
Normal file
27
README
Normal file
@ -0,0 +1,27 @@
|
||||
> irclibs
|
||||
git.macaw.me/8nl/irclibs
|
||||
|
||||
md5 irc.c c43a8faf4ad199a30a1148b847867022
|
||||
md5 irc.h bd6a06cb02d75da9896233db6ea20cd8
|
||||
|
||||
> gemini://any-key.press/tt/welcome.gmi
|
||||
Сделано в соответствии с духом Тривиальных Технологий
|
||||
|
||||
> Лицензия: WTFPL
|
||||
|
||||
|
||||
_.oo.
|
||||
_.u[[/;:,. .odMMMMMM'
|
||||
.o888UU[[[/;:-. .o@P^ MMM^
|
||||
oN88888UU[[[/;::-. dP^
|
||||
dNMMNN888UU[[[/;:--. .o@P^
|
||||
,MMMMMMN888UU[[/;::-. o@^
|
||||
NNMMMNN888UU[[[/~.o@P^
|
||||
888888888UU[[[/o@^-..
|
||||
oI8888UU[[[/o@P^:--..
|
||||
.@^ YUU[[[/o@^;::---..
|
||||
oMP ^/o@P^;:::---..
|
||||
.dMMM .o@^ ^;::---...
|
||||
dMMMMMMM@^` `^^^^
|
||||
YMMMUP^
|
||||
^^
|
263
main.c
Normal file
263
main.c
Normal file
@ -0,0 +1,263 @@
|
||||
#define VERSION "1.0"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <netdb.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define ENABLE_SSL
|
||||
#include "irc.h"
|
||||
|
||||
#define bool char
|
||||
typedef struct {
|
||||
/* config */
|
||||
int port;
|
||||
char *ip;
|
||||
char *nick;
|
||||
bool use_ssl;
|
||||
bool debug;
|
||||
|
||||
/* Irc socket */
|
||||
IRCC_client client;
|
||||
} CFG;
|
||||
static CFG cfg = {.nick = "gem2irc", .ip = "127.0.0.1", .port = 6667};
|
||||
|
||||
typedef struct {
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
} GEM_CFG;
|
||||
static GEM_CFG gem_cfg;
|
||||
|
||||
int irc_client(const CFG cfg, IRCC_client *client, char **channels, const int channels_size, char **error_msg) {
|
||||
if (IRCC_connect(client, cfg.ip, cfg.port) == IRCC_ERROR) {
|
||||
*error_msg = strerror(errno);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (cfg.use_ssl) {
|
||||
if (IRCC_initssl(client) == IRCC_ERROR) {
|
||||
*error_msg = ERR_error_string(ERR_get_error(), NULL);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int status = IRCC_register(client, cfg.nick);
|
||||
if (status == IRCC_ERROR || status == IRCC_DISCONNECTED) {
|
||||
*error_msg = "disconnected";
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < channels_size; i++) {
|
||||
char *key = "";
|
||||
const char *channel = channels[i];
|
||||
|
||||
char *p = strchr(channel, ':');
|
||||
if (p != NULL) {
|
||||
p[0] = '\0';
|
||||
key = p + 1;
|
||||
}
|
||||
|
||||
IRCC_join(client, channel, key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void run_gemini(IRCC_client *client) {
|
||||
char *uri = client->irc_msg + 4;
|
||||
if (strlen(uri) <= 1)
|
||||
return;
|
||||
|
||||
char *nick = strdup(client->irc_nick);
|
||||
if (nick == NULL)
|
||||
return;
|
||||
|
||||
int ret = 1;
|
||||
|
||||
/* Connect to the gemini server */
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
goto RG_CLOSE;
|
||||
|
||||
/* Get domainname from uri */
|
||||
char domain[1024];
|
||||
snprintf(domain, sizeof(domain), "%.*s", (int)strcspn(uri, ":/\0"), uri);
|
||||
|
||||
struct hostent *he;
|
||||
if ((he = gethostbyname(domain)) == 0)
|
||||
goto RG_CLOSE_SOCK;
|
||||
|
||||
/* Connect */
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(1965);
|
||||
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)he->h_addr));
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
goto RG_CLOSE_SOCK;
|
||||
|
||||
/* TLS */
|
||||
if ((gem_cfg.ssl = SSL_new(gem_cfg.ctx)) == 0)
|
||||
goto RG_CLOSE_SOCK;
|
||||
|
||||
if (!SSL_set_tlsext_host_name(gem_cfg.ssl, domain))
|
||||
goto RG_CLOSE_TLS;
|
||||
|
||||
if (!SSL_set_fd(gem_cfg.ssl, sock))
|
||||
goto RG_CLOSE_TLS;
|
||||
|
||||
if (SSL_connect(gem_cfg.ssl) < 1)
|
||||
goto RG_CLOSE_TLS;
|
||||
|
||||
/* Send response */
|
||||
ssize_t size = snprintf(domain, sizeof(domain), "gemini://%s\r\n", uri);
|
||||
if (SSL_write(gem_cfg.ssl, domain, size) < 1)
|
||||
goto RG_CLOSE_TLS;
|
||||
|
||||
bool exit_flag = 0;
|
||||
while (1) {
|
||||
char buf[128];
|
||||
char *p = buf;
|
||||
|
||||
/* Read line */
|
||||
while ((size = SSL_read(gem_cfg.ssl, p, 1)) > 0) {
|
||||
if (*p == '\n' || p == buf + sizeof(buf)) {
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
if (size <= 0) {
|
||||
if (exit_flag)
|
||||
break;
|
||||
|
||||
exit_flag = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
IRCC_send(client, nick, buf);
|
||||
exit_flag = 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
RG_CLOSE_TLS:
|
||||
SSL_free(gem_cfg.ssl);
|
||||
gem_cfg.ssl = NULL;
|
||||
|
||||
RG_CLOSE_SOCK:
|
||||
close(sock);
|
||||
|
||||
RG_CLOSE:
|
||||
free(nick);
|
||||
if (ret)
|
||||
IRCC_send(client, nick, "Internal error. Maybe invaild uri?");
|
||||
}
|
||||
|
||||
void sig_handler(int sig) {
|
||||
IRCC_close(&cfg.client);
|
||||
|
||||
/* Close ssl for all forked processes */
|
||||
if (gem_cfg.ssl) {
|
||||
SSL_shutdown(gem_cfg.ssl);
|
||||
SSL_free(gem_cfg.ssl);
|
||||
}
|
||||
|
||||
if (gem_cfg.ctx)
|
||||
SSL_CTX_free(gem_cfg.ctx);
|
||||
|
||||
if (sig == -1)
|
||||
exit(1);
|
||||
|
||||
fprintf(stderr, "gem2irc: received signal %d\n", sig);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGKILL, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "n:p:h:tVD")) != -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
cfg.nick = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
cfg.ip = optarg;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
cfg.port = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
cfg.use_ssl = 1;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
printf("License: WTFPL\nVersion: %s\n", VERSION);
|
||||
return 0;
|
||||
|
||||
case 'D':
|
||||
cfg.debug = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("gem2irc - simple bridge between irc and gemini\ngem2irc -[n:p:h:tVD] [e.p CHANNEL1:PASSWORD CHANNEL2...]\n\t-n NICK\tdefault: %s\n\t-h HOST\tdefault: %s\n\t-p PORT\tdefault: %d\n\t-t Use ssl\tdefault: %s\n\t-D Print raw messages\n\t-V Version\n", cfg.nick, cfg.ip, cfg.port, (cfg.use_ssl) ? "true" : "false");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
/* TLS FOR GEMINI */
|
||||
SSL_library_init();
|
||||
gem_cfg.ctx = SSL_CTX_new(TLS_client_method());
|
||||
if (!gem_cfg.ctx) {
|
||||
fprintf(stderr, "gem2irc: ssl: %s\n", ERR_error_string(ERR_get_error(), NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* IRC */
|
||||
char *error_msg = NULL;
|
||||
if (irc_client(cfg, &cfg.client, argv, argc, &error_msg)) {
|
||||
fprintf(stderr, "gem2irc: irc: %s\n", (error_msg) ? error_msg : "error");
|
||||
sig_handler(-1);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int status = IRCC_recv(&cfg.client);
|
||||
if (status == IRCC_DISCONNECTED) {
|
||||
fprintf(stderr, "gem2irc: irc: disconnected\n");
|
||||
sig_handler(-1);
|
||||
}
|
||||
|
||||
if (cfg.debug)
|
||||
printf("\033[32m%s\033[0m", cfg.client.irc_raw);
|
||||
|
||||
status = IRCC_parse(&cfg.client);
|
||||
if (status == IRCC_PRIVMSG && cfg.client.irc_nick != NULL)
|
||||
if (!strncmp(cfg.client.irc_msg, "!go ", 4))
|
||||
if (fork() == 0) {
|
||||
run_gemini(&cfg.client);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user