summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2022-04-30 15:35:33 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2022-04-30 15:35:33 +0200
commit61125a3302eeb712700efc0208024b066668ed9b (patch)
tree2d30e7eb7d791c7677b2073b3d6147fa5ac98a87
parentnot working. just a checkpoint before I rewrite to binary tree (diff)
downloadircxmpp-61125a3302eeb712700efc0208024b066668ed9b.tar
ircxmpp-61125a3302eeb712700efc0208024b066668ed9b.tar.gz
ircxmpp-61125a3302eeb712700efc0208024b066668ed9b.tar.bz2
ircxmpp-61125a3302eeb712700efc0208024b066668ed9b.tar.lz
ircxmpp-61125a3302eeb712700efc0208024b066668ed9b.tar.xz
ircxmpp-61125a3302eeb712700efc0208024b066668ed9b.tar.zst
ircxmpp-61125a3302eeb712700efc0208024b066668ed9b.zip
-rw-r--r--README3
-rw-r--r--ircxmpp.c416
-rw-r--r--ircxmpp.h37
3 files changed, 288 insertions, 168 deletions
diff --git a/README b/README
index 0c0f23f..49963f3 100644
--- a/README
+++ b/README
@@ -82,12 +82,13 @@ Compilation and manual install from source:
- make install # not required, but otherwise LD_LIBRARY_PATH=. ./ircxmpp for libircxmpp.so
Using as a library:
- - you may only use functions between #else and #endif in ircxmpp.h, handler struct is opaque
+ - you may only use functions after #endif in ircxmpp.h, handler struct is opaque
- after make install, ircxmpp.h and libircxmpp.so are placed in /usr/{include,lib}
- #include <ircxmpp.h> and link with -lircxmpp
- functions return nothing (except ircxmpp_init) and log to standard error
- do not call ircxmpp_set_*() functions after first call to ircxmpp_run_once()
- actual main function of the ircxmpp program is in ircxmpp.c between #else and #endif
+ - in the 0.0.x stage, no binary compatiblity is guaranteed. nothing is guaranteed.
Gentoo/openrc?:
- http://github.com/OpenRC/openrc/pull/517 needs to be merged before for increased security
diff --git a/ircxmpp.c b/ircxmpp.c
index 5d4b8d9..d435797 100644
--- a/ircxmpp.c
+++ b/ircxmpp.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -11,58 +12,88 @@
#include "ircxmpp.h"
#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, ...) {
+__attribute__((noreturn)) __attribute__((unused))
+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"
+ fprintf(stderr, "BUG in ircxmpp %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);
- if ((*bridge)->irc) {
- irc_cmd_quit((*bridge)->irc, razlog);
- irc_run_once(*bridge); // verjetno je to potrebno, da pošlje quit
- irc_destroy_session((*bridge)->irc);
- }
- if ((*bridge)->conn)
- 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]);
- free((*bridge)->messages);
- if ((*bridge)->next)
- (*bridge)->next->prev = (*bridge)->prev;
- struct bridge * tofree = *bridge;
- if ((*bridge)->prev)
- (*bridge)->prev->next = (*bridge)->next;
+static int bridge_compare (const void * ap, const void * bp) {
+ const struct bridge * a = (const struct bridge *) ap;
+ const struct bridge * b = (const struct bridge *) bp;
+ int i = strcmp(a->identifier, b->identifier);
+ if (i)
+ return i;
+ if (a->side == b->side)
+ return 0;
else {
- if ((*bridge)->next)
- (*bridge)->next->prev = (*bridge)->prev;
- *bridge = (*bridge)->next;
+ if (a->side > b->side)
+ return -1;
+ else
+ return 1;
}
- free(tofree);
}
-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");
+#define LOG(ircxmpp, level, ...) logwrite(ircxmpp, level, __FILE__, __LINE__, __func__, __VA_ARGS__);
+static void logwrite (struct ircxmpp * ircxmpp, enum ircxmpp_loglevel level, const char * file,
+ int line, const char * function, const char * format, ...) {
+ va_list ap_len, ap_print;
+ va_start(ap_len, format);
+ va_copy(ap_print, ap_len);
+#define LOCATION_FORMAT "%s()@%s:%d "
+#define LOCATION_ARGS function, file, line
+ int location_len = snprintf(NULL, 0, LOCATION_FORMAT, LOCATION_ARGS);
+ int len = vsnprintf(NULL, 0, format, ap_len) + 1 + location_len;
+ if (len > 65535)
+ return;
+ char buf[len];
+ char * c = buf;
+ c += sprintf(c, LOCATION_FORMAT, LOCATION_ARGS);
+ vsprintf(c, format, ap_print);
+ ircxmpp->log_handler(ircxmpp->log_userdata, level, "ircxmpp", buf);
+ va_end(ap_len);
+ va_end(ap_print);
+}
+static void free_bridge (struct bridge * bridge, const char * razlog) {
+ if (!bridge)
+ return;
+ LOG(bridge->ircxmpp, IRCXMPP_DEBUG, "freeing bridge with reason: %s", razlog);
+ if (bridge->irc) {
+ irc_cmd_quit(bridge->irc, razlog);
+ irc_run_once(bridge); // verjetno je to potrebno, da pošlje quit
+ irc_destroy_session(bridge->irc);
}
+ if (bridge->conn)
+ xmpp_conn_release(bridge->conn); // graceful disconnect, what is that?
+ tdelete(bridge, bridge->ircxmpp->bridges, bridge_compare);
+ free(bridge->identifier);
+ for (size_t i = 0; i < bridge->messages_length; i++)
+ free(bridge->messages[i]);
+ free(bridge->messages);
+ free(bridge);
+}
+
+static char * free_reason = "global readdson not set since startup. this is a bug. report it.";
+static void free_bridge_global_reason (void * bridge) {
+ free_bridge((struct bridge *) bridge, free_reason);
+}
+static void free_bridges (void ** bridges) {
+ free_reason = "vsi mostovi se podirajo, ker se ircxmpp izklaplja";
+ tdestroy(*bridges, free_bridge_global_reason);
}
-static struct bridge ** find_bridge (struct bridge ** bridges, const char * id, enum side side) {
-s:
- if (!bridges || !*bridges)
+static struct bridge * find_bridge (void ** bridges, const char * id, enum side side) {
+ struct bridge bridge = {
+ .side = side,
+ .identifier = (char *) id
+ };
+ struct bridge ** found = tfind(&bridge, bridges, bridge_compare);
+ if (!found)
return NULL;
- if ((*bridges)->side == side && !strcmp((*bridges)->identifier, id))
- return bridges;
- bridges = &((*bridges)->next);
- goto s;
+ return *found;
}
static void jid2ircnick (char * jid) { /* edits a jid into an irc nick. libera trims nicks. */
@@ -93,21 +124,17 @@ static void jid2ircuser (char * jid) {
*jid = 'x';
}
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);
+ struct bridge * bridge = 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", f, s == IRC ? "IRC" : "XMPP",
+ LOG(ircxmpp, IRCXMPP_DEBUG, "sending text from %s to %s: %s", f, s == IRC ? "IRC" : "XMPP",
m ? m : "[join only]");
- struct bridge * bridge;
- if (!bridge_resp) {
+ if (!bridge) {
bridge = calloc(1, sizeof(struct bridge));
- if (ircxmpp->bridges)
- ircxmpp->bridges->prev = bridge;
- bridge->next = ircxmpp->bridges;
- ircxmpp->bridges = bridge;
bridge->identifier = strdup(f);
bridge->ircxmpp = ircxmpp;
bridge->side = !s;
+ tsearch(bridge, &ircxmpp->bridges, bridge_compare);
if (s == IRC)
init_irc(bridge);
else {
@@ -116,8 +143,7 @@ static void bridge_forward (const char * f, const char * m, struct ircxmpp * irc
xmpp_conn_set_pass(bridge->conn, bridge->ircxmpp->password);
xmpp_connect_client(bridge->conn, NULL, 0, conn_handler_bridge, bridge);
}
- } else
- bridge = *bridge_resp;
+ }
if (s == IRC) {
irc_cmd_join(bridge->irc, ircxmpp->channel, ircxmpp->channel_password);
irc_run_once(bridge);
@@ -138,13 +164,12 @@ static void bridge_forward (const char * f, const char * m, struct ircxmpp * irc
bridge->messages[bridge->messages_length++] = strdup(m);
}
} /* 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;
+static int message_handler (xmpp_conn_t * const c __attribute__((unused)),
+ xmpp_stanza_t * const stanza, void * const ud) {
struct ircxmpp * ircxmpp = (struct ircxmpp *) ud;
xmpp_stanza_t * body;
const char * type;
- char * intext;
+ char * tx;
body = xmpp_stanza_get_child_by_name(stanza, "body");
if (body == NULL)
return 1;
@@ -155,10 +180,10 @@ static int message_handler (xmpp_conn_t * const c, xmpp_stanza_t * const stanza,
return 1; // this is our message
if (xmpp_stanza_get_child_by_name_and_ns(stanza, "delay", "urn:xmpp:delay"))
return 1; // MUC MAM history
- intext = xmpp_stanza_get_text(body);
- printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext);
- bridge_forward(xmpp_stanza_get_from(stanza), intext, ircxmpp, IRC);
- xmpp_free(ircxmpp->ctx, intext);
+ tx = xmpp_stanza_get_text(body);
+ LOG(ircxmpp, IRCXMPP_INFO, "Incoming message from %s: %s", xmpp_stanza_get_from(stanza), tx);
+ bridge_forward(xmpp_stanza_get_from(stanza), tx, ircxmpp, IRC);
+ xmpp_free(ircxmpp->ctx, tx);
return 1;
}
static int presence_handler (xmpp_conn_t * const c, xmpp_stanza_t * const stanza, void * const ud) {
@@ -166,25 +191,25 @@ static int presence_handler (xmpp_conn_t * const c, xmpp_stanza_t * const 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));
+ LOG(ircxmpp, IRCXMPP_INFO, "user %s left MUC", xmpp_stanza_get_from(stanza));
free_bridge(find_bridge(&ircxmpp->bridges, xmpp_stanza_get_from(stanza), XMPP),
"ircxmpp: sogovornik je zapustil XMPP MUC sobo");
}
if (!xmpp_stanza_get_type(stanza)) {
- fprintf(stderr, "sogovornik %s se je pridružil MUC\n", xmpp_stanza_get_from(stanza));
+ LOG(ircxmpp, IRCXMPP_INFO, "user %s connected to MUC", xmpp_stanza_get_from(stanza));
bridge_forward(xmpp_stanza_get_from(stanza), NULL, ircxmpp, IRC);
}
return 1;
}
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) {
+ const int error __attribute__((unused)),
+ xmpp_stream_error_t * const stream_error __attribute__((unused)),
+ 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);
if (status == XMPP_CONN_CONNECT) {
xmpp_stanza_t * pres;
- fprintf(stderr, "DEBUG: connected.\n");
+ LOG(ircxmpp, IRCXMPP_INFO, "control connected to XMPP.");
xmpp_handler_add(conn, message_handler, NULL, "message", NULL, ircxmpp);
xmpp_handler_add(conn, presence_handler, NULL, "presence", NULL, ircxmpp);
/* Send initial <presence/> so that we appear online to contacts */
@@ -202,23 +227,19 @@ static void conn_handler (xmpp_conn_t * const conn, const xmpp_conn_event_t stat
xmpp_stanza_release(x);
xmpp_send(conn, pres);
xmpp_stanza_release(pres);
- } else {
- fprintf(stderr, "DEBUG: disconnected\n");
- // xmpp_stop(ircxmpp->ctx);
- }
+ } else
+ LOG(ircxmpp, IRCXMPP_WARN, "control disconnected from XMPP.");
}
-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) {
+static void conn_handler_bridge (xmpp_conn_t * const conn __attribute__((unused)),
+ const xmpp_conn_event_t status, const int error __attribute__((unused)),
+ xmpp_stream_error_t * const stream_error __attribute__((unused)),
+ 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);
- if (!conn) /* just for -Wunused-parameter */
- return;
if (status == XMPP_CONN_CONNECT) {
char stanzato[512];
snprintf(stanzato, 512, "%s/%s ircxmpp_%x", bridge->ircxmpp->muc,
bridge->identifier, rand());
- fprintf(stderr, "joining muc %s (to)\n", stanzato);
+ LOG(bridge->ircxmpp, IRCXMPP_INFO, "bridge joining muc %s (to)", stanzato);
xmpp_stanza_t * pres = xmpp_presence_new(bridge->ircxmpp->ctx); // joining a MUC
xmpp_stanza_set_to(pres, stanzato);
xmpp_stanza_t * x = xmpp_stanza_new(bridge->ircxmpp->ctx);
@@ -228,55 +249,88 @@ static void conn_handler_bridge (xmpp_conn_t * const conn, const xmpp_conn_event
xmpp_stanza_release(x);
xmpp_send(bridge->conn, pres);
xmpp_stanza_release(pres);
- } else {
- fprintf(stderr, "DEBUG: disconnected\n");
- // xmpp_stop(ircxmpp->ctx);
- }
+ } else
+ LOG(bridge->ircxmpp, IRCXMPP_WARN, "control disconnected from XMPP.");
}
/* IRC */
+static void dump_event_control (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
+ struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
+ int requiredbuf = 256;
+ for (unsigned int i = 0; i < c; i++) {
+ requiredbuf += strlen(p[c])+256;
+ }
+ if (requiredbuf > 65535)
+ return;
+ char buf[requiredbuf];
+ char * cp = buf;
+ cp += sprintf(cp, "%s, origin %s, params %d [", e, o ? o : "NULL", c);
+ for (unsigned int i = 0; i < c; i++) {
+ if (i)
+ cp += sprintf(cp, "|");
+ cp += sprintf(cp, "%s", p[i]);
+ }
+ cp += sprintf(cp, "]");
+ ircxmpp->log_handler(ircxmpp->log_userdata, IRCXMPP_DEBUG, "irc_event_control", buf);
+}
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 */
+ struct bridge * bridge = (struct bridge *) irc_get_ctx(s);
+ struct ircxmpp * ircxmpp = bridge->ircxmpp;
+ int requiredbuf = 256;
+ for (unsigned int i = 0; i < c; i++) {
+ requiredbuf += strlen(p[c])+256;
+ }
+ if (requiredbuf > 65535)
return;
- fprintf(stderr, "Event %s, origin %s, params %d [", e, o ? o : "NULL", c);
+ char buf[requiredbuf];
+ char * cp = buf;
+ cp += sprintf(cp, "%s, origin %s, params %d [", e, o ? o : "NULL", c);
for (unsigned int i = 0; i < c; i++) {
if (i)
- fprintf(stderr, "|");
- fprintf(stderr, "%s", p[i]);
+ cp += sprintf(cp, "|");
+ cp += sprintf(cp, "%s", p[i]);
}
- fprintf(stderr, "]\n");
+ cp += sprintf(cp, "]");
+ ircxmpp->log_handler(ircxmpp->log_userdata, IRCXMPP_DEBUG, "irc_event", buf);
}
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);
+ dump_event(s, e, o, p, c);
irc_cmd_join(s, bridge->ircxmpp->channel, bridge->ircxmpp->channel_password);
}
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);
+ dump_event_control(s, e, o, p, c);
irc_cmd_join(s, ircxmpp->channel, ircxmpp->channel_password);
}
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!!! */
+ dump_event(s, e, o, p, c);
+ 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/.");
+}
+static void event_privmsg_control (
+ irc_session_t * s, const char * e, const char * o, const char ** p, unsigned c) {
+ dump_event_control(s, e, o, p, c);
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/.");
}
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);
+ dump_event_control(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");
+ free_bridge(find_bridge(&ircxmpp->bridges, o, IRC), "part or quit from irc");
} /* part and quit events */
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 */
+ dump_event_control(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);
@@ -284,7 +338,7 @@ static void event_channel_control (
}
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);
+ dump_event_control(s, e, o, p, c);
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
char buf[512];
strncpy(buf, o, 512-1);
@@ -301,21 +355,18 @@ static void event_join_control (
if (cp) {
free(ircxmpp->irchost);
ircxmpp->irchost = strdup(++cp);
- fprintf(stderr, "FOUND OUR HOSTNAME: %s\n", ircxmpp->irchost);
+ LOG(ircxmpp, IRCXMPP_DEBUG, "FOUND OUR HOSTNAME: %s", ircxmpp->irchost);
}
}
bridge_forward(o /* indeed n!u@h */, NULL, ircxmpp, XMPP);
}
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 */
+ dump_event_control(s, e, o, p, c); /* o je originalen nick, p[0] je nov nick */
if (!c)
return;
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
- struct bridge ** bridge = find_bridge(&ircxmpp->bridges, o /* indeed n!u@h */, IRC);
- if (!bridge || !*bridge)
- return;
- free_bridge(bridge, "nick change from irc");
+ free_bridge(find_bridge(&ircxmpp->bridges, o, IRC), "nick change from irc");
char buf[512];
snprintf(buf, 512, "%s%s", p[0], strchr(o, '!') ? strchr(o, '!')
: "neznan uporabnik@neznan strežnik");
@@ -323,7 +374,7 @@ static void event_nick_control (
}
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 */
+ dump_event_control(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]);
@@ -356,7 +407,7 @@ static void event_numeric_control (
char b[512];
struct ircxmpp * ircxmpp = (struct ircxmpp *) irc_get_ctx(s);
sprintf(b, "%d", e);
- dump_event(s, b, o, p, c);
+ dump_event_control(s, b, o, p, c);
switch (e) {
case ERR_NONICKNAMEGIVEN:
case ERR_ERRONEUSNICKNAME:
@@ -381,10 +432,10 @@ static int irc_run_once (struct bridge * bridge) { /* returns nonzero if connect
sprintf(b, "xmpp_%x", rand());
if (!strlen(u))
strcpy(u, "ircxmpp");
- fprintf(stderr, "CONNECTING bridge %s!%s@host\n", b, u);
+ LOG(bridge->ircxmpp, IRCXMPP_INFO, "CONNECTING bridge %s!%s@host", b, u);
if (irc_connect(bridge->irc, bridge->ircxmpp->hostname, bridge->ircxmpp->port,
NULL, b, u, bridge->identifier)) {
- fprintf(stderr, "could not connect: %s\n",
+ LOG(bridge->ircxmpp, IRCXMPP_ERROR, "bridge could not connect: %s",
irc_strerror(irc_errno(bridge->irc)));
return 1;
}
@@ -400,11 +451,11 @@ static int irc_run_once (struct bridge * bridge) { /* returns nonzero if connect
if (select(maxfd+1, &in_set, &out_set, NULL, &tv) < 0) {
if (errno == EINTR)
return 0;
- fprintf(stderr, "SELECT failed in bridge!\n");
+ LOG(bridge->ircxmpp, IRCXMPP_WARN, "SELECT failed in bridge!");
return 1;
}
if (irc_process_select_descriptors(bridge->irc, &in_set, &out_set)) {
- fprintf(stderr, "PROCESS_SELECT failed in bridge!\n");
+ LOG(bridge->ircxmpp, IRCXMPP_WARN, "PROCESS_SELECT failed in bridge!");
return 1;
}
return 0;
@@ -415,12 +466,12 @@ static int irc_run_once_control (struct ircxmpp * ircxmpp) { /* returns nonzero
if (!irc_is_connected(ircxmpp->irc)) {
char b[512];
sprintf(b, "ircxmpp_%X", rand());
- fprintf(stderr, "CONNECTING control %s!ircxmpp@host\n", b);
+ LOG(ircxmpp, IRCXMPP_INFO, "CONNECTING control %s!ircxmpp@host", b);
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")) {
- fprintf(stderr, "could not connect: %s\n",
+ LOG(ircxmpp, IRCXMPP_ERROR, "control could not connect: %s",
irc_strerror(irc_errno(ircxmpp->irc)));
return 2;
}
@@ -469,7 +520,7 @@ static void init_irc (struct bridge * bridge) {
// callbacks.event_dcc_chat_req = dump_event;
// callbacks.event_dcc_send_req = dump_event;
if (!(s = irc_create_session(&callbacks))) {
- fprintf(stderr, "could not create IRC session!\n");
+ LOG(bridge->ircxmpp, IRCXMPP_ERROR, "could not create IRC bridge session!");
return;
}
bridge->irc = s;
@@ -486,24 +537,24 @@ static void init_irc_control (struct ircxmpp * ircxmpp) {
callbacks.event_quit = event_partquit_control;
callbacks.event_join = event_join_control;
callbacks.event_part = event_partquit_control;
- callbacks.event_mode = dump_event;
- callbacks.event_umode = dump_event;
+ callbacks.event_mode = dump_event_control;
+ callbacks.event_umode = dump_event_control;
callbacks.event_topic = event_topic_control;
- callbacks.event_kick = dump_event;
+ callbacks.event_kick = dump_event_control;
callbacks.event_channel = event_channel_control;
- callbacks.event_privmsg = event_privmsg;
- callbacks.event_notice = dump_event;
- callbacks.event_channel_notice = dump_event;
- callbacks.event_invite = dump_event;
- callbacks.event_ctcp_req = dump_event;
- callbacks.event_ctcp_rep = dump_event;
- callbacks.event_ctcp_action = dump_event;
- callbacks.event_unknown = dump_event;
+ callbacks.event_privmsg = event_privmsg_control;
+ callbacks.event_notice = dump_event_control;
+ callbacks.event_channel_notice = dump_event_control;
+ callbacks.event_invite = dump_event_control;
+ callbacks.event_ctcp_req = dump_event_control;
+ callbacks.event_ctcp_rep = dump_event_control;
+ callbacks.event_ctcp_action = dump_event_control;
+ callbacks.event_unknown = dump_event_control;
callbacks.event_numeric = event_numeric_control;
// callbacks.event_dcc_chat_req = dump_event;
// callbacks.event_dcc_send_req = dump_event;
if (!(s = irc_create_session(&callbacks))) {
- fprintf(stderr, "could not create IRC control session!\n");
+ LOG(ircxmpp, IRCXMPP_ERROR, "could not create IRC control session!");
return;
}
ircxmpp->irc = s;
@@ -511,10 +562,61 @@ static void init_irc_control (struct ircxmpp * ircxmpp) {
irc_run_once_control(ircxmpp);
return;
}
+static void ircxmpp_default_logger (void * const u __attribute__((unused)),
+ const enum ircxmpp_loglevel l, const char * const a, const char * const m) {
+ char * t = "unspec";
+ switch (l) {
+ case IRCXMPP_DEBUG:
+ t = "DEBUG";
+ break;
+ case IRCXMPP_INFO:
+ t = "INFO";
+ break;
+ case IRCXMPP_WARN:
+ t = "WARN";
+ break;
+ case IRCXMPP_ERROR:
+ t = "ERROR";
+ break;
+ }
+ fprintf(stderr, "[ircxmpp %s] %s: %s\n", t, a, m);
+}
/* /IRC */ /* irc_is_connected(irc_session_t * session): 1 ali 0 */
+static void send_xmpp_logs_to_me (void * const u, const xmpp_log_level_t l, const char * const a,
+ const char * const m) {
+ enum ircxmpp_loglevel loglevel = IRCXMPP_ERROR;
+ switch (l) {
+ case XMPP_LEVEL_DEBUG:
+ loglevel = IRCXMPP_DEBUG;
+ break;
+ case XMPP_LEVEL_INFO:
+ loglevel = IRCXMPP_INFO;
+ break;
+ case XMPP_LEVEL_WARN:
+ loglevel = IRCXMPP_WARN;
+ break;
+ case XMPP_LEVEL_ERROR:
+ loglevel = IRCXMPP_ERROR;
+ break;
+ }
+ struct ircxmpp * ircxmpp = (struct ircxmpp *) u;
+ ircxmpp->log_handler(ircxmpp->log_userdata, loglevel, a, m);
+}
struct ircxmpp * ircxmpp_init (void) {
xmpp_initialize();
- return calloc(1, sizeof(struct ircxmpp));
+ struct ircxmpp * ircxmpp = calloc(1, sizeof(struct ircxmpp));
+ ircxmpp->log_handler = ircxmpp_default_logger;
+ ircxmpp->xmpp_logger.handler = send_xmpp_logs_to_me;
+ ircxmpp->xmpp_logger.userdata = ircxmpp;
+ return ircxmpp;
+}
+void ircxmpp_set_log_handler (struct ircxmpp * ircxmpp, ircxmpp_logger log_handler) {
+ if (!log_handler)
+ ircxmpp->log_handler = ircxmpp_default_logger;
+ ircxmpp->log_handler = log_handler;
+}
+void ircxmpp_set_log_userdata (struct ircxmpp * ircxmpp, void * log_userdata) {
+ ircxmpp->log_userdata = log_userdata;
}
void ircxmpp_set_jid (struct ircxmpp * ircxmpp, const char * jid) {
free(ircxmpp->jid);
@@ -543,15 +645,45 @@ void ircxmpp_set_channel_password (struct ircxmpp * ircxmpp, const char * channe
free(ircxmpp->channel_password);
ircxmpp->channel_password = strdup(channel_password);
}
+static void obdelaj_bridge (const void * nodep, VISIT which __attribute__((unused)),
+ int depth __attribute__((unused))) {
+ struct bridge * bridge = *(struct bridge **) nodep;
+ if (bridge->irc && irc_run_once(bridge)) {
+ free_bridge(bridge, "irc connection dropped");
+ return;
+ }
+ if (bridge->conn && !xmpp_conn_is_connected(bridge->conn)
+ && !xmpp_conn_is_connecting((bridge->conn))) {
+ if (bridge->side == IRC && bridge->messages_length) {
+ LOG(bridge->ircxmpp, IRCXMPP_WARN, "RECONNECTING dead BRIDGE with msgs!");
+ xmpp_connect_client(bridge->conn, NULL, 0, conn_handler_bridge, bridge);
+ } else
+ free_bridge(bridge, "xmpp connection dropped");
+ return;
+ }
+ while (bridge->conn && xmpp_conn_is_connected(bridge->conn) && bridge->messages_length
+ && xmpp_conn_get_bound_jid(bridge->conn)) {
+ char id[64];
+ LOG(bridge->ircxmpp, IRCXMPP_DEBUG, "sending xmpp msg from %s", 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]);
+ }
+}
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");
+ LOG(ircxmpp, IRCXMPP_WARN, "XMPP control is DISCONNECTED! CONNECTING!");
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->ctx = xmpp_ctx_new(NULL, &ircxmpp->xmpp_logger);
ircxmpp->conn = xmpp_conn_new(ircxmpp->ctx);
xmpp_conn_set_jid(ircxmpp->conn, ircxmpp->jid);
xmpp_conn_set_pass(ircxmpp->conn, ircxmpp->password);
@@ -560,48 +692,12 @@ void ircxmpp_run_once (struct ircxmpp * 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);
+ LOG(ircxmpp, IRCXMPP_WARN, "IRC control DISCONNECTED, code %d. CONNECTING!", 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;
- }
+ twalk(ircxmpp->bridges, obdelaj_bridge);
}
void ircxmpp_free (struct ircxmpp * ircxmpp) {
free_bridges(&ircxmpp->bridges);
@@ -623,8 +719,8 @@ void ircxmpp_free (struct ircxmpp * ircxmpp) {
}
#else
int shouldexit = 0;
-void signalhandler (int s) {
- shouldexit += s+1; /* only for -Wunused-parameter */
+void signalhandler (int s __attribute__((unused))) {
+ shouldexit++;
}
const char * str2str (const char * str) {
return str;
diff --git a/ircxmpp.h b/ircxmpp.h
index 89f23a8..3ca5e03 100644
--- a/ircxmpp.h
+++ b/ircxmpp.h
@@ -1,4 +1,12 @@
-#ifdef IX_LIB /* do not use functions until #else in programs that use libircxmpp. */
+enum ircxmpp_loglevel {
+ IRCXMPP_DEBUG,
+ IRCXMPP_INFO,
+ IRCXMPP_WARN,
+ IRCXMPP_ERROR
+};
+typedef void (*ircxmpp_logger)
+ (void * const, const enum ircxmpp_loglevel, const char * const, const char * const);
+#ifdef IX_LIB /* do not use functions until #endif in programs that use libircxmpp. */
#include <libircclient.h> /* do not use members of struct ircxmpp, use opaque ircxmpp type! */
#include <strophe.h>
enum irc_numeric { /* numerics from rfc 1459 */
@@ -143,8 +151,6 @@ enum side {
};
struct bridge { // xmpp connection is the same for every user, only IRC connection differs
struct ircxmpp * ircxmpp;
- struct bridge * next;
- struct bridge * prev;
char * identifier; /* jid if side is XMPP or nickname if side is IRC */
irc_session_t * irc;
xmpp_conn_t * conn; /* isti xmpp_ctx_t ima lahko več connov */
@@ -153,7 +159,7 @@ struct bridge { // xmpp connection is the same for every user, only IRC connecti
char ** messages;
};
struct ircxmpp {
- struct bridge * bridges;
+ void * bridges;
irc_session_t * irc;
char * ircnick;
char * irchost;
@@ -166,10 +172,19 @@ struct ircxmpp {
char * channel;
char * muc;
char * channel_password;
+ void * log_userdata;
+ ircxmpp_logger log_handler;
+ xmpp_log_t xmpp_logger;
};
-static void free_bridge (struct bridge **, const char *);
-static void free_bridges (struct bridge **);
-static struct bridge ** find_bridge (struct bridge **, const char *, enum side);
+static void send_xmpp_logs_to_me (
+ void * const, const xmpp_log_level_t, const char * const, const char * const);
+static void logwrite (struct ircxmpp *, enum ircxmpp_loglevel, const char *, int,
+ const char *, const char *, ...);
+static int bridge_compare (const void *, const void *);
+static void free_bridge (struct bridge *, const char *);
+static void free_bridges (void **);
+static void free_bridge_global_reason (void *);
+static struct bridge * find_bridge (void **, const char *, enum side);
static void jid2ircnick (char *);
static void jid2ircuser (char *);
static void bridge_forward (const char *, const char *, struct ircxmpp *, enum side);
@@ -180,6 +195,8 @@ static void conn_handler (xmpp_conn_t * const, const xmpp_conn_event_t, const in
static void conn_handler_bridge (xmpp_conn_t * const, const xmpp_conn_event_t, const int,
xmpp_stream_error_t * const, void * const);
// IRC
+static void dump_event_control (
+ irc_session_t *, const char *, const char *, const char **, unsigned);
static void dump_event (irc_session_t *, const char *, const char *, const char **, unsigned);
static void event_connect (irc_session_t *, const char *, const char *, const char **, unsigned);
static void event_connect_control (
@@ -201,11 +218,16 @@ static void event_numeric_control (
static int irc_run_once (struct bridge *);
static void init_irc (struct bridge *);
static void init_irc_control (struct ircxmpp *);
+static void obdelaj_bridge (const void *, VISIT, int);
+static void ircxmpp_default_logger (
+ void * const, const enum ircxmpp_loglevel, const char * const, const char * const);
// /IRC
#endif // IX_LIB
// ZUNANJE
typedef struct ircxmpp ircxmpp; /* opaque handle */
ircxmpp * ircxmpp_init (void);
+void ircxmpp_set_log_handler (ircxmpp *, ircxmpp_logger);
+void ircxmpp_set_log_userdata (ircxmpp *, void *);
void ircxmpp_set_jid (ircxmpp *, const char *);
void ircxmpp_set_password (ircxmpp *, const char *);
void ircxmpp_set_hostname (ircxmpp *, const char *);
@@ -215,4 +237,5 @@ void ircxmpp_set_muc (ircxmpp *, const char *);
void ircxmpp_set_channel_password (ircxmpp *, const char *);
void ircxmpp_run_once (struct ircxmpp *);
void ircxmpp_free (struct ircxmpp *);
+int ircxmpp_version = 0;
// /ZUNANJE