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