Hi Please find attached an update to bitlbee 3.2.1. OTR patch has been merged upstream and I have regenerated the others.
Changelog: Version 3.2.1 (released 2013-11-27) hilights: - http_client now uses HTTP/1.1, which is required by Twitter since last week. - A bunch of other things. Cheers Tom
Index: Makefile =================================================================== RCS file: /cvs/ports/net/bitlbee/Makefile,v retrieving revision 1.52 diff -u -p -u -r1.52 Makefile --- Makefile 15 Aug 2013 16:34:00 -0000 1.52 +++ Makefile 31 Dec 2013 22:10:53 -0000 @@ -2,9 +2,9 @@ COMMENT= IRC proxy to connect to AIM, ICQ, Jabber, MSN and Yahoo -DISTNAME= bitlbee-3.2 +DISTNAME= bitlbee-3.2.1 CATEGORIES= net -REVISION= 2 +REVISION= 0 HOMEPAGE= http://bitlbee.org/ Index: distinfo =================================================================== RCS file: /cvs/ports/net/bitlbee/distinfo,v retrieving revision 1.24 diff -u -p -u -r1.24 distinfo --- distinfo 30 Jan 2013 21:45:42 -0000 1.24 +++ distinfo 31 Dec 2013 22:10:53 -0000 @@ -1,2 +1,2 @@ -SHA256 (bitlbee-3.2.tar.gz) = G0OCjpBvVFCZM1Py6+zGwDjwJhxNw/FyLrr6bqPmIDA= -SIZE (bitlbee-3.2.tar.gz) = 666404 +SHA256 (bitlbee-3.2.1.tar.gz) = APQR3X1tKPMPDnPkbJy+iLQAbn8Drf4HuQqXKAopD1k= +SIZE (bitlbee-3.2.1.tar.gz) = 657595 Index: patches/patch-configure =================================================================== RCS file: /cvs/ports/net/bitlbee/patches/patch-configure,v retrieving revision 1.9 diff -u -p -u -r1.9 patch-configure --- patches/patch-configure 13 Mar 2013 21:42:58 -0000 1.9 +++ patches/patch-configure 31 Dec 2013 22:10:53 -0000 @@ -1,7 +1,7 @@ $OpenBSD: patch-configure,v 1.9 2013/03/13 21:42:58 landry Exp $ ---- configure.orig Mon Jan 7 00:41:11 2013 -+++ configure Wed Mar 6 16:23:10 2013 -@@ -362,6 +362,23 @@ detect_resolv_dynamic() +--- configure.orig Tue Dec 31 21:40:21 2013 ++++ configure Tue Dec 31 21:42:26 2013 +@@ -344,6 +344,24 @@ detect_resolv_dynamic() FreeBSD ) # In FreeBSD res_* routines are present in libc.so LIBRESOLV=;; @@ -17,11 +17,12 @@ $OpenBSD: patch-configure,v 1.9 2013/03/ + +int main() +{ -+ res_query( NULL, 0, 0, NULL, 0 ); -+ dn_expand( NULL, NULL, NULL, NULL, 0 ); ++ res_query( NULL, 0, 0, NULL, 0 ); ++ dn_expand( NULL, NULL, NULL, NULL, 0 ); +} +' +;; ++ * ) LIBRESOLV=-lresolv;; esac Index: patches/patch-lib_misc_c =================================================================== RCS file: /cvs/ports/net/bitlbee/patches/patch-lib_misc_c,v retrieving revision 1.1 diff -u -p -u -r1.1 patch-lib_misc_c --- patches/patch-lib_misc_c 13 Mar 2013 21:42:58 -0000 1.1 +++ patches/patch-lib_misc_c 31 Dec 2013 22:10:53 -0000 @@ -1,8 +1,8 @@ $OpenBSD: patch-lib_misc_c,v 1.1 2013/03/13 21:42:58 landry Exp $ http://bugs.bitlbee.org/bitlbee/ticket/421 needed until ns_parse family of functions are added to lib/libc/asr ---- lib/misc.c.orig Mon Jan 7 00:41:11 2013 -+++ lib/misc.c Wed Mar 6 19:13:27 2013 +--- lib/misc.c.orig Wed Nov 27 22:54:54 2013 ++++ lib/misc.c Tue Dec 31 21:52:54 2013 @@ -44,7 +44,10 @@ #ifdef HAVE_RESOLV_A #include <arpa/nameser.h> @@ -20,29 +20,28 @@ needed until ns_parse family of function const unsigned char *buf; + int i, n, len, size; +#if defined (__OpenBSD__) -+ char uncomp[MAXDNAME]; -+ int complen = -1; -+ unsigned int qdcount = 0, ancount = 0; -+ -+ const unsigned char *comp = NULL; -+ unsigned char *end = NULL; -+ HEADER *head = NULL; ++ char uncomp[MAXDNAME]; ++ int complen = -1; ++ unsigned int qdcount = 0, ancount = 0; ++ ++ const unsigned char *comp = NULL; ++ unsigned char *end = NULL; ++ HEADER *head = NULL; + -+ int ns_c_in = C_IN, ns_t_srv = T_SRV; -+ int prio = -1, weight = -1, port = -1; ++ int ns_c_in = C_IN, ns_t_srv = T_SRV; ++ int prio = -1, weight = -1, port = -1; +#else ns_msg nsh; ns_rr rr; - int i, n, len, size; +#endif -+ g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain ); if( ( size = res_query( name, ns_c_in, ns_t_srv, querybuf, sizeof( querybuf ) ) ) <= 0 ) return NULL; - -+ n = 0; ++ ++ n = 0; + +#if defined (__OpenBSD__) + head = (HEADER *)querybuf; @@ -100,6 +99,7 @@ needed until ns_parse family of function + ancount--; + } +#else + if( ns_initparse( querybuf, size, &nsh ) != 0 ) return NULL; Index: patches/patch-otr_c =================================================================== RCS file: patches/patch-otr_c diff -N patches/patch-otr_c --- patches/patch-otr_c 15 Aug 2013 16:34:00 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,927 +0,0 @@ -$OpenBSD: patch-otr_c,v 1.1 2013/08/15 16:34:00 stsp Exp $ -http://bugs.bitlbee.org/bitlbee/ticket/1004 ---- otr.c.orig Wed Aug 14 18:26:03 2013 -+++ otr.c Wed Aug 14 18:26:08 2013 -@@ -1,23 +1,25 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * -- * Copyright 2002-2010 Wilmer van der Gaast and others * -+ * Copyright 2002-2012 Wilmer van der Gaast and others * - \********************************************************************/ - - /* - OTR support (cf. http://www.cypherpunks.ca/otr/) - -- (c) 2008-2011 Sven Moritz Hallberg <pe...@khjk.org> -- (c) 2008 funded by stonedcoder.org -+ (c) 2008-2011,2013 Sven Moritz Hallberg <pe...@khjk.org> -+ funded by stonedcoder.org - - files used to store OTR data: - <configdir>/<nick>.otr_keys - <configdir>/<nick>.otr_fprints -+ <configdir>/<nick>.otr_instags <- don't copy this one between hosts - - top-level todos: (search for TODO for more ;-)) - integrate otr_load/otr_save with existing storage backends - per-account policy settings - per-user policy settings -+ add a way to select recipient instance - */ - - /* -@@ -59,9 +61,6 @@ int op_is_logged_in(void *opdata, const char *accountn - void op_inject_message(void *opdata, const char *accountname, const char *protocol, - const char *recipient, const char *message); - --int op_display_otr_message(void *opdata, const char *accountname, const char *protocol, -- const char *username, const char *msg); -- - void op_new_fingerprint(void *opdata, OtrlUserState us, const char *accountname, - const char *protocol, const char *username, unsigned char fingerprint[20]); - -@@ -79,7 +78,21 @@ int op_max_message_size(void *opdata, ConnContext *con - - const char *op_account_name(void *opdata, const char *account, const char *protocol); - -+void op_create_instag(void *opdata, const char *account, const char *protocol); - -+void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ, -+ char **dst, const char *src); -+void op_convert_free(void *opdata, ConnContext *ctx, char *msg); -+ -+void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx, -+ unsigned short percent, char *question); -+ -+void op_handle_msg_event(void *opdata, OtrlMessageEvent ev, ConnContext *ctx, -+ const char *message, gcry_error_t err); -+ -+const char *op_otr_error_message(void *opdata, ConnContext *ctx, -+ OtrlErrorCode err_code); -+ - /** otr sub-command handlers: **/ - - static void cmd_otr(irc_t *irc, char **args); -@@ -140,6 +153,9 @@ void yes_forget_fingerprint(void *data); - void yes_forget_context(void *data); - void yes_forget_key(void *data); - -+/* timeout handler that calls otrl_message_poll */ -+gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond); -+ - /* helper to make sure accountname and protocol match the incoming "opdata" */ - struct im_connection *check_imc(void *opdata, const char *accountname, - const char *protocol); -@@ -155,9 +171,12 @@ int hexval(char a); - returns NULL if not found */ - irc_user_t *peeruser(irc_t *irc, const char *handle, const char *protocol); - --/* handle SMP TLVs from a received message */ --void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs); -+/* show an otr-related message to the user */ -+void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...); - -+/* write an otr-related message to the system log */ -+void log_otr_message(void *opdata, const char *fmt, ...); -+ - /* combined handler for the 'otr smp' and 'otr smpq' commands */ - void otr_smp_or_smpq(irc_t *irc, const char *nick, const char *question, - const char *secret); -@@ -207,21 +226,29 @@ void init_plugin(void) - otr_ops.create_privkey = &op_create_privkey; - otr_ops.is_logged_in = &op_is_logged_in; - otr_ops.inject_message = &op_inject_message; -- otr_ops.notify = NULL; -- otr_ops.display_otr_message = &op_display_otr_message; - otr_ops.update_context_list = NULL; -- otr_ops.protocol_name = NULL; -- otr_ops.protocol_name_free = NULL; - otr_ops.new_fingerprint = &op_new_fingerprint; - otr_ops.write_fingerprints = &op_write_fingerprints; - otr_ops.gone_secure = &op_gone_secure; - otr_ops.gone_insecure = &op_gone_insecure; - otr_ops.still_secure = &op_still_secure; -- otr_ops.log_message = &op_log_message; - otr_ops.max_message_size = &op_max_message_size; - otr_ops.account_name = &op_account_name; - otr_ops.account_name_free = NULL; -- -+ -+ /* stuff added with libotr 4.0.0 */ -+ otr_ops.received_symkey = NULL; /* we don't use the extra key */ -+ otr_ops.otr_error_message = &op_otr_error_message; -+ otr_ops.otr_error_message_free = NULL; -+ otr_ops.resent_msg_prefix = NULL; /* default: [resent] */ -+ otr_ops.resent_msg_prefix_free = NULL; -+ otr_ops.handle_smp_event = &op_handle_smp_event; -+ otr_ops.handle_msg_event = &op_handle_msg_event; -+ otr_ops.create_instag = &op_create_instag; -+ otr_ops.convert_msg = &op_convert_msg; -+ otr_ops.convert_free = &op_convert_free; -+ otr_ops.timer_control = NULL; /* we just poll */ -+ - root_command_add( "otr", 1, cmd_otr, 0 ); - register_irc_plugin( &otr_plugin ); - } -@@ -245,12 +272,17 @@ gboolean otr_irc_new(irc_t *irc) - - s = set_add( &irc->b->set, "otr_does_html", "true", set_eval_bool, irc ); - -+ /* regularly call otrl_message_poll */ -+ gint definterval = otrl_message_poll_get_default_interval(irc->otr->us); -+ irc->otr->timer = b_timeout_add(definterval, ev_message_poll, irc->otr); -+ - return TRUE; - } - - void otr_irc_free(irc_t *irc) - { - otr_t *otr = irc->otr; -+ b_event_remove(otr->timer); - otrl_userstate_free(otr->us); - if(otr->keygen) { - kill(otr->keygen, SIGTERM); -@@ -288,6 +320,11 @@ void otr_load(irc_t *irc) - if(e && e!=enoent) { - irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e)); - } -+ g_snprintf(s, 511, "%s%s.otr_instags", global.conf->configdir, irc->user->nick); -+ e = otrl_instag_read(irc->otr->us, s); -+ if(e && e!=enoent) { -+ irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e)); -+ } - } - - /* check for otr keys on all accounts */ -@@ -385,10 +422,8 @@ char *otr_filter_msg_in(irc_user_t *iu, char *msg, int - - ignore_msg = otrl_message_receiving(irc->otr->us, &otr_ops, ic, - ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg, -- &tlvs, NULL, NULL); -+ &tlvs, NULL, NULL, NULL); - -- otr_handle_smp(ic, iu->bu->handle, tlvs); -- - if(ignore_msg) { - /* this was an internal OTR protocol message */ - return NULL; -@@ -396,57 +431,8 @@ char *otr_filter_msg_in(irc_user_t *iu, char *msg, int - /* this was a non-OTR message */ - return msg; - } else { -- /* OTR has processed this message */ -- ConnContext *context = otrl_context_find(irc->otr->us, iu->bu->handle, -- ic->acc->user, ic->acc->prpl->name, 0, NULL, NULL, NULL); -- - /* we're done with the original msg, which will be caller-freed. */ -- /* NB: must not change the newmsg pointer, since we free it. */ -- msg = newmsg; -- -- if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { -- /* HTML decoding */ -- /* perform any necessary stripping that the top level would miss */ -- if(set_getbool(&ic->bee->set, "otr_does_html") && -- !(ic->flags & OPT_DOES_HTML) && -- set_getbool(&ic->bee->set, "strip_html")) { -- strip_html(msg); -- } -- -- /* coloring */ -- if(set_getbool(&ic->bee->set, "otr_color_encrypted")) { -- int color; /* color according to f'print trust */ -- char *pre="", *sep=""; /* optional parts */ -- const char *trust = context->active_fingerprint->trust; -- -- if(trust && trust[0] != '\0') -- color=3; /* green */ -- else -- color=5; /* red */ -- -- /* in a query window, keep "/me " uncolored at the beginning */ -- if(g_strncasecmp(msg, "/me ", 4) == 0 -- && irc_user_msgdest(iu) == irc->user->nick) { -- msg += 4; /* skip */ -- pre = "/me "; -- } -- -- /* comma in first place could mess with the color code */ -- if(msg[0] == ',') { -- /* insert a space between color spec and message */ -- sep = " "; -- } -- -- msg = g_strdup_printf("%s\x03%.2d%s%s\x0F", pre, -- color, sep, msg); -- } -- } -- -- if(msg == newmsg) { -- msg = g_strdup(newmsg); -- } -- otrl_message_free(newmsg); -- return msg; -+ return newmsg; - } - } - -@@ -458,50 +444,27 @@ char *otr_filter_msg_out(irc_user_t *iu, char *msg, in - ConnContext *ctx = NULL; - irc_t *irc = iu->irc; - struct im_connection *ic = iu->bu->ic; -+ otrl_instag_t instag = OTRL_INSTAG_RECENT; // XXX? - - /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ - if(ic->acc->prpl->options & OPT_NOOTR) { - return msg; - } - -- ctx = otrl_context_find(irc->otr->us, -- iu->bu->handle, ic->acc->user, ic->acc->prpl->name, -- 1, NULL, NULL, NULL); -- -- /* HTML encoding */ -- /* consider OTR plaintext to be HTML if otr_does_html is set */ -- if(ctx && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED && -- set_getbool(&ic->bee->set, "otr_does_html") && -- (g_strncasecmp(msg, "<html>", 6) != 0)) { -- emsg = escape_html(msg); -- } -- - st = otrl_message_sending(irc->otr->us, &otr_ops, ic, -- ic->acc->user, ic->acc->prpl->name, iu->bu->handle, -- emsg, NULL, &otrmsg, NULL, NULL); -+ ic->acc->user, ic->acc->prpl->name, iu->bu->handle, instag, -+ emsg, NULL, &otrmsg, OTRL_FRAGMENT_SEND_ALL, &ctx, NULL, NULL); -+ /* in libotr 4.0.0 with OTRL_FRAGMENT_SEND_ALL, otrmsg must be passed -+ * but the value it gets carries no meaning. it can be set even though -+ * the message has been injected. */ -+ - if(emsg != msg) { - g_free(emsg); /* we're done with this one */ - } - if(st) { -- return NULL; -+ /* TODO: Error reporting? */ - } -- -- if(otrmsg) { -- if(!ctx) { -- otrl_message_free(otrmsg); -- return NULL; -- } -- st = otrl_message_fragment_and_send(&otr_ops, ic, ctx, -- otrmsg, OTRL_FRAGMENT_SEND_ALL, NULL); -- otrl_message_free(otrmsg); -- } else { -- /* note: otrl_message_sending handles policy, so that if REQUIRE_ENCRYPTION is set, -- this case does not occur */ -- return msg; -- } - -- /* TODO: Error reporting should be done here now (if st!=0), probably. */ -- - return NULL; - } - -@@ -619,26 +582,6 @@ void op_inject_message(void *opdata, const char *accou - } - } - --int op_display_otr_message(void *opdata, const char *accountname, -- const char *protocol, const char *username, const char *message) --{ -- struct im_connection *ic = check_imc(opdata, accountname, protocol); -- char *msg = g_strdup(message); -- irc_t *irc = ic->bee->ui_data; -- irc_user_t *u = peeruser(irc, username, protocol); -- -- strip_html(msg); -- if(u) { -- /* display as a notice from this particular user */ -- irc_usernotice(u, "%s", msg); -- } else { -- irc_rootmsg(irc, "[otr] %s", msg); -- } -- -- g_free(msg); -- return 0; --} -- - void op_new_fingerprint(void *opdata, OtrlUserState us, - const char *accountname, const char *protocol, - const char *username, unsigned char fingerprint[20]) -@@ -690,6 +633,9 @@ void op_gone_secure(void *opdata, ConnContext *context - - void op_gone_insecure(void *opdata, ConnContext *context) - { -+ /* XXX on 'otr disconnect', this gets called for every instance and we -+ * get the message multiple times... */ -+ - struct im_connection *ic = - check_imc(opdata, context->accountname, context->protocol); - irc_t *irc = ic->bee->ui_data; -@@ -729,20 +675,11 @@ void op_still_secure(void *opdata, ConnContext *contex - } - } - --void op_log_message(void *opdata, const char *message) --{ -- char *msg = g_strdup(message); -- -- strip_html(msg); -- log_message(LOGLVL_INFO, "otr: %s", msg); -- g_free(msg); --} -- - int op_max_message_size(void *opdata, ConnContext *context) - { - struct im_connection *ic = - check_imc(opdata, context->accountname, context->protocol); -- -+ - return ic->acc->prpl->mms; - } - -@@ -754,7 +691,247 @@ const char *op_account_name(void *opdata, const char * - return peernick(irc, account, protocol); - } - -+void op_create_instag(void *opdata, const char *account, const char *protocol) -+{ -+ struct im_connection *ic = -+ check_imc(opdata, account, protocol); -+ irc_t *irc = ic->bee->ui_data; -+ gcry_error_t e; -+ char s[512]; -+ -+ g_snprintf(s, 511, "%s%s.otr_instags", global.conf->configdir, -+ irc->user->nick); -+ e = otrl_instag_generate(irc->otr->us, s, account, protocol); -+ if(e) { -+ irc_rootmsg(irc, "otr: %s/%s: otrl_instag_generate failed: %s", -+ account, protocol, gcry_strerror(e)); -+ } -+} - -+void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ, -+ char **dst, const char *src) -+{ -+ struct im_connection *ic = -+ check_imc(opdata, ctx->accountname, ctx->protocol); -+ irc_t *irc = ic->bee->ui_data; -+ irc_user_t *iu = peeruser(irc, ctx->username, ctx->protocol); -+ -+ if(typ == OTRL_CONVERT_RECEIVING) { -+ char *msg = g_strdup(src); -+ -+ /* HTML decoding */ -+ if(set_getbool(&ic->bee->set, "otr_does_html") && -+ !(ic->flags & OPT_DOES_HTML) && -+ set_getbool(&ic->bee->set, "strip_html")) { -+ strip_html(msg); -+ *dst = msg; -+ } -+ -+ /* coloring */ -+ if(set_getbool(&ic->bee->set, "otr_color_encrypted")) { -+ int color; /* color according to f'print trust */ -+ char *pre="", *sep=""; /* optional parts */ -+ const char *trust = ctx->active_fingerprint->trust; -+ -+ if(trust && trust[0] != '\0') -+ color=3; /* green */ -+ else -+ color=5; /* red */ -+ -+ /* in a query window, keep "/me " uncolored at the beginning */ -+ if(g_strncasecmp(msg, "/me ", 4) == 0 -+ && irc_user_msgdest(iu) == irc->user->nick) { -+ msg += 4; /* skip */ -+ pre = "/me "; -+ } -+ -+ /* comma in first place could mess with the color code */ -+ if(msg[0] == ',') { -+ /* insert a space between color spec and message */ -+ sep = " "; -+ } -+ -+ *dst = g_strdup_printf("%s\x03%.2d%s%s\x0F", pre, -+ color, sep, msg); -+ g_free(msg); -+ } -+ } else { -+ /* HTML encoding */ -+ /* consider OTR plaintext to be HTML if otr_does_html is set */ -+ if(ctx && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED && -+ set_getbool(&ic->bee->set, "otr_does_html") && -+ (g_strncasecmp(src, "<html>", 6) != 0)) { -+ *dst = escape_html(src); -+ } -+ } -+} -+ -+void op_convert_free(void *opdata, ConnContext *ctx, char *msg) -+{ -+ g_free(msg); -+} -+ -+/* Socialist Millionaires' Protocol */ -+void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx, -+ unsigned short percent, char *question) -+{ -+ struct im_connection *ic = -+ check_imc(opdata, ctx->accountname, ctx->protocol); -+ irc_t *irc = ic->bee->ui_data; -+ OtrlUserState us = irc->otr->us; -+ irc_user_t *u = peeruser(irc, ctx->username, ctx->protocol); -+ -+ if(!u) return; -+ -+ switch(ev) { -+ case OTRL_SMPEVENT_ASK_FOR_SECRET: -+ irc_rootmsg(irc, "smp: initiated by %s" -+ " - respond with \x02otr smp %s <secret>\x02", -+ u->nick, u->nick); -+ break; -+ case OTRL_SMPEVENT_ASK_FOR_ANSWER: -+ irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick, -+ question); -+ irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02", -+ u->nick); -+ break; -+ case OTRL_SMPEVENT_CHEATED: -+ irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting", -+ u->nick); -+ otrl_message_abort_smp(us, &otr_ops, u->bu->ic, ctx); -+ otrl_sm_state_free(ctx->smstate); -+ break; -+ case OTRL_SMPEVENT_NONE: -+ break; -+ case OTRL_SMPEVENT_IN_PROGRESS: -+ break; -+ case OTRL_SMPEVENT_SUCCESS: -+ if(ctx->smstate->received_question) { -+ irc_rootmsg(irc, "smp %s: correct answer, you are trusted", -+ u->nick); -+ } else { -+ irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted", -+ u->nick); -+ } -+ otrl_sm_state_free(ctx->smstate); -+ break; -+ case OTRL_SMPEVENT_FAILURE: -+ if(ctx->smstate->received_question) { -+ irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted", -+ u->nick); -+ } else { -+ irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted", -+ u->nick); -+ } -+ otrl_sm_state_free(ctx->smstate); -+ break; -+ case OTRL_SMPEVENT_ABORT: -+ irc_rootmsg(irc, "smp: received abort from %s", u->nick); -+ otrl_sm_state_free(ctx->smstate); -+ break; -+ case OTRL_SMPEVENT_ERROR: -+ irc_rootmsg(irc, "smp %s: protocol error, aborting", -+ u->nick); -+ otrl_message_abort_smp(us, &otr_ops, u->bu->ic, ctx); -+ otrl_sm_state_free(ctx->smstate); -+ break; -+ } -+} -+ -+void op_handle_msg_event(void *opdata, OtrlMessageEvent ev, ConnContext *ctx, -+ const char *message, gcry_error_t err) -+{ -+ switch(ev) { -+ case OTRL_MSGEVENT_ENCRYPTION_REQUIRED: -+ display_otr_message(opdata, ctx, -+ "policy requires encryption - message not sent"); -+ break; -+ case OTRL_MSGEVENT_ENCRYPTION_ERROR: -+ display_otr_message(opdata, ctx, -+ "error during encryption - message not sent"); -+ break; -+ case OTRL_MSGEVENT_CONNECTION_ENDED: -+ display_otr_message(opdata, ctx, -+ "other end has disconnected OTR - " -+ "close connection or reconnect!"); -+ break; -+ case OTRL_MSGEVENT_SETUP_ERROR: -+ display_otr_message(opdata, ctx, -+ "OTR connection failed: %s", gcry_strerror(err)); -+ break; -+ case OTRL_MSGEVENT_MSG_REFLECTED: -+ display_otr_message(opdata, ctx, -+ "received our own OTR message (!?)"); -+ break; -+ case OTRL_MSGEVENT_MSG_RESENT: -+ display_otr_message(opdata, ctx, -+ "the previous message was resent"); -+ break; -+ case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE: -+ display_otr_message(opdata, ctx, -+ "unexpected encrypted message received"); -+ break; -+ case OTRL_MSGEVENT_RCVDMSG_UNREADABLE: -+ display_otr_message(opdata, ctx, -+ "unreadable encrypted message received"); -+ break; -+ case OTRL_MSGEVENT_RCVDMSG_MALFORMED: -+ display_otr_message(opdata, ctx, -+ "malformed OTR message received"); -+ break; -+ case OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD: -+ if(global.conf->verbose) { -+ log_otr_message(opdata, "%s/%s: heartbeat received", -+ ctx->accountname, ctx->protocol); -+ } -+ break; -+ case OTRL_MSGEVENT_LOG_HEARTBEAT_SENT: -+ if(global.conf->verbose) { -+ log_otr_message(opdata, "%s/%s: heartbeat sent", -+ ctx->accountname, ctx->protocol); -+ } -+ break; -+ case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR: -+ display_otr_message(opdata, ctx, -+ "OTR error message received: %s", message); -+ break; -+ case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED: -+ display_otr_message(opdata, ctx, -+ "unencrypted message received: %s", message); -+ break; -+ case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED: -+ display_otr_message(opdata, ctx, -+ "unrecognized OTR message received"); -+ break; -+ case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE: -+ display_otr_message(opdata, ctx, -+ "OTR message for a different instance received"); -+ break; -+ default: -+ /* shouldn't happen */ -+ break; -+ } -+} -+ -+const char *op_otr_error_message(void *opdata, ConnContext *ctx, -+ OtrlErrorCode err_code) -+{ -+ switch(err_code) { -+ case OTRL_ERRCODE_ENCRYPTION_ERROR: -+ return "i failed to encrypt a message"; -+ case OTRL_ERRCODE_MSG_NOT_IN_PRIVATE: -+ return "you sent an encrypted message i didn't expect"; -+ case OTRL_ERRCODE_MSG_UNREADABLE: -+ return "could not read encrypted message"; -+ case OTRL_ERRCODE_MSG_MALFORMED: -+ return "you sent a malformed OTR message"; -+ default: -+ return "i suffered an unexpected OTR error"; -+ } -+} -+ -+ -+ - /*** OTR sub-command handlers ***/ - - void cmd_otr_reconnect(irc_t *irc, char **args) -@@ -773,19 +950,24 @@ void cmd_otr_disconnect(irc_t *irc, char **args) - return; - } - -- otrl_message_disconnect(irc->otr->us, &otr_ops, -+ /* XXX we disconnect all instances; is that what we want? */ -+ otrl_message_disconnect_all_instances(irc->otr->us, &otr_ops, - u->bu->ic, u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, u->bu->handle); - -- /* for some reason, libotr (3.1.0) doesn't do this itself: */ -- if(u->flags & IRC_USER_OTR_ENCRYPTED) { -- ConnContext *ctx; -- ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, -- u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); -- if(ctx) -- op_gone_insecure(u->bu->ic, ctx); -- else /* huh? */ -- u->flags &= ( IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED ); -+ /* for some reason, libotr (4.0.0) doesn't do this itself: */ -+ if(!(u->flags & IRC_USER_OTR_ENCRYPTED)) -+ return; -+ -+ ConnContext *ctx, *p; -+ ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, -+ u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); -+ if(!ctx) { /* huh? */ -+ u->flags &= ( IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED ); -+ return; - } -+ -+ for(p=ctx; p && p->m_context == ctx->m_context; p=p->next) -+ op_gone_insecure(u->bu->ic, p); - } - - void cmd_otr_connect(irc_t *irc, char **args) -@@ -802,7 +984,9 @@ void cmd_otr_connect(irc_t *irc, char **args) - return; - } - -- bee_user_msg(irc->b, u->bu, "?OTR?v2?", 0); -+ /* passing this through the filter so it goes through libotr which -+ * will replace the simple query string with a proper one */ -+ otr_filter_msg_out(u, "?OTR?", 0); - } - - void cmd_otr_smp(irc_t *irc, char **args) -@@ -830,7 +1014,7 @@ void cmd_otr_trust(irc_t *irc, char **args) - } - - ctx = otrl_context_find(irc->otr->us, u->bu->handle, -- u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); -+ u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); - if(!ctx) { - irc_rootmsg(irc, "%s: no otr context with user", args[1]); - return; -@@ -894,7 +1078,7 @@ void cmd_otr_info(irc_t *irc, char **args) - if(protocol && myhandle) { - *(myhandle++) = '\0'; - handle = arg; -- ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, 0, NULL, NULL, NULL); -+ ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); - if(!ctx) { - irc_rootmsg(irc, "no such context"); - g_free(arg); -@@ -908,7 +1092,7 @@ void cmd_otr_info(irc_t *irc, char **args) - return; - } - ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, -- u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); -+ u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); - if(!ctx) { - irc_rootmsg(irc, "no otr context with %s", args[1]); - g_free(arg); -@@ -981,6 +1165,8 @@ void yes_forget_context(void *data) - ConnContext *ctx = (ConnContext *)p->snd; - - g_free(p); -+ -+ // XXX forget all contexts - - if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) { - irc_rootmsg(irc, "active otr connection with %s, terminate it first", -@@ -1027,7 +1213,7 @@ void cmd_otr_forget(irc_t *irc, char **args) - } - - ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, -- u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); -+ u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); - if(!ctx) { - irc_rootmsg(irc, "no otr context with %s", args[2]); - return; -@@ -1070,7 +1256,7 @@ void cmd_otr_forget(irc_t *irc, char **args) - } - - ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, -- u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); -+ u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); - if(!ctx) { - irc_rootmsg(irc, "no otr context with %s", args[2]); - return; -@@ -1118,133 +1304,37 @@ void cmd_otr_forget(irc_t *irc, char **args) - - /*** local helpers / subroutines: ***/ - --/* Socialist Millionaires' Protocol */ --void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs) -+void log_otr_message(void *opdata, const char *fmt, ...) - { -+ va_list va; -+ -+ va_start(va, fmt); -+ char *msg = g_strdup_vprintf(fmt, va); -+ va_end(va); -+ -+ log_message(LOGLVL_INFO, "otr: %s", msg); -+} -+ -+void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...) -+{ -+ struct im_connection *ic = -+ check_imc(opdata, ctx->accountname, ctx->protocol); - irc_t *irc = ic->bee->ui_data; -- OtrlUserState us = irc->otr->us; -- OtrlMessageAppOps *ops = &otr_ops; -- OtrlTLV *tlv = NULL; -- ConnContext *context; -- NextExpectedSMP nextMsg; -- irc_user_t *u; -- bee_user_t *bu; -+ irc_user_t *u = peeruser(irc, ctx->username, ctx->protocol); -+ va_list va; - -- bu = bee_user_by_handle(ic->bee, ic, handle); -- if(!bu || !(u = bu->ui_data)) return; -- context = otrl_context_find(us, handle, -- ic->acc->user, ic->acc->prpl->name, 1, NULL, NULL, NULL); -- if(!context) { -- /* huh? out of memory or what? */ -- irc_rootmsg(irc, "smp: failed to get otr context for %s", u->nick); -- otrl_message_abort_smp(us, ops, u->bu->ic, context); -- otrl_sm_state_free(context->smstate); -- return; -- } -- nextMsg = context->smstate->nextExpected; -+ va_start(va, fmt); -+ char *msg = g_strdup_vprintf(fmt, va); -+ va_end(va); - -- if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED) { -- irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting", -- u->nick); -- otrl_message_abort_smp(us, ops, u->bu->ic, context); -- otrl_sm_state_free(context->smstate); -- return; -+ if(u) { -+ /* display as a notice from this particular user */ -+ irc_usernotice(u, "%s", msg); -+ } else { -+ irc_rootmsg(irc, "[otr] %s", msg); - } - -- tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q); -- if (tlv) { -- if (nextMsg != OTRL_SMP_EXPECT1) { -- irc_rootmsg(irc, "smp %s: spurious SMP1Q received, aborting", u->nick); -- otrl_message_abort_smp(us, ops, u->bu->ic, context); -- otrl_sm_state_free(context->smstate); -- } else { -- char *question = g_strndup((char *)tlv->data, tlv->len); -- irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick, -- question); -- irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02", -- u->nick); -- g_free(question); -- /* smp stays in EXPECT1 until user responds */ -- } -- } -- tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1); -- if (tlv) { -- if (nextMsg != OTRL_SMP_EXPECT1) { -- irc_rootmsg(irc, "smp %s: spurious SMP1 received, aborting", u->nick); -- otrl_message_abort_smp(us, ops, u->bu->ic, context); -- otrl_sm_state_free(context->smstate); -- } else { -- irc_rootmsg(irc, "smp: initiated by %s" -- " - respond with \x02otr smp %s <secret>\x02", -- u->nick, u->nick); -- /* smp stays in EXPECT1 until user responds */ -- } -- } -- tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2); -- if (tlv) { -- if (nextMsg != OTRL_SMP_EXPECT2) { -- irc_rootmsg(irc, "smp %s: spurious SMP2 received, aborting", u->nick); -- otrl_message_abort_smp(us, ops, u->bu->ic, context); -- otrl_sm_state_free(context->smstate); -- } else { -- /* SMP2 received, otrl_message_receiving will have sent SMP3 */ -- context->smstate->nextExpected = OTRL_SMP_EXPECT4; -- } -- } -- tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3); -- if (tlv) { -- if (nextMsg != OTRL_SMP_EXPECT3) { -- irc_rootmsg(irc, "smp %s: spurious SMP3 received, aborting", u->nick); -- otrl_message_abort_smp(us, ops, u->bu->ic, context); -- otrl_sm_state_free(context->smstate); -- } else { -- /* SMP3 received, otrl_message_receiving will have sent SMP4 */ -- if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) { -- if(context->smstate->received_question) { -- irc_rootmsg(irc, "smp %s: correct answer, you are trusted", -- u->nick); -- } else { -- irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted", -- u->nick); -- } -- } else { -- if(context->smstate->received_question) { -- irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted", -- u->nick); -- } else { -- irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted", -- u->nick); -- } -- } -- otrl_sm_state_free(context->smstate); -- /* smp is in back in EXPECT1 */ -- } -- } -- tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4); -- if (tlv) { -- if (nextMsg != OTRL_SMP_EXPECT4) { -- irc_rootmsg(irc, "smp %s: spurious SMP4 received, aborting", u->nick); -- otrl_message_abort_smp(us, ops, u->bu->ic, context); -- otrl_sm_state_free(context->smstate); -- } else { -- /* SMP4 received, otrl_message_receiving will have set fp trust */ -- if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) { -- irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted", -- u->nick); -- } else { -- irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted", -- u->nick); -- } -- otrl_sm_state_free(context->smstate); -- /* smp is in back in EXPECT1 */ -- } -- } -- tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT); -- if (tlv) { -- irc_rootmsg(irc, "smp: received abort from %s", u->nick); -- otrl_sm_state_free(context->smstate); -- /* smp is in back in EXPECT1 */ -- } -+ g_free(msg); - } - - /* combined handler for the 'otr smp' and 'otr smpq' commands */ -@@ -1253,6 +1343,7 @@ void otr_smp_or_smpq(irc_t *irc, const char *nick, con - { - irc_user_t *u; - ConnContext *ctx; -+ otrl_instag_t instag = OTRL_INSTAG_RECENT; // XXX - - u = irc_user_by_name(irc, nick); - if(!u || !u->bu || !u->bu->ic) { -@@ -1265,7 +1356,7 @@ void otr_smp_or_smpq(irc_t *irc, const char *nick, con - } - - ctx = otrl_context_find(irc->otr->us, u->bu->handle, -- u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); -+ u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, instag, 0, NULL, NULL, NULL); - if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) { - irc_rootmsg(irc, "smp: otr inactive with %s, try \x02otr connect" - " %s\x02", nick, nick); -@@ -1306,6 +1397,17 @@ void otr_smp_or_smpq(irc_t *irc, const char *nick, con - } - } - -+/* timeout handler that calls otrl_message_poll */ -+gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond) -+{ -+ otr_t *otr = data; -+ -+ if(otr && otr->us) -+ otrl_message_poll(otr->us, &otr_ops, NULL); -+ -+ return TRUE; /* cycle timer */ -+} -+ - /* helper to assert that account and protocol names given to ops below always - match the im_connection passed through as opdata */ - struct im_connection *check_imc(void *opdata, const char *accountname, -@@ -1313,6 +1415,21 @@ struct im_connection *check_imc(void *opdata, const ch - { - struct im_connection *ic = (struct im_connection *)opdata; - -+ /* libotr 4.0.0 has a bug where it doesn't set opdata, so we catch -+ * that and try to find the desired connection in the global list. */ -+ if(!ic) { -+ GSList *l; -+ for(l=get_connections(); l; l=l->next) { -+ ic = l->data; -+ if(strcmp(accountname, ic->acc->user) == 0 && -+ strcmp(protocol, ic->acc->prpl->name) == 0) -+ break; -+ } -+ assert(l != NULL); /* a match should always be found */ -+ if(!l) -+ return NULL; -+ } -+ - if (strcmp(accountname, ic->acc->user) != 0) { - log_message(LOGLVL_WARNING, - "otr: internal account name mismatch: '%s' vs '%s'", -@@ -1593,6 +1710,8 @@ void show_general_otr_info(irc_t *irc) - irc_rootmsg(irc, " (none)"); - - /* list all contexts */ -+ /* XXX remove this, or split off as its own command */ -+ /* XXX show instags? */ - irc_rootmsg(irc, "%s", ""); - irc_rootmsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)"); - for(ctx=irc->otr->us->context_root; ctx; ctx=ctx->next) {\ -@@ -1621,6 +1740,8 @@ void show_general_otr_info(irc_t *irc) - - void show_otr_context_info(irc_t *irc, ConnContext *ctx) - { -+ // XXX show all instags/subcontexts -+ - switch(ctx->otr_offer) { - case OFFER_NOT: - irc_rootmsg(irc, " otr offer status: none sent"); Index: patches/patch-otr_h =================================================================== RCS file: patches/patch-otr_h diff -N patches/patch-otr_h --- patches/patch-otr_h 15 Aug 2013 16:34:00 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,25 +0,0 @@ -$OpenBSD: patch-otr_h,v 1.1 2013/08/15 16:34:00 stsp Exp $ -http://bugs.bitlbee.org/bitlbee/ticket/1004 ---- otr.h.orig Wed Aug 14 18:26:06 2013 -+++ otr.h Wed Aug 14 18:26:10 2013 -@@ -7,8 +7,8 @@ - /* - OTR support (cf. http://www.cypherpunks.ca/otr/) - -- 2008, Sven Moritz Hallberg <pe...@khjk.org> -- (c) and funded by stonedcoder.org -+ (c) 2008,2013 Sven Moritz Hallberg <pe...@khjk.org> -+ funded by stonedcoder.org - */ - - /* -@@ -65,6 +65,9 @@ typedef struct otr { - - /* keygen jobs waiting to be sent to slave */ - kg_t *todo; -+ -+ /* event timer for otrl_message_poll */ -+ gint timer; - } otr_t; - - /* called from main() */