$OpenBSD: patch-mcabber_otr_c,v 1.1 2013/08/15 16:34:50 stsp Exp $
http://www.isbear.org.ua/hg/isbear/mcabber-patches/file/tip/use-otr-v4.diff
--- mcabber/otr.c.orig	Sun Dec  2 14:27:32 2012
+++ mcabber/otr.c	Wed Aug 14 18:56:07 2013
@@ -56,6 +56,20 @@ static void       cb_inject_message     (void *opdata,
                                          const char *protocol,
                                          const char *recipient,
                                          const char *message);
+static void       cb_update_context_list(void *opdata);
+static void       cb_new_fingerprint    (void *opdata, OtrlUserState us,
+                                         const char *accountname,
+                                         const char *protocol,
+                                         const char *username,
+                                         unsigned char fingerprint[20]);
+static void       cb_write_fingerprints (void *opdata);
+static void       cb_gone_secure        (void *opdata, ConnContext *context);
+static void       cb_gone_insecure      (void *opdata, ConnContext *context);
+static void       cb_still_secure       (void *opdata, ConnContext *context,
+                                         int is_reply);
+static int        cb_max_message_size   (void *opdata, ConnContext *context);
+
+#ifdef HAVE_LIBOTR3
 static void       cb_notify             (void *opdata,
                                          OtrlNotifyLevel level,
                                          const char *accountname,
@@ -69,49 +83,71 @@ static int        cb_display_otr_message(void *opdata,
                                          const char *protocol,
                                          const char *username,
                                          const char *msg);
-static void       cb_update_context_list(void *opdata);
 static const char *cb_protocol_name     (void *opdata, const char *protocol);
 static void       cb_protocol_name_free (void *opdata,
                                          const char *protocol_name);
-static void       cb_new_fingerprint    (void *opdata, OtrlUserState us,
-                                         const char *accountname,
-                                         const char *protocol,
-                                         const char *username,
-                                         unsigned char fingerprint[20]);
-static void       cb_write_fingerprints (void *opdata);
-static void       cb_gone_secure        (void *opdata, ConnContext *context);
-static void       cb_gone_insecure      (void *opdata, ConnContext *context);
-static void       cb_still_secure       (void *opdata, ConnContext *context,
-                                         int is_reply);
 static void       cb_log_message        (void *opdata, const char *message);
-static int        cb_max_message_size   (void *opdata, ConnContext *context);
 
+static void       otr_handle_smp_tlvs   (OtrlTLV *tlvs, ConnContext *ctx);
+#else /* HAVE_LIBOTR3 */
+static char *tagfile = NULL;
+static guint otr_timer_source = 0;
+
+static void       cb_handle_smp_event   (void *opdata, OtrlSMPEvent event,
+                                         ConnContext *context, unsigned short percent,
+                                         char *question);
+static void       cb_handle_msg_event   (void *opdata, OtrlMessageEvent event,
+                                         ConnContext *context, const char *message,
+                                         gcry_error_t err);
+static void       cb_create_instag      (void *opdata, const char *accountname,
+                                         const char *protocol);
+static void       cb_timer_control      (void *opdata, unsigned int interval);
+#endif /* HAVE_LIBOTR3 */
+
 static OtrlMessageAppOps ops =
 {
   cb_policy,
   cb_create_privkey,
   cb_is_logged_in,
   cb_inject_message,
+#ifdef HAVE_LIBOTR3
   cb_notify,
   cb_display_otr_message,
+#endif
   cb_update_context_list,
+#ifdef HAVE_LIBOTR3
   cb_protocol_name,
   cb_protocol_name_free,
+#endif
   cb_new_fingerprint,
   cb_write_fingerprints,
   cb_gone_secure,
   cb_gone_insecure,
   cb_still_secure,
+#ifdef HAVE_LIBOTR3
   cb_log_message,
+#endif
   cb_max_message_size,
-  NULL, /*account_name*/
-  NULL  /*account_name_free*/
+  NULL, /* account_name */
+  NULL, /* account_name_free */
+#ifndef HAVE_LIBOTR3
+  NULL, /* received_symkey */
+  NULL, /* otr_error_message */
+  NULL, /* otr_error_message_free */
+  NULL, /* resent_msg_prefix */
+  NULL, /* resent_msg_prefix_free */
+  cb_handle_smp_event,
+  cb_handle_msg_event,
+  cb_create_instag,
+  NULL, /* convert_msg */
+  NULL, /* convert_free */
+  cb_timer_control,
+#endif
 };
 
 static void otr_message_disconnect(ConnContext *ctx);
 static ConnContext *otr_get_context(const char *buddy);
 static void otr_startstop(const char *buddy, int start);
-static void otr_handle_smp_tlvs(OtrlTLV *tlvs, ConnContext *ctx);
 
 static char *otr_get_dir(void);
 
@@ -135,7 +171,6 @@ void otr_init(const char *fjid)
   account = jidtodisp(fjid);
   keyfile = g_strdup_printf("%s%s.key", root, account);
   fprfile = g_strdup_printf("%s%s.fpr", root, account);
-  g_free(root);
 
   if (otrl_privkey_read(userstate, keyfile)){
     scr_LogPrint(LPRINT_LOGNORM, "Could not read OTR key from %s", keyfile);
@@ -145,6 +180,14 @@ void otr_init(const char *fjid)
     scr_LogPrint(LPRINT_LOGNORM, "Could not read OTR fingerprints from %s",
                  fprfile);
   }
+#ifndef HAVE_LIBOTR3
+  tagfile = g_strdup_printf("%s%s.tag", root, account);
+  if (otrl_instag_read(userstate, tagfile)) {
+    scr_LogPrint(LPRINT_LOGNORM, "Could not read OTR instance tag from %s", tagfile);
+    cb_create_instag(NULL, account, OTR_PROTOCOL_NAME);
+  }
+#endif
+  g_free(root);
 }
 
 void otr_terminate(void)
@@ -154,6 +197,13 @@ void otr_terminate(void)
   if (!otr_is_enabled)
     return;
 
+#ifndef HAVE_LIBOTR3
+  if (otr_timer_source > 0) {
+    g_source_remove (otr_timer_source);
+    otr_timer_source = 0;
+  }
+#endif
+
   for (ctx = userstate->context_root; ctx; ctx = ctx->next)
     if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED)
       otr_message_disconnect(ctx);
@@ -175,6 +225,12 @@ void otr_terminate(void)
   userstate = NULL;
   g_free(keyfile);
   keyfile = NULL;
+  g_free(fprfile);
+  fprfile = NULL;
+#ifndef HAVE_LIBOTR3
+  g_free(tagfile);
+  tagfile = NULL;
+#endif
 }
 
 static char *otr_get_dir(void)
@@ -206,7 +262,12 @@ static ConnContext *otr_get_context(const char *buddy)
 
   mc_strtolower(lowcasebuddy);
   ctx = otrl_context_find(userstate, lowcasebuddy, account, OTR_PROTOCOL_NAME,
+#ifdef HAVE_LIBOTR3
                           1, &null, NULL, NULL);
+#else
+                          // INSTAG XXX
+                          OTRL_INSTAG_BEST, 1, &null, NULL, NULL);
+#endif
   g_free(lowcasebuddy);
   return ctx;
 }
@@ -216,7 +277,12 @@ static void otr_message_disconnect(ConnContext *ctx)
   if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED)
     cb_gone_insecure(NULL, ctx);
   otrl_message_disconnect(userstate, &ops, NULL, ctx->accountname,
+#ifdef HAVE_LIBOTR3
                           ctx->protocol, ctx->username);
+#else
+                          // INSTAG XXX
+                          ctx->protocol, ctx->username, OTRL_INSTAG_BEST);
+#endif
 }
 
 static void otr_startstop(const char *buddy, int start)
@@ -283,6 +349,8 @@ void otr_fingerprint(const char *buddy, const char *tr
   cb_write_fingerprints(NULL);
 }
 
+#ifdef HAVE_LIBOTR3
+
 static void otr_handle_smp_tlvs(OtrlTLV *tlvs, ConnContext *ctx)
 {
   OtrlTLV *tlv = NULL;
@@ -354,6 +422,130 @@ static void otr_handle_smp_tlvs(OtrlTLV *tlvs, ConnCon
   }
 }
 
+#else /* HAVE_LIBOTR3 */
+
+static void cb_handle_smp_event(void *opdata, OtrlSMPEvent event,
+                                ConnContext *context, unsigned short percent,
+                                char *question)
+{
+  const char *msg = NULL;
+  char *freeme = NULL;
+  switch (event) {
+    case OTRL_SMPEVENT_ASK_FOR_SECRET:
+      msg = freeme = g_strdup_printf("OTR: Socialist Millionaires' Protocol: "
+                                     "Received SMP Initiation.\n"
+                                     "Answer with /otr smpr %s $secret",
+                                     context->username);
+      break;
+    case OTRL_SMPEVENT_ASK_FOR_ANSWER:
+      msg = freeme = g_strdup_printf("OTR: Socialist Millionaires' Protocol: "
+                                     "Received SMP Initiation.\n"
+                                     "Answer with /otr smpr %s $secret\n"
+                                     "Question: %s", context->username,
+                                     question);
+      break;
+    case OTRL_SMPEVENT_CHEATED:
+      msg = "OTR: Socialist Millionaires' Protocol: Correspondent cancelled negotiation!";
+      otrl_message_abort_smp(userstate, &ops, opdata, context);
+      break;
+    case OTRL_SMPEVENT_IN_PROGRESS:
+      scr_log_print(LPRINT_DEBUG, "OTR: Socialist Millionaires' Protocol: "
+                                  "Negotiation is in pogress...");
+      break;
+    case OTRL_SMPEVENT_SUCCESS:
+      msg = "OTR: Socialist Millionaires' Protocol: Success!";
+      break;
+    case OTRL_SMPEVENT_FAILURE:
+      msg = "OTR: Socialist Millionaires' Protocol: Failure.";
+      break;
+    case OTRL_SMPEVENT_ABORT:
+      msg = "OTR: Socialist Millionaires' Protocol: Aborted.";
+      break;
+    case OTRL_SMPEVENT_ERROR:
+      msg = "OTR: Socialist Millionaires' Protocol: Error occured, aborting negotiations!";
+      otrl_message_abort_smp(userstate, &ops, opdata, context);
+      break;
+    default:
+      break;
+  }
+
+  if (msg) {
+    scr_WriteIncomingMessage(context->username, msg, 0, HBB_PREFIX_INFO, 0);
+    g_free(freeme);
+  }
+}
+
+static void cb_handle_msg_event(void *opdata, OtrlMessageEvent event,
+                                ConnContext *context, const char *message,
+                                gcry_error_t err)
+{
+  const char *msg = NULL;
+  char *freeme = NULL;
+  switch (event) {
+    case OTRL_MSGEVENT_ENCRYPTION_REQUIRED:
+      msg = "OTR: Policy requires encryption on message!";
+      break;
+    case OTRL_MSGEVENT_ENCRYPTION_ERROR:
+      msg = "OTR: Encryption error! Message not sent.";
+      break;
+    case OTRL_MSGEVENT_CONNECTION_ENDED:
+      msg = "OTR: Connection closed by remote end, message lost. "
+            "Close or refresh connection.";
+      break;
+    case OTRL_MSGEVENT_SETUP_ERROR:
+      // FIXME
+      msg = freeme = g_strdup_printf("OTR: Error setting up private conversation: %u",
+                                     err);
+      break;
+    case OTRL_MSGEVENT_MSG_REFLECTED:
+      msg = "OTR: Received own OTR message!";
+      break;
+    case OTRL_MSGEVENT_MSG_RESENT:
+      msg = "OTR: Previous message was resent.";
+      break;
+    case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE:
+      msg = "OTR: Received encrypted message, but connection is not established " \
+            "yet! Message lost.";
+      break;
+    case OTRL_MSGEVENT_RCVDMSG_UNREADABLE:
+      msg = "OTR: Unable to read incoming message!";
+      break;
+    case OTRL_MSGEVENT_RCVDMSG_MALFORMED:
+      msg = "OTR: Malformed incoming message!";
+      break;
+    case OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD:
+      scr_log_print(LPRINT_DEBUG, "OTR: Received heartbeat.");
+      break;
+    case OTRL_MSGEVENT_LOG_HEARTBEAT_SENT:
+      scr_log_print(LPRINT_DEBUG, "OTR: Sent heartbeat.");
+      break;
+    case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR:
+      msg = freeme = g_strdup_printf("OTR: Received general otr error: %s",
+                                     message);
+      break;
+    case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED:
+      msg = freeme = g_strdup_printf("OTR: Received unencrypted message: %s",
+                                     message);
+      break;
+    case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED:
+      msg = "OTR: Unable to determine type of received OTR message!";
+      break;
+    case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE:
+      // XXX
+      scr_log_print(LPRINT_DEBUG, "OTR: Received message for other instance.");
+      break;
+    default:
+      break;
+  }
+
+  if (msg) {
+    scr_WriteIncomingMessage(context->username, msg, 0, HBB_PREFIX_INFO, 0);
+    g_free(freeme);
+  }
+}
+
+#endif /* HAVE_LIBOTR3 */
+
 /*
  * returns whether a otr_message was received
  * sets *otr_data to NULL, when it was an internal otr message
@@ -362,8 +554,10 @@ int otr_receive(char **otr_data, const char *buddy, in
 {
   int ignore_message;
   char *newmessage = NULL;
+#ifdef HAVE_LIBOTR3
   OtrlTLV *tlvs = NULL;
   OtrlTLV *tlv = NULL;
+#endif
   ConnContext *ctx;
 
   ctx = otr_get_context(buddy);
@@ -371,9 +565,9 @@ int otr_receive(char **otr_data, const char *buddy, in
   ignore_message = otrl_message_receiving(userstate, &ops, NULL,
                                           ctx->accountname, ctx->protocol,
                                           ctx->username, *otr_data,
-                                          &newmessage, &tlvs,NULL, NULL);
+#ifdef HAVE_LIBOTR3
+                                          &newmessage, &tlvs, NULL, NULL);
 
-
   tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
   if (tlv) {
     /* Notify the user that the other side disconnected. */
@@ -387,6 +581,9 @@ int otr_receive(char **otr_data, const char *buddy, in
 
   if (tlvs != NULL)
     otrl_tlv_free(tlvs);
+#else
+                                          &newmessage, NULL, NULL, NULL, NULL);
+#endif
 
   if (ignore_message)
     *otr_data = NULL;
@@ -410,13 +607,27 @@ int otr_send(char **msg, const char *buddy)
 
   if (ctx->msgstate == OTRL_MSGSTATE_PLAINTEXT)
     err = otrl_message_sending(userstate, &ops, NULL, ctx->accountname,
+#ifdef HAVE_LIBOTR3
                                ctx->protocol, ctx->username, *msg, NULL,
                                &newmessage, NULL, NULL);
+#else
+                               // INSTAG XXX
+                               ctx->protocol, ctx->username, OTRL_INSTAG_BEST,
+                               *msg, NULL, &newmessage, OTRL_FRAGMENT_SEND_SKIP,
+                               NULL, NULL, NULL);
+#endif
   else {
     htmlmsg = html_escape(*msg);
     err = otrl_message_sending(userstate, &ops, NULL, ctx->accountname,
+#ifdef HAVE_LIBOTR3
                                ctx->protocol, ctx->username, htmlmsg, NULL,
                                &newmessage, NULL, NULL);
+#else
+                               // INSTAG XXX
+                               ctx->protocol, ctx->username, OTRL_INSTAG_BEST,
+                               htmlmsg, NULL, &newmessage, OTRL_FRAGMENT_SEND_SKIP,
+                               NULL, NULL, NULL);
+#endif
     g_free(htmlmsg);
   }
 
@@ -648,6 +859,59 @@ static void cb_inject_message(void *opdata, const char
                   LM_MESSAGE_SUB_TYPE_NOT_SET, NULL);
 }
 
+/* When the list of ConnContexts changes (including a change in
+ * state), this is called so the UI can be updated. */
+static void cb_update_context_list(void *opdata)
+{
+  /*maybe introduce new status characters for mcabber,
+   * then use this function (?!)*/
+}
+
+/* A new fingerprint for the given user has been received. */
+static void cb_new_fingerprint(void *opdata, OtrlUserState us,
+                               const char *accountname, const char *protocol,
+                               const char *username,
+                               unsigned char fingerprint[20])
+{
+  char *sbuf = NULL;
+  char readable[45];
+
+  otrl_privkey_hash_to_human(readable, fingerprint);
+  sbuf = g_strdup_printf("OTR: new fingerprint: %s", readable);
+  scr_WriteIncomingMessage(username, sbuf, 0, HBB_PREFIX_INFO, 0);
+  g_free(sbuf);
+}
+
+/* The list of known fingerprints has changed.  Write them to disk. */
+static void cb_write_fingerprints(void *opdata)
+{
+  otrl_privkey_write_fingerprints(userstate, fprfile);
+}
+
+/* A ConnContext has entered a secure state. */
+static void cb_gone_secure(void *opdata, ConnContext *context)
+{
+  scr_WriteIncomingMessage(context->username, "OTR: channel established", 0,
+                           HBB_PREFIX_INFO, 0);
+}
+
+/* A ConnContext has left a secure state. */
+static void cb_gone_insecure(void *opdata, ConnContext *context)
+{
+  scr_WriteIncomingMessage(context->username, "OTR: channel closed", 0,
+                           HBB_PREFIX_INFO, 0);
+}
+
+/* We have completed an authentication, using the D-H keys we
+ * already knew.  is_reply indicates whether we initiated the AKE. */
+static void cb_still_secure(void *opdata, ConnContext *context, int is_reply)
+{
+  scr_WriteIncomingMessage(context->username, "OTR: channel reestablished", 0,
+                           HBB_PREFIX_INFO, 0);
+}
+
+#ifdef HAVE_LIBOTR3
+
 /* Display a notification message for a particular
  * accountname / protocol / username conversation. */
 static void cb_notify(void *opdata, OtrlNotifyLevel level,
@@ -684,14 +948,6 @@ static int cb_display_otr_message(void *opdata, const 
   return 0;
 }
 
-/* When the list of ConnContexts changes (including a change in
- * state), this is called so the UI can be updated. */
-static void cb_update_context_list(void *opdata)
-{
-  /*maybe introduce new status characters for mcabber,
-   * then use this function (?!)*/
-}
-
 /* Return a newly allocated string containing a human-friendly name
  * for the given protocol id */
 static const char *cb_protocol_name(void *opdata, const char *protocol)
@@ -705,54 +961,40 @@ static void cb_protocol_name_free (void *opdata, const
   /* We didn't allocated memory, so we don't have to free anything :p */
 }
 
-/* A new fingerprint for the given user has been received. */
-static void cb_new_fingerprint(void *opdata, OtrlUserState us,
-                               const char *accountname, const char *protocol,
-                               const char *username,
-                               unsigned char fingerprint[20])
+/* Log a message.  The passed message will end in "\n". */
+static void cb_log_message(void *opdata, const char *message)
 {
-  char *sbuf = NULL;
-  char readable[45];
-
-  otrl_privkey_hash_to_human(readable, fingerprint);
-  sbuf = g_strdup_printf("OTR: new fingerprint: %s", readable);
-  scr_WriteIncomingMessage(username, sbuf, 0, HBB_PREFIX_INFO, 0);
-  g_free(sbuf);
+  scr_LogPrint(LPRINT_DEBUG, "OTR: %s", message);
 }
 
-/* The list of known fingerprints has changed.  Write them to disk. */
-static void cb_write_fingerprints(void *opdata)
-{
-  otrl_privkey_write_fingerprints(userstate, fprfile);
-}
+#else /* HAVE_LIBOTR3 */
 
-/* A ConnContext has entered a secure state. */
-static void cb_gone_secure(void *opdata, ConnContext *context)
+/* Generate unique instance tag for account. */
+static void cb_create_instag(void *opdata, const char *accountname,
+                             const char *protocol)
 {
-  scr_WriteIncomingMessage(context->username, "OTR: channel established", 0,
-                           HBB_PREFIX_INFO, 0);
+  if (otrl_instag_generate(userstate, tagfile, accountname, protocol)) {
+    scr_LogPrint(LPRINT_LOGNORM, "OTR instance tag generation failed!");
+  }
 }
 
-/* A ConnContext has left a secure state. */
-static void cb_gone_insecure(void *opdata, ConnContext *context)
+static gboolean otr_timer_cb(gpointer userdata)
 {
-  scr_WriteIncomingMessage(context->username, "OTR: channel closed", 0,
-                           HBB_PREFIX_INFO, 0);
+  otrl_message_poll(userstate, &ops, userdata);
+  return TRUE;
 }
 
-/* We have completed an authentication, using the D-H keys we
- * already knew.  is_reply indicates whether we initiated the AKE. */
-static void cb_still_secure(void *opdata, ConnContext *context, int is_reply)
+static void cb_timer_control(void *opdata, unsigned int interval)
 {
-  scr_WriteIncomingMessage(context->username, "OTR: channel reestablished", 0,
-                           HBB_PREFIX_INFO, 0);
+  if (otr_timer_source > 0) {
+    g_source_remove(otr_timer_source);
+    otr_timer_source = 0;
+  }
+  if (interval > 0)
+    otr_timer_source = g_timeout_add_seconds(interval, otr_timer_cb, opdata);
 }
 
-/* Log a message.  The passed message will end in "\n". */
-static void cb_log_message(void *opdata, const char *message)
-{
-  scr_LogPrint(LPRINT_DEBUG, "OTR: %s", message);
-}
+#endif /* HAVE_LIBOTR3 */
 
 /* Find the maximum message size supported by this protocol. */
 static int cb_max_message_size(void *opdata, ConnContext *context)
