summaryrefslogtreecommitdiffstats
path: root/ircxmpp.c
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2022-04-30 02:10:29 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2022-04-30 02:10:29 +0200
commit743086cf4e69c77e139c23defaf63bfa403c1678 (patch)
tree752cb5c0427ea9ea306ee200f0b1148a8fa33ab2 /ircxmpp.c
parentoh, looh, security issues already (diff)
downloadircxmpp-743086cf4e69c77e139c23defaf63bfa403c1678.tar
ircxmpp-743086cf4e69c77e139c23defaf63bfa403c1678.tar.gz
ircxmpp-743086cf4e69c77e139c23defaf63bfa403c1678.tar.bz2
ircxmpp-743086cf4e69c77e139c23defaf63bfa403c1678.tar.lz
ircxmpp-743086cf4e69c77e139c23defaf63bfa403c1678.tar.xz
ircxmpp-743086cf4e69c77e139c23defaf63bfa403c1678.tar.zst
ircxmpp-743086cf4e69c77e139c23defaf63bfa403c1678.zip
Diffstat (limited to '')
-rw-r--r--ircxmpp.c (renamed from main.c)415
-rw-r--r--ircxmpp.conf10
2 files changed, 261 insertions, 164 deletions
diff --git a/main.c b/ircxmpp.c
index 4359e78..5d4b8d9 100644
--- a/main.c
+++ b/ircxmpp.c
@@ -1,14 +1,26 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <strophe.h>
#include <ctype.h>
#include <time.h>
#include <sys/select.h>
#include <errno.h>
#include <signal.h>
+#include <stdarg.h>
+#include <search.h>
#include "ircxmpp.h"
-void free_bridge (struct bridge ** bridge, const char * razlog) {
+#ifdef IX_LIB
+#define BUG(...) bug(__FILE__, __func__, __LINE__, __VA_ARGS__)
+__attribute__((noreturn)) static void bug (const char * file, const char * function, int line, const char * format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "BUG DETECTED in %s()@%s:%d REPORT TO anton@šijanec.eu and attach core.\n"
+ "additional description: ", file, function, line);
+ vfprintf(stderr, format, ap);
+ abort();
+ va_end(ap); /* this is never called */
+}
+static void free_bridge (struct bridge ** bridge, const char * razlog) {
if (!bridge || !*bridge)
return;
fprintf(stderr, "freeing bridge with reason: %s\n", razlog);
@@ -18,7 +30,7 @@ void free_bridge (struct bridge ** bridge, const char * razlog) {
irc_destroy_session((*bridge)->irc);
}
if ((*bridge)->conn)
- xmpp_conn_release((*bridge)->conn); /* graceful disconnect, what is that? */
+ xmpp_conn_release((*bridge)->conn); // graceful disconnect, what is that?
free((*bridge)->identifier);
for (size_t i = 0; i < (*bridge)->messages_length; i++)
free((*bridge)->messages[i]);
@@ -28,26 +40,32 @@ void free_bridge (struct bridge ** bridge, const char * razlog) {
struct bridge * tofree = *bridge;
if ((*bridge)->prev)
(*bridge)->prev->next = (*bridge)->next;
- else
+ else {
+ if ((*bridge)->next)
+ (*bridge)->next->prev = (*bridge)->prev;
*bridge = (*bridge)->next;
+ }
free(tofree);
}
-void free_bridges (struct bridge ** bridges) {
- while (*bridges) // enkrat bo *bridges NULL, ker ne bo nobenega več notri
+static void free_bridges (struct bridge ** bridges) {
+ while (*bridges) { // enkrat bo *bridges NULL, ker ne bo nobenega več notri
+ if ((*bridges)->prev)
+ BUG("(*bridges)->prev is set");
free_bridge(bridges, "vsi mostovi se podirajo, ker se ircxmpp izklaplja");
+ }
}
-struct bridge ** find_bridge (struct bridge ** bridges, const char * identifier, enum side side) {
+static struct bridge ** find_bridge (struct bridge ** bridges, const char * id, enum side side) {
s:
if (!bridges || !*bridges)
return NULL;
- if ((*bridges)->side == side && !strcmp((*bridges)->identifier, identifier))
+ if ((*bridges)->side == side && !strcmp((*bridges)->identifier, id))
return bridges;
bridges = &((*bridges)->next);
goto s;
}
-void jid2ircnick (char * jid) { /* edits a jid into an irc-compatible nick. libera trims nicks. */
+static void jid2ircnick (char * jid) { /* edits a jid into an irc nick. libera trims nicks. */
char * c = strchr(jid, '/');
if (c) {
c++;
@@ -60,7 +78,7 @@ void jid2ircnick (char * jid) { /* edits a jid into an irc-compatible nick. libe
if (!(isalnum(*jid) || memchr(VALID_NICK, *jid, strlen(VALID_NICK))))
*jid = '_';
}
-void jid2ircuser (char * jid) {
+static void jid2ircuser (char * jid) {
char * c = strchr(jid, '/');
if (c) {
c++;
@@ -74,12 +92,12 @@ void jid2ircuser (char * jid) {
if (!(isalnum(*jid) || memchr(VALID_USER, *jid, strlen(VALID_USER))))
*jid = 'x';
}
-void bridge_forward (const char * from, const char * msg, struct ircxmpp * ircxmpp, enum side side) {
- struct bridge ** bridge_resp = find_bridge(&ircxmpp->bridges, from, !side);
- if (strstr(from, "ircxmpp_") || (ircxmpp->irchost && strstr(from, ircxmpp->irchost)))
+static void bridge_forward (const char * f, const char * m, struct ircxmpp * ircxmpp, enum side s) {
+ struct bridge ** bridge_resp = find_bridge(&ircxmpp->bridges, f, !s);
+ if (strstr(f, "ircxmpp_") || (ircxmpp->irchost && strstr(f, ircxmpp->irchost)))
return;
- fprintf(stderr, "sending text from %s to %s: %s\n", from, side == IRC ? "IRC" : "XMPP",
- msg ? msg : "[join only]");
+ fprintf(stderr, "sending text from %s to %s: %s\n", f, s == IRC ? "IRC" : "XMPP",
+ m ? m : "[join only]");
struct bridge * bridge;
if (!bridge_resp) {
bridge = calloc(1, sizeof(struct bridge));
@@ -87,10 +105,10 @@ void bridge_forward (const char * from, const char * msg, struct ircxmpp * ircxm
ircxmpp->bridges->prev = bridge;
bridge->next = ircxmpp->bridges;
ircxmpp->bridges = bridge;
- bridge->identifier = strdup(from);
+ bridge->identifier = strdup(f);
bridge->ircxmpp = ircxmpp;
- bridge->side = !side;
- if (side == IRC)
+ bridge->side = !s;
+ if (s == IRC)
init_irc(bridge);
else {
bridge->conn = xmpp_conn_new(bridge->ircxmpp->ctx);
@@ -100,22 +118,30 @@ void bridge_forward (const char * from, const char * msg, struct ircxmpp * ircxm
}
} else
bridge = *bridge_resp;
- if (side == IRC) {
+ if (s == IRC) {
irc_cmd_join(bridge->irc, ircxmpp->channel, ircxmpp->channel_password);
irc_run_once(bridge);
- if (msg)
- irc_cmd_msg(bridge->irc, ircxmpp->channel, msg);
+ if (m) {
+ char b[1024];
+ strncpy(b, m, 1023);
+ b[1023] = '\0';
+ char * c = b;
+ while (*++c != '\0')
+ if (!(isprint(*c) || * (unsigned char *) c > 0x7F /* UTF-8 */))
+ *c = ' '; /* to prevent newline message smuggling */
+ irc_cmd_msg(bridge->irc, ircxmpp->channel, m);
+ }
irc_run_once(bridge);
- } else if (msg) {
+ } else if (m) {
bridge->messages = realloc(bridge->messages,
sizeof(*bridge->messages) * (bridge->messages_length+1));
- bridge->messages[bridge->messages_length++] = strdup(msg);
+ bridge->messages[bridge->messages_length++] = strdup(m);
}
-} /* msg can be NULL, in that case we only join. */
-int message_handler (xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) {
- if (!conn) /* just to get rid of -Wunused-parameter */
+} /* m can be NULL, in that case we only join. */
+static int message_handler (xmpp_conn_t * const c, xmpp_stanza_t * const stanza, void * const ud) {
+ if (!c) /* just to get rid of -Wunused-parameter */
return 1;
- struct ircxmpp * ircxmpp = (struct ircxmpp *) userdata;
+ struct ircxmpp * ircxmpp = (struct ircxmpp *) ud;
xmpp_stanza_t * body;
const char * type;
char * intext;
@@ -135,9 +161,9 @@ int message_handler (xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, voi
xmpp_free(ircxmpp->ctx, intext);
return 1;
}
-int presence_handler (xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const ud) {
+static int presence_handler (xmpp_conn_t * const c, xmpp_stanza_t * const stanza, void * const ud) {
struct ircxmpp * ircxmpp = (struct ircxmpp *) ud;
- if (!conn || !xmpp_stanza_get_from(stanza) || !strchr(xmpp_stanza_get_from(stanza), '/'))
+ if (!c || !xmpp_stanza_get_from(stanza) || !strchr(xmpp_stanza_get_from(stanza), '/'))
return 1;
if (xmpp_stanza_get_type(stanza) && !strcmp("unavailable", xmpp_stanza_get_type(stanza))) {
fprintf(stderr, "sogovornik %s je zapustil MUC\n", xmpp_stanza_get_from(stanza));
@@ -151,8 +177,8 @@ int presence_handler (xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, vo
return 1;
}
-void conn_handler (xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int error,
- xmpp_stream_error_t * const stream_error, void * const userdata) {
+static void conn_handler (xmpp_conn_t * const conn, const xmpp_conn_event_t status,
+ const int error, xmpp_stream_error_t * const stream_error, void * const userdata) {
struct ircxmpp * ircxmpp = (struct ircxmpp *) userdata;
if (stream_error) /* just for -Wunused-parameter */
fprintf(stderr, "stream_error in conn_handler, error = %d\n", error);
@@ -181,8 +207,8 @@ void conn_handler (xmpp_conn_t * const conn, const xmpp_conn_event_t status, con
// xmpp_stop(ircxmpp->ctx);
}
}
-void conn_handler_bridge (xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int error,
- xmpp_stream_error_t * const stream_error, void * const userdata) {
+static void conn_handler_bridge (xmpp_conn_t * const conn, const xmpp_conn_event_t status,
+ const int error, xmpp_stream_error_t * const stream_error, void * const userdata) {
struct bridge * bridge = (struct bridge *) userdata;
if (stream_error) /* just for -Wunused-parameter */
fprintf(stderr, "stream_error in conn_handler, error = %d\n", error);
@@ -202,27 +228,6 @@ void conn_handler_bridge (xmpp_conn_t * const conn, const xmpp_conn_event_t stat
xmpp_stanza_release(x);
xmpp_send(bridge->conn, pres);
xmpp_stanza_release(pres);
- /* xmpp_stanza_t * pres;
- fprintf(stderr, "DEBUG: connected.\n");
- xmpp_handler_add(conn, message_handler, NULL, "message", NULL, bridge);
- xmpp_handler_add(conn, presence_handler, NULL, "presence", NULL, bridge);
- // Send initial <presence/> so that we appear online to contacts
- // pres = xmpp_presence_new(ctx); // somehow send can only be called once?
- // xmpp_send(conn, pres);
- // xmpp_stanza_release(pres);
- pres = xmpp_presence_new(bridge->ircxmpp->ctx); // joining a MUC
- char b[512];
- bridge->identifier();
- snprintf(b, 512, "%s/ircxmpp_%x", ircxmpp->muc, rand());
- xmpp_stanza_set_to(pres, b);
- xmpp_stanza_t * x = xmpp_stanza_new(ircxmpp->ctx);
- xmpp_stanza_set_name(x, "x");
- xmpp_stanza_set_ns(x, "http://jabber.org/protocol/muc");
- xmpp_stanza_add_child(pres, x);
- xmpp_stanza_release(x);
- xmpp_send(conn, pres);
- xmpp_stanza_release(pres);
- */
} else {
fprintf(stderr, "DEBUG: disconnected\n");
// xmpp_stop(ircxmpp->ctx);
@@ -231,7 +236,8 @@ void conn_handler_bridge (xmpp_conn_t * const conn, const xmpp_conn_event_t stat
}
/* IRC */
-void dump_event (irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
+static void dump_event (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
if (!s) /* just for -Wunused-parameter */
return;
fprintf(stderr, "Event %s, origin %s, params %d [", e, o ? o : "NULL", c);
@@ -242,40 +248,42 @@ void dump_event (irc_session_t * s, const char * e, const char * o, const char *
}
fprintf(stderr, "]\n");
}
-void event_connect (irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
+static void event_connect (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
dump_event(s, e, o, p, c);
struct bridge * bridge = (struct bridge *) irc_get_ctx(s);
irc_cmd_join(s, bridge->ircxmpp->channel, bridge->ircxmpp->channel_password);
}
-void event_connect_control (irc_session_t * s, const char * e, const char * o, const char ** p,
- unsigned c) {
+static void event_connect_control (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
dump_event(s, e, o, p, c);
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
irc_cmd_join(s, ircxmpp->channel, ircxmpp->channel_password);
}
-void event_privmsg (irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
+static void event_privmsg (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
dump_event(s, e, o, p, c); /* SAME FOR _control. do NOT use irc_get_ctx here!!! */
char nickbuf[512];
irc_target_get_nick(o, nickbuf, sizeof(nickbuf));
irc_cmd_msg(s, nickbuf, "ircxmpp (še) ne podpira zasebnih sporočil xmpp uporabnikom. ircxmpp se razvija na http://git.sijanec.eu/sijanec/ircxmpp/.");
}
-void event_partquit_control (irc_session_t * s, const char * e, const char * o, const char ** p,
- unsigned c) {
+static void event_partquit_control (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
dump_event(s, e, o, p, c);
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
struct bridge ** bridge = find_bridge(&ircxmpp->bridges, o /* indeed n!u@h */, IRC);
free_bridge(bridge, "part or quit from irc");
} /* part and quit events */
-void event_channel_control (irc_session_t * s, const char * e, const char * o, const char ** p,
- unsigned c) {
+static void event_channel_control (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
dump_event(s, e, o, p, c); /* o je avtor, p[0] je kanal p[1] je besedilo */
if (c != 2) /* no message text */
return;
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
bridge_forward(o /* indeed n!u@h */, p[1], ircxmpp, XMPP);
}
-void event_join_control (irc_session_t * s, const char * e, const char * o, const char ** p,
- unsigned c) {
+static void event_join_control (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
dump_event(s, e, o, p, c);
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
char buf[512];
@@ -298,8 +306,8 @@ void event_join_control (irc_session_t * s, const char * e, const char * o, cons
}
bridge_forward(o /* indeed n!u@h */, NULL, ircxmpp, XMPP);
}
-void event_nick_control (irc_session_t * s, const char * e, const char * o, const char ** p,
- unsigned c) {
+static void event_nick_control (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
dump_event(s, e, o, p, c); /* o je originalen nick, p[0] je nov nick */
if (!c)
return;
@@ -313,15 +321,16 @@ void event_nick_control (irc_session_t * s, const char * e, const char * o, cons
: "neznan uporabnik@neznan strežnik");
bridge_forward(buf, NULL, ircxmpp, XMPP); /* and now connect */
}
-void event_topic_control (irc_session_t * s, const char * e, const char * o, const char ** p,
- unsigned c) {
+static void event_topic_control (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
dump_event(s, e, o, p, c); /* o je avtor, p[0] je kanal, p[1] je nova tema/zadeva */
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
char buf[1024];
snprintf(buf, 1024, "/me je nastavil IRC temo na: %s", p[1]);
bridge_forward(o, buf, ircxmpp, XMPP);
} /* TODO */
-void event_numeric (irc_session_t * s, unsigned int e, const char * o, const char ** p, unsigned c) {
+static void event_numeric (
+ irc_session_t * s, unsigned int e, const char * o, const char ** p, unsigned c) {
char b[512];
struct bridge * bridge = (struct bridge *) irc_get_ctx(s);
sprintf(b, "%d", e);
@@ -342,8 +351,8 @@ void event_numeric (irc_session_t * s, unsigned int e, const char * o, const cha
break;
}
}
-void event_numeric_control (irc_session_t * s, unsigned int e, const char * o, const char ** p,
- unsigned c) {
+static void event_numeric_control (
+ irc_session_t * s, unsigned int e, const char * o, const char ** p, unsigned c) {
char b[512];
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
sprintf(b, "%d", e);
@@ -360,7 +369,7 @@ void event_numeric_control (irc_session_t * s, unsigned int e, const char * o, c
break;
}
}
-int irc_run_once (struct bridge * bridge) { /* returns nonzero if connection failed (dropped brid) */
+static int irc_run_once (struct bridge * bridge) { /* returns nonzero if connection failed */
if (!irc_is_connected(bridge->irc)) {
char b[512], u[512];
strncpy(b, bridge->identifier, sizeof(b)-1);
@@ -400,7 +409,9 @@ int irc_run_once (struct bridge * bridge) { /* returns nonzero if connection fai
}
return 0;
}
-int irc_run_once_control (struct ircxmpp * ircxmpp) { /* returns nonzero if failed (dropped conne) */
+static int irc_run_once_control (struct ircxmpp * ircxmpp) { /* returns nonzero if failed */
+ if (!ircxmpp->irc)
+ return 1;
if (!irc_is_connected(ircxmpp->irc)) {
char b[512];
sprintf(b, "ircxmpp_%X", rand());
@@ -408,11 +419,12 @@ int irc_run_once_control (struct ircxmpp * ircxmpp) { /* returns nonzero if fail
free(ircxmpp->ircnick);
ircxmpp->ircnick = strdup(b);
if (irc_connect(ircxmpp->irc, ircxmpp->hostname, ircxmpp->port,
- NULL, b, "ircxmpp", "http://git.sijanec.eu/sijanec/ircxmpp")) {
+ NULL, b, "ircxmpp", "http git.sijanec.eu/sijanec/ircxmpp")) {
fprintf(stderr, "could not connect: %s\n",
irc_strerror(irc_errno(ircxmpp->irc)));
- return 1;
+ return 2;
}
+ return 0;
}
struct timeval tv;
fd_set in_set, out_set;
@@ -425,13 +437,13 @@ int irc_run_once_control (struct ircxmpp * ircxmpp) { /* returns nonzero if fail
if (select(maxfd+1, &in_set, &out_set, NULL, &tv) < 0) {
if (errno == EINTR)
return 0;
- return 1;
+ return 3;
}
if (irc_process_select_descriptors(ircxmpp->irc, &in_set, &out_set))
- return 1;
+ return 4;
return 0;
}
-void init_irc (struct bridge * bridge) {
+static void init_irc (struct bridge * bridge) {
irc_callbacks_t callbacks;
irc_session_t * s;
memset(&callbacks, 0, sizeof(callbacks));
@@ -465,7 +477,7 @@ void init_irc (struct bridge * bridge) {
irc_run_once(bridge);
return;
}
-void init_irc_control (struct ircxmpp * ircxmpp) {
+static void init_irc_control (struct ircxmpp * ircxmpp) {
irc_callbacks_t callbacks;
irc_session_t * s;
memset(&callbacks, 0, sizeof(callbacks));
@@ -499,92 +511,172 @@ void init_irc_control (struct ircxmpp * ircxmpp) {
irc_run_once_control(ircxmpp);
return;
}
-/* /IRC */ /* irc_is_connected(irc_session_t * session): 1 ali 0 */ /* TODO: if nick is used */
+/* /IRC */ /* irc_is_connected(irc_session_t * session): 1 ali 0 */
+struct ircxmpp * ircxmpp_init (void) {
+ xmpp_initialize();
+ return calloc(1, sizeof(struct ircxmpp));
+}
+void ircxmpp_set_jid (struct ircxmpp * ircxmpp, const char * jid) {
+ free(ircxmpp->jid);
+ ircxmpp->jid = strdup(jid);
+}
+void ircxmpp_set_password (struct ircxmpp * ircxmpp, const char * password) {
+ free(ircxmpp->password);
+ ircxmpp->password = strdup(password);
+}
+void ircxmpp_set_hostname (struct ircxmpp * ircxmpp, const char * hostname) {
+ free(ircxmpp->hostname);
+ ircxmpp->hostname = strdup(hostname);
+}
+void ircxmpp_set_port (struct ircxmpp * ircxmpp, unsigned short int port) {
+ ircxmpp->port = port;
+}
+void ircxmpp_set_channel (struct ircxmpp * ircxmpp, const char * channel) {
+ free(ircxmpp->channel);
+ ircxmpp->channel = strdup(channel);
+}
+void ircxmpp_set_muc (struct ircxmpp * ircxmpp, const char * muc) {
+ free(ircxmpp->muc);
+ ircxmpp->muc = strdup(muc);
+}
+void ircxmpp_set_channel_password (struct ircxmpp * ircxmpp, const char * channel_password) {
+ free(ircxmpp->channel_password);
+ ircxmpp->channel_password = strdup(channel_password);
+}
+void ircxmpp_run_once (struct ircxmpp * ircxmpp) {
+ if (!ircxmpp->ctx || !ircxmpp->conn || (!xmpp_conn_is_connected(ircxmpp->conn)
+ && !xmpp_conn_is_connecting(ircxmpp->conn))) {
+ fprintf(stderr, "XMPP control is DISCONNECTED! CONNECTING!\n");
+ if (ircxmpp->conn)
+ xmpp_conn_release(ircxmpp->conn);
+ if (ircxmpp->ctx)
+ xmpp_ctx_free(ircxmpp->ctx);
+ ircxmpp->ctx = xmpp_ctx_new(NULL, xmpp_get_default_logger(XMPP_LEVEL_DEBUG));
+ ircxmpp->conn = xmpp_conn_new(ircxmpp->ctx);
+ xmpp_conn_set_jid(ircxmpp->conn, ircxmpp->jid);
+ xmpp_conn_set_pass(ircxmpp->conn, ircxmpp->password);
+ xmpp_connect_client(ircxmpp->conn, NULL, 0, conn_handler, ircxmpp);
+ }
+ xmpp_run_once(ircxmpp->ctx, 1); /* no need to run for bridges, as they share the ctx */
+ int ret = 0;
+ if ((ret = irc_run_once_control(ircxmpp))) {
+ fprintf(stderr, "IRC control is DISCONNECTED with code %d. CONNECTING!\n", ret);
+ if (ircxmpp->irc)
+ irc_destroy_session(ircxmpp->irc);
+ init_irc_control(ircxmpp);
+ }
+ struct bridge ** bridge = &ircxmpp->bridges;
+ while (bridge && *bridge) {
+ struct bridge ** next = NULL;
+ if ((*bridge)->next)
+ next = &((*bridge)->next);
+ if ((*bridge)->irc && irc_run_once(*bridge)) {
+ free_bridge(bridge, "irc connection dropped");
+ goto cont;
+ }
+ if ((*bridge)->conn && !xmpp_conn_is_connected((*bridge)->conn)
+ && !xmpp_conn_is_connecting(((*bridge)->conn))) {
+ if ((*bridge)->side == IRC && (*bridge)->messages_length) {
+ fprintf(stderr, "RECONNECTING BRIDGE BECAUSE IT DIED and has msgs!");
+ xmpp_connect_client((*bridge)->conn, NULL, 0,
+ conn_handler_bridge, *bridge);
+ } else
+ free_bridge(bridge, "xmpp connection dropped");
+ goto cont;
+ }
+ while ((*bridge)->conn && xmpp_conn_is_connected((*bridge)->conn)
+ && (*bridge)->messages_length
+ && xmpp_conn_get_bound_jid((*bridge)->conn)) {
+ char id[64];
+ fprintf(stderr, "sending xmpp msg from %s\n", (*bridge)->identifier);
+ sprintf(id, "ircxmpp-%x", rand());
+ xmpp_stanza_t * stan = xmpp_message_new(ircxmpp->ctx,
+ "groupchat", ircxmpp->muc, id);
+ xmpp_message_set_body(stan,
+ (*bridge)->messages[(*bridge)->messages_length-1]);
+ xmpp_stanza_set_from(stan, xmpp_conn_get_bound_jid((*bridge)->conn));
+ xmpp_send((*bridge)->conn, stan);
+ xmpp_stanza_release(stan);
+ free((*bridge)->messages[--(*bridge)->messages_length]);
+ }
+cont:
+ bridge = next;
+ }
+}
+void ircxmpp_free (struct ircxmpp * ircxmpp) {
+ free_bridges(&ircxmpp->bridges);
+ xmpp_conn_release(ircxmpp->conn);
+ xmpp_ctx_free(ircxmpp->ctx);
+ xmpp_shutdown();
+ irc_cmd_quit(ircxmpp->irc, "vsesplošni izklop programa");
+ irc_run_once_control(ircxmpp); // verjetno je to potrebno, da pošlje quit
+ irc_destroy_session(ircxmpp->irc);
+ free(ircxmpp->ircnick);
+ free(ircxmpp->irchost);
+ free(ircxmpp->jid);
+ free(ircxmpp->password);
+ free(ircxmpp->hostname);
+ free(ircxmpp->channel);
+ free(ircxmpp->muc);
+ free(ircxmpp->channel_password);
+ free(ircxmpp);
+}
+#else
int shouldexit = 0;
void signalhandler (int s) {
shouldexit += s+1; /* only for -Wunused-parameter */
}
+const char * str2str (const char * str) {
+ return str;
+}
int main (void) {
srand(time(NULL));
- struct ircxmpp ircxmpp;
- memset(&ircxmpp, '\0', sizeof(ircxmpp));
- xmpp_log_t *log;
- if (!getenv("IX_JID") || !getenv("IX_PASS") || !getenv("IX_HOST") || !getenv("IX_PORT")
- || !getenv("IX_CHANNEL") || !getenv("IX_MUC")) {
- fprintf(stderr, "Usage: IX_JID=jid@xmpp.server IX_PASS=pass IX_HOST=irc.server "
- "IX_PORT=6666 IX_CHANNEL=#channel IX_MUC=muc@xmpp.srv ircxmpp\n");
- return 1;
+#define USAGE " *** ircxmpp is developed at http://git.sijanec.eu/sijanec/ircxmpp ***\n" \
+ "Usage: IX_JID=jid@xmpp.server IX_PASS=pass IX_HOST=irc.server IX_PORT=6666 " \
+ "IX_CHANNEL=#channel IX_MUC=muc@xmpp.srv ircxmpp\n" \
+ "multiple links can be specified by appending a consecutive number, starting with " \
+ "2, to every environment variable. first link is IX_*, second is IX_*2, and so on.\n"
+ size_t handles_length = 0;
+ ircxmpp ** handles = NULL;
+ while (1) { // note that if input config is invalid we leak memory before exiting
+ char b[64]; // i don't free any allocated shit and just return, probably it's ok
+ if (handles_length++)
+ sprintf(b, "IX_JID%d", handles_length);
+ else
+ strcpy(b, "IX_JID");
+ if (!getenv(b)) {
+ if (handles_length == 1) {
+ fprintf(stderr, USAGE "FAIL: at least one link is required!\n");
+ return 1;
+ }
+ handles_length--;
+ break;
+ }
+ handles = realloc(handles, sizeof(ircxmpp *)*handles_length);
+ handles[handles_length-1] = ircxmpp_init();
+#define PREPARE_HANDLE(value, config, function, required) \
+ if (handles_length == 1) \
+ sprintf(b, "IX_" config); \
+ else \
+ sprintf(b, "IX_" config "%d", handles_length); \
+ if (getenv(b)) \
+ ircxmpp_set_##value(handles[handles_length-1], function(getenv(b))); \
+ else if (required) \
+ fprintf(stderr, USAGE "FAIL: environment variable %s was expected to be set.\n", b)
+ PREPARE_HANDLE(jid, "JID", str2str, 1);
+ PREPARE_HANDLE(password, "PASS", str2str, 1);
+ PREPARE_HANDLE(hostname, "HOST", str2str, 1);
+ PREPARE_HANDLE(port, "PORT", atoi, 1);
+ PREPARE_HANDLE(channel, "CHANNEL", str2str, 1);
+ PREPARE_HANDLE(muc, "MUC", str2str, 1);
+ PREPARE_HANDLE(channel_password, "CHPASS", str2str, 0);
}
- ircxmpp.jid = getenv("IX_JID");
- ircxmpp.password = getenv("IX_PASS");
- ircxmpp.hostname = getenv("IX_HOST");
- ircxmpp.port = atoi(getenv("IX_PORT"));
- ircxmpp.channel = getenv("IX_CHANNEL");
- ircxmpp.muc = getenv("IX_MUC");
- ircxmpp.channel_password = getenv("IX_CHPASS");
- xmpp_initialize();
- log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
- init_irc_control(&ircxmpp);
-c:
- ircxmpp.ctx = xmpp_ctx_new(NULL, log);
- ircxmpp.conn = xmpp_conn_new(ircxmpp.ctx);
- xmpp_conn_set_jid(ircxmpp.conn, ircxmpp.jid);
- xmpp_conn_set_pass(ircxmpp.conn, ircxmpp.password);
- xmpp_connect_client(ircxmpp.conn, NULL, 0, conn_handler, &ircxmpp);
signal(SIGTERM, signalhandler);
signal(SIGINT, signalhandler);
// signal(SIGPIPE, SIG_IGN);
while (!shouldexit) { /* TEH EVENT LOOP */
- xmpp_conn_is_disconnected(ircxmpp.conn);
- xmpp_run_once(ircxmpp.ctx, 1);
- struct bridge ** bridge = &ircxmpp.bridges;
- while (*bridge) {
- struct bridge ** next = &((*bridge)->next);
- if ((*bridge)->irc && irc_run_once(*bridge)) {
- free_bridge(bridge, "irc connection dropped");
- goto cont;
- }
- if ((*bridge)->conn)
- xmpp_run_once(xmpp_conn_get_context((*bridge)->conn), 1);
- if ((*bridge)->conn && !xmpp_conn_is_connected((*bridge)->conn)
- && !xmpp_conn_is_connecting(((*bridge)->conn))) {
- if ((*bridge)->side == IRC) {
- fprintf(stderr, "RECONNECTING BRIDGE BECAUSE IT DIED!");
- xmpp_connect_client((*bridge)->conn, NULL, 0,
- conn_handler_bridge, *bridge);
- } else
- free_bridge(bridge, "xmpp connection dropped");
- goto cont;
- }
- while ((*bridge)->conn && xmpp_conn_is_connected((*bridge)->conn)
- && (*bridge)->messages_length
- && xmpp_conn_get_bound_jid((*bridge)->conn)) {
- char id[64];
- fprintf(stderr, "sending xmpp msg from %s\n", (*bridge)->identifier);
- sprintf(id, "ircxmpp-%x", rand());
- xmpp_stanza_t * stan = xmpp_message_new((*bridge)->ircxmpp->ctx,
- "groupchat", (*bridge)->ircxmpp->muc, id);
- xmpp_message_set_body(stan,
- (*bridge)->messages[(*bridge)->messages_length-1]);
- xmpp_stanza_set_from(stan, xmpp_conn_get_bound_jid((*bridge)->conn));
- xmpp_send((*bridge)->conn, stan);
- xmpp_stanza_release(stan);
- free((*bridge)->messages[--(*bridge)->messages_length]);
- }
-cont:
- bridge = next;
- }
- if (!xmpp_conn_is_connected(ircxmpp.conn) && !xmpp_conn_is_connecting(ircxmpp.conn)){
- fprintf(stderr, "XMPP control DISCONNECTED! RECONNECTING!\n");
- xmpp_conn_release(ircxmpp.conn);
- xmpp_ctx_free(ircxmpp.ctx);
- goto c;
- }
- if (irc_run_once_control(&ircxmpp)) {
- fprintf(stderr, "IRC control DISCONNECTED! RECONNECTING!\n");
- irc_destroy_session(ircxmpp.irc);
- init_irc_control(&ircxmpp);
- }
+ for (size_t i = 0; i < handles_length; i++)
+ ircxmpp_run_once(handles[i]);
struct timespec ts = {
.tv_sec = 0,
.tv_nsec = getenv("IX_LOOPDELAY") ? atoi(getenv("IX_LOOPDELAY"))/1000 : 1e8
@@ -592,14 +684,9 @@ cont:
nanosleep(&ts, NULL);
}
fprintf(stderr, "signal received, cleaning up!\n");
- free_bridges(&ircxmpp.bridges);
- xmpp_conn_release(ircxmpp.conn);
- xmpp_ctx_free(ircxmpp.ctx);
- xmpp_shutdown();
- irc_cmd_quit(ircxmpp.irc, "vsesplošni izklop programa");
- irc_run_once_control(&ircxmpp); // verjetno je to potrebno, da pošlje quit
- irc_destroy_session(ircxmpp.irc);
- free(ircxmpp.ircnick);
- free(ircxmpp.irchost);
+ for (size_t i = 0; i < handles_length; i++)
+ ircxmpp_free(handles[i]);
+ free(handles);
return 0;
}
+#endif
diff --git a/ircxmpp.conf b/ircxmpp.conf
index fd635c7..ae11eef 100644
--- a/ircxmpp.conf
+++ b/ircxmpp.conf
@@ -19,3 +19,13 @@
# IX_CHPASS=somepassword
## delay after each event loop cycle in microseconds, defaults to 100ms.
# IX_LOOPDELAY=100000
+####################### ANOTHER LINK SETUP ########################
+## As many links as you'd like can be setup. Append a number, starting with 2, to every setting.
+# IX_JID2=v@lu.e
+# IX_PASS2=value
+# IX_HOST2=valu.e
+# IX_PORT2=6666
+# IX_CHANNEL2=#value
+# IX_MUC2=v@l.u.e
+# IX_CHPASS2=value
+# IX_LOOPDELAY2 does not exist, as the event loop is shared between all links.