Patch by Robert Scheck <robert@fedoraproject.org> for bitlbee >= 3.2.2 which just re-adds the support for libotr < 4.0.0 again - but this time conditionally (based on the previous implementation in bitlbee). This patch has been also proposed to upstream, see http://bugs.bitlbee.org/bitlbee/ticket/1163 for details. --- bitlbee-3.2.2/otr.c 2014-07-05 23:40:53.000000000 +0200 +++ bitlbee-3.2.2/otr.c.libotr-3-4 2014-07-06 16:50:44.000000000 +0200 @@ -58,6 +58,11 @@ int op_is_logged_in(void *opdata, const char *accountname, const char *protocol, const char *recipient); +#if OTRL_VERSION_MAJOR < 4 +int op_display_otr_message(void *opdata, const char *accountname, const char *protocol, + const char *username, const char *msg); +#endif + void op_inject_message(void *opdata, const char *accountname, const char *protocol, const char *recipient, const char *message); @@ -78,6 +83,7 @@ const char *op_account_name(void *opdata, const char *account, const char *protocol); +#if OTRL_VERSION_MAJOR >= 4 void op_create_instag(void *opdata, const char *account, const char *protocol); void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ, @@ -92,6 +98,7 @@ const char *op_otr_error_message(void *opdata, ConnContext *ctx, OtrlErrorCode err_code); +#endif /** otr sub-command handlers: **/ @@ -153,8 +160,10 @@ void yes_forget_context(void *data); void yes_forget_key(void *data); +#if OTRL_VERSION_MAJOR >= 4 /* timeout handler that calls otrl_message_poll */ gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond); +#endif /* helper to make sure accountname and protocol match the incoming "opdata" */ struct im_connection *check_imc(void *opdata, const char *accountname, @@ -171,11 +180,16 @@ returns NULL if not found */ irc_user_t *peeruser(irc_t *irc, const char *handle, const char *protocol); +#if OTRL_VERSION_MAJOR >= 4 /* 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, ...); +#else +/* handle SMP TLVs from a received message */ +void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs); +#endif /* combined handler for the 'otr smp' and 'otr smpq' commands */ void otr_smp_or_smpq(irc_t *irc, const char *nick, const char *question, @@ -207,11 +221,13 @@ /* check whether a string is safe to use in a path component */ int strsane(const char *s); +#if OTRL_VERSION_MAJOR >= 4 /* close the OTR connection with the given buddy */ gboolean otr_disconnect_user(irc_t *irc, irc_user_t *u); /* close all active OTR connections */ void otr_disconnect_all(irc_t *irc); +#endif /* functions to be called for certain events */ static const struct irc_plugin otr_plugin; @@ -241,6 +257,7 @@ otr_ops.account_name = &op_account_name; otr_ops.account_name_free = NULL; +#if OTRL_VERSION_MAJOR >= 4 /* 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; @@ -253,6 +270,13 @@ otr_ops.convert_msg = &op_convert_msg; otr_ops.convert_free = &op_convert_free; otr_ops.timer_control = NULL; /* we just poll */ +#else + otr_ops.notify = NULL; + otr_ops.display_otr_message = &op_display_otr_message; + otr_ops.protocol_name = NULL; + otr_ops.protocol_name_free = NULL; + otr_ops.log_message = &op_log_message; +#endif root_command_add( "otr", 1, cmd_otr, 0 ); register_irc_plugin( &otr_plugin ); @@ -277,9 +301,12 @@ s = set_add( &irc->b->set, "otr_does_html", "true", set_eval_bool, irc ); + +#if OTRL_VERSION_MAJOR >= 4 /* 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); +#endif return TRUE; } @@ -287,8 +314,10 @@ void otr_irc_free(irc_t *irc) { otr_t *otr = irc->otr; +#if OTRL_VERSION_MAJOR >= 4 otr_disconnect_all(irc); b_event_remove(otr->timer); +#endif otrl_userstate_free(otr->us); if(otr->keygen) { kill(otr->keygen, SIGTERM); @@ -326,11 +355,13 @@ if(e && e!=enoent) { irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e)); } +#if OTRL_VERSION_MAJOR >= 4 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)); } +#endif } /* check for otr keys on all accounts */ @@ -428,7 +459,13 @@ ignore_msg = otrl_message_receiving(irc->otr->us, &otr_ops, ic, ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg, +#if OTRL_VERSION_MAJOR >= 4 &tlvs, NULL, NULL, NULL); +#else + &tlvs, NULL, NULL); + + otr_handle_smp(ic, iu->bu->handle, tlvs); +#endif if(ignore_msg) { /* this was an internal OTR protocol message */ @@ -437,8 +474,62 @@ /* this was a non-OTR message */ return msg; } else { +#if OTRL_VERSION_MAJOR >= 4 /* we're done with the original msg, which will be caller-freed. */ return newmsg; +#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; +#endif } } @@ -446,19 +537,25 @@ { int st; char *otrmsg = NULL; +#if OTRL_VERSION_MAJOR < 4 + char *emsg = msg; /* the message as we hand it to libotr */ +#endif ConnContext *ctx = NULL; irc_t *irc = iu->irc; struct im_connection *ic = iu->bu->ic; +#if OTRL_VERSION_MAJOR >= 4 otrl_instag_t instag = OTRL_INSTAG_BEST; // XXX? /* NB: in libotr 4.0.0 OTRL_INSTAG_RECENT will cause a null-pointer deref * in otrl_message_sending with newly-added OTR contexts. */ +#endif /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ if(ic->acc->prpl->options & OPT_NOOTR) { return msg; } +#if OTRL_VERSION_MAJOR >= 4 st = otrl_message_sending(irc->otr->us, &otr_ops, ic, ic->acc->user, ic->acc->prpl->name, iu->bu->handle, instag, msg, NULL, &otrmsg, OTRL_FRAGMENT_SEND_ALL_BUT_LAST, &ctx, NULL, NULL); @@ -476,6 +573,47 @@ } return msg; +#else + 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); + if(emsg != msg) { + g_free(emsg); /* we're done with this one */ + } + if(st) { + return NULL; + } + + 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; +#endif } static const struct irc_plugin otr_plugin = @@ -592,6 +730,28 @@ } } +#if OTRL_VERSION_MAJOR < 4 +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; +} +#endif + void op_new_fingerprint(void *opdata, OtrlUserState us, const char *accountname, const char *protocol, const char *username, unsigned char fingerprint[20]) @@ -682,6 +842,17 @@ } } +#if OTRL_VERSION_MAJOR < 4 +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); +} +#endif + int op_max_message_size(void *opdata, ConnContext *context) { struct im_connection *ic = @@ -698,6 +869,7 @@ return peernick(irc, account, protocol); } +#if OTRL_VERSION_MAJOR >= 4 void op_create_instag(void *opdata, const char *account, const char *protocol) { struct im_connection *ic = @@ -937,6 +1109,7 @@ return "i suffered an unexpected OTR error"; } } +#endif @@ -952,6 +1125,7 @@ { irc_user_t *u; +#if OTRL_VERSION_MAJOR >= 4 if(!strcmp("*", args[1])) { otr_disconnect_all(irc); irc_rootmsg(irc, "all conversations are now in cleartext"); @@ -962,12 +1136,35 @@ else irc_rootmsg(irc, "%s: unknown user", args[1]); } +#else + u = irc_user_by_name(irc, args[1]); + if(!u || !u->bu || !u->bu->ic) { + irc_rootmsg(irc, "%s: unknown user", args[1]); + return; + } + + otrl_message_disconnect(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 ); + } +#endif } void cmd_otr_connect(irc_t *irc, char **args) { irc_user_t *u; +#if OTRL_VERSION_MAJOR >= 4 char *msg, *query = "?OTR?"; +#endif u = irc_user_by_name(irc, args[1]); if(!u || !u->bu || !u->bu->ic) { @@ -979,6 +1176,7 @@ return; } +#if OTRL_VERSION_MAJOR >= 4 /* passing this through the filter so it goes through libotr which * will replace the simple query string with a proper one */ msg = otr_filter_msg_out(u, query, 0); @@ -991,6 +1189,9 @@ if(msg != query) g_free(msg); } +#else + bee_user_msg(irc->b, u->bu, "?OTR?v2?", 0); +#endif } void cmd_otr_smp(irc_t *irc, char **args) @@ -1018,7 +1219,11 @@ } ctx = otrl_context_find(irc->otr->us, u->bu->handle, +#if OTRL_VERSION_MAJOR >= 4 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); +#else + u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); +#endif if(!ctx) { irc_rootmsg(irc, "%s: no otr context with user", args[1]); return; @@ -1082,7 +1287,11 @@ if(protocol && myhandle) { *(myhandle++) = '\0'; handle = arg; +#if OTRL_VERSION_MAJOR >= 4 ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); +#else + ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, 0, NULL, NULL, NULL); +#endif if(!ctx) { irc_rootmsg(irc, "no such context"); g_free(arg); @@ -1096,7 +1305,11 @@ return; } ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, +#if OTRL_VERSION_MAJOR >= 4 u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); +#else + u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); +#endif if(!ctx) { irc_rootmsg(irc, "no otr context with %s", args[1]); g_free(arg); @@ -1217,7 +1430,11 @@ } ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, +#if OTRL_VERSION_MAJOR >= 4 u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); +#else + u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); +#endif if(!ctx) { irc_rootmsg(irc, "no otr context with %s", args[2]); return; @@ -1260,7 +1477,11 @@ } ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, +#if OTRL_VERSION_MAJOR >= 4 u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); +#else + u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); +#endif if(!ctx) { irc_rootmsg(irc, "no otr context with %s", args[2]); return; @@ -1308,6 +1529,136 @@ /*** local helpers / subroutines: ***/ +#if OTRL_VERSION_MAJOR < 4 +/* Socialist Millionaires' Protocol */ +void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs) +{ + 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; + + 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; + + 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; + } + + 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 */ + } +} +#else void log_otr_message(void *opdata, const char *fmt, ...) { va_list va; @@ -1340,6 +1691,7 @@ g_free(msg); } +#endif /* combined handler for the 'otr smp' and 'otr smpq' commands */ void otr_smp_or_smpq(irc_t *irc, const char *nick, const char *question, @@ -1347,7 +1699,9 @@ { irc_user_t *u; ConnContext *ctx; +#if OTRL_VERSION_MAJOR >= 4 otrl_instag_t instag = OTRL_INSTAG_BEST; // XXX +#endif u = irc_user_by_name(irc, nick); if(!u || !u->bu || !u->bu->ic) { @@ -1360,7 +1714,11 @@ } ctx = otrl_context_find(irc->otr->us, u->bu->handle, +#if OTRL_VERSION_MAJOR >= 4 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, instag, 0, NULL, NULL, NULL); +#else + u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); +#endif if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) { irc_rootmsg(irc, "smp: otr inactive with %s, try \x02otr connect" " %s\x02", nick, nick); @@ -1401,6 +1759,7 @@ } } +#if OTRL_VERSION_MAJOR >= 4 /* timeout handler that calls otrl_message_poll */ gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond) { @@ -1411,6 +1770,7 @@ return TRUE; /* cycle timer */ } +#endif /* helper to assert that account and protocol names given to ops below always match the im_connection passed through as opdata */ @@ -1419,6 +1779,7 @@ { struct im_connection *ic = (struct im_connection *)opdata; +#if OTRL_VERSION_MAJOR >= 4 /* 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) { @@ -1433,6 +1794,7 @@ if(!l) return NULL; } +#endif if (strcmp(accountname, ic->acc->user) != 0) { log_message(LOGLVL_WARNING, @@ -2005,6 +2367,7 @@ return strpbrk(s, "/\\") == NULL; } +#if OTRL_VERSION_MAJOR >= 4 /* close the OTR connection with the given buddy */ gboolean otr_disconnect_user(irc_t *irc, irc_user_t *u) { @@ -2035,5 +2398,6 @@ } } } +#endif /* vim: set noet ts=4 sw=4: */ --- bitlbee-3.2.2/otr.h 2014-07-05 23:40:53.000000000 +0200 +++ bitlbee-3.2.2/otr.h.libotr-3-4 2014-07-06 16:49:21.000000000 +0200 @@ -66,8 +66,10 @@ /* keygen jobs waiting to be sent to slave */ kg_t *todo; +#if OTRL_VERSION_MAJOR >= 4 /* event timer for otrl_message_poll */ gint timer; +#endif } otr_t; /* called from main() */ --- bitlbee-3.2.2/configure 2014-07-05 23:40:53.000000000 +0200 +++ bitlbee-3.2.2/configure.libotr-3-4 2014-07-06 17:09:54.000000000 +0200 @@ -517,12 +517,6 @@ echo "CFLAGS+=-I${otrprefix}/include" >> Makefile.settings echo 'OTR_PI=otr.so' >> Makefile.settings fi -if [ "$otr" != 0 ] && ! pkg-config libotr --atleast-version=4.0; then - echo - echo 'WARNING: Your libotr seems to be old. BitlBee now needs at least libotr 4.0.' - # Not hard-failing because the code above doesn't use pkg-config, so who knows - # what's true at this point... -fi if [ "$skype" = "1" -o "$skype" = "plugin" ]; then if [ "$arch" = "Darwin" ]; then