summary refs log tree commit diff stats
path: root/libotr/libotr-4.1.1/src
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2021-04-09 07:19:03 -0300
committerSoniEx2 <endermoneymod@gmail.com>2021-04-09 07:19:03 -0300
commit0e752a6e215aee21dc73da097c3225495d54a5b6 (patch)
treeb81be02cbf2f06aebf322ac4a5d014b44176bba5 /libotr/libotr-4.1.1/src
parent7754076c715285173311a1b6811ce377950e18a6 (diff)
Add libotr/etc sources
Diffstat (limited to 'libotr/libotr-4.1.1/src')
-rw-r--r--libotr/libotr-4.1.1/src/Makefile.am14
-rw-r--r--libotr/libotr-4.1.1/src/Makefile.in680
-rw-r--r--libotr/libotr-4.1.1/src/auth.c1573
-rw-r--r--libotr/libotr-4.1.1/src/auth.h177
-rw-r--r--libotr/libotr-4.1.1/src/b64.c267
-rw-r--r--libotr/libotr-4.1.1/src/b64.h72
-rw-r--r--libotr/libotr-4.1.1/src/context.c547
-rw-r--r--libotr/libotr-4.1.1/src/context.h193
-rw-r--r--libotr/libotr-4.1.1/src/context_priv.c95
-rw-r--r--libotr/libotr-4.1.1/src/context_priv.h94
-rw-r--r--libotr/libotr-4.1.1/src/dh.c476
-rw-r--r--libotr/libotr-4.1.1/src/dh.h123
-rw-r--r--libotr/libotr-4.1.1/src/instag.c277
-rw-r--r--libotr/libotr-4.1.1/src/instag.h89
-rw-r--r--libotr/libotr-4.1.1/src/mem.c180
-rw-r--r--libotr/libotr-4.1.1/src/mem.h35
-rw-r--r--libotr/libotr-4.1.1/src/message.c2058
-rw-r--r--libotr/libotr-4.1.1/src/message.h440
-rw-r--r--libotr/libotr-4.1.1/src/privkey-t.h50
-rw-r--r--libotr/libotr-4.1.1/src/privkey.c938
-rw-r--r--libotr/libotr-4.1.1/src/privkey.h154
-rw-r--r--libotr/libotr-4.1.1/src/proto.c1081
-rw-r--r--libotr/libotr-4.1.1/src/proto.h174
-rw-r--r--libotr/libotr-4.1.1/src/serial.h107
-rw-r--r--libotr/libotr-4.1.1/src/sm.c998
-rw-r--r--libotr/libotr-4.1.1/src/sm.h84
-rw-r--r--libotr/libotr-4.1.1/src/tlv.c109
-rw-r--r--libotr/libotr-4.1.1/src/tlv.h78
-rw-r--r--libotr/libotr-4.1.1/src/userstate.c57
-rw-r--r--libotr/libotr-4.1.1/src/userstate.h51
-rw-r--r--libotr/libotr-4.1.1/src/version.h31
31 files changed, 11302 insertions, 0 deletions
diff --git a/libotr/libotr-4.1.1/src/Makefile.am b/libotr/libotr-4.1.1/src/Makefile.am
new file mode 100644
index 0000000..c2146cf
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/Makefile.am
@@ -0,0 +1,14 @@
+AM_CPPFLAGS = @LIBGCRYPT_CFLAGS@
+
+lib_LTLIBRARIES = libotr.la
+
+libotr_la_SOURCES = privkey.c context.c proto.c b64.c dh.c mem.c message.c \
+		    userstate.c tlv.c auth.c sm.c context_priv.c instag.c
+
+libotr_la_LDFLAGS = -version-info @LIBOTR_LIBTOOL_VERSION@ @LIBS@ @LIBGCRYPT_LIBS@
+
+otrincdir = $(includedir)/libotr
+
+otrinc_HEADERS = b64.h context.h dh.h mem.h message.h privkey.h proto.h \
+		 version.h userstate.h tlv.h serial.h auth.h sm.h privkey-t.h \
+		 context_priv.h instag.h
diff --git a/libotr/libotr-4.1.1/src/Makefile.in b/libotr/libotr-4.1.1/src/Makefile.in
new file mode 100644
index 0000000..41789c7
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/Makefile.in
@@ -0,0 +1,680 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/config/depcomp $(otrinc_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \
+	$(top_srcdir)/config/ltoptions.m4 \
+	$(top_srcdir)/config/ltsugar.m4 \
+	$(top_srcdir)/config/ltversion.m4 \
+	$(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(otrincdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libotr_la_LIBADD =
+am_libotr_la_OBJECTS = privkey.lo context.lo proto.lo b64.lo dh.lo \
+	mem.lo message.lo userstate.lo tlv.lo auth.lo sm.lo \
+	context_priv.lo instag.lo
+libotr_la_OBJECTS = $(am_libotr_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libotr_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libotr_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libotr_la_SOURCES)
+DIST_SOURCES = $(libotr_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+HEADERS = $(otrinc_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = @LIBGCRYPT_CFLAGS@
+lib_LTLIBRARIES = libotr.la
+libotr_la_SOURCES = privkey.c context.c proto.c b64.c dh.c mem.c message.c \
+		    userstate.c tlv.c auth.c sm.c context_priv.c instag.c
+
+libotr_la_LDFLAGS = -version-info @LIBOTR_LIBTOOL_VERSION@ @LIBS@ @LIBGCRYPT_LIBS@
+otrincdir = $(includedir)/libotr
+otrinc_HEADERS = b64.h context.h dh.h mem.h message.h privkey.h proto.h \
+		 version.h userstate.h tlv.h serial.h auth.h sm.h privkey-t.h \
+		 context_priv.h instag.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libotr.la: $(libotr_la_OBJECTS) $(libotr_la_DEPENDENCIES) $(EXTRA_libotr_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libotr_la_LINK) -rpath $(libdir) $(libotr_la_OBJECTS) $(libotr_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/b64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context_priv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/instag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/privkey.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tlv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/userstate.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+install-otrincHEADERS: $(otrinc_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(otrinc_HEADERS)'; test -n "$(otrincdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(otrincdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(otrincdir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(otrincdir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(otrincdir)" || exit $$?; \
+	done
+
+uninstall-otrincHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(otrinc_HEADERS)'; test -n "$(otrincdir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(otrincdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(otrincdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-otrincHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES uninstall-otrincHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-libLTLIBRARIES install-man \
+	install-otrincHEADERS install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-libLTLIBRARIES uninstall-otrincHEADERS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libotr/libotr-4.1.1/src/auth.c b/libotr/libotr-4.1.1/src/auth.c
new file mode 100644
index 0000000..d0c5505
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/auth.c
@@ -0,0 +1,1573 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2014  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* libotr headers */
+#include "b64.h"
+#include "privkey.h"
+#include "auth.h"
+#include "serial.h"
+#include "proto.h"
+#include "context.h"
+#include "mem.h"
+
+#if OTRL_DEBUGGING
+#include <stdio.h>
+
+/* Dump the contents of an OtrlAuthInfo to the FILE *f. */
+void otrl_auth_dump(FILE *f, const OtrlAuthInfo *auth)
+{
+    int i;
+
+    fprintf(f, "  Auth info %p:\n", auth);
+    fprintf(f, "    State: %d (%s)\n", auth->authstate,
+	auth->authstate == OTRL_AUTHSTATE_NONE ? "NONE" :
+	auth->authstate == OTRL_AUTHSTATE_AWAITING_DHKEY ? "AWAITING_DHKEY" :
+	auth->authstate == OTRL_AUTHSTATE_AWAITING_REVEALSIG ?
+	    "AWAITING_REVEALSIG" :
+	auth->authstate == OTRL_AUTHSTATE_AWAITING_SIG ? "AWAITING_SIG" :
+	auth->authstate == OTRL_AUTHSTATE_V1_SETUP ? "V1_SETUP" :
+	"INVALID");
+    fprintf(f, "    Context: %p\n", auth->context);
+    fprintf(f, "    Our keyid:   %u\n", auth->our_keyid);
+    fprintf(f, "    Their keyid: %u\n", auth->their_keyid);
+    fprintf(f, "    Their fingerprint: ");
+    for (i=0;i<20;++i) {
+	fprintf(f, "%02x", auth->their_fingerprint[i]);
+    }
+    fprintf(f, "\n    Initiated = %d\n", auth->initiated);
+    fprintf(f, "\n    Proto version = %d\n", auth->protocol_version);
+    fprintf(f, "\n    Lastauthmsg = %s\n",
+	auth->lastauthmsg ? auth->lastauthmsg : "(nil)");
+    fprintf(f, "\n    Commit sent time = %ld\n",
+	(long) auth->commit_sent_time);
+}
+
+#endif
+
+/*
+ * Initialize the fields of an OtrlAuthInfo (already allocated).
+ */
+void otrl_auth_new(struct context *context)
+{
+    OtrlAuthInfo *auth = &(context->auth);
+    auth->authstate = OTRL_AUTHSTATE_NONE;
+    otrl_dh_keypair_init(&(auth->our_dh));
+    auth->our_keyid = 0;
+    auth->encgx = NULL;
+    auth->encgx_len = 0;
+    memset(auth->r, 0, 16);
+    memset(auth->hashgx, 0, 32);
+    auth->their_pub = NULL;
+    auth->their_keyid = 0;
+    auth->enc_c = NULL;
+    auth->enc_cp = NULL;
+    auth->mac_m1 = NULL;
+    auth->mac_m1p = NULL;
+    auth->mac_m2 = NULL;
+    auth->mac_m2p = NULL;
+    memset(auth->their_fingerprint, 0, 20);
+    auth->initiated = 0;
+    auth->protocol_version = 0;
+    memset(auth->secure_session_id, 0, 20);
+    auth->secure_session_id_len = 0;
+    auth->lastauthmsg = NULL;
+    auth->commit_sent_time = 0;
+    auth->context = context;
+}
+
+/*
+ * Clear the fields of an OtrlAuthInfo (but leave it allocated).
+ */
+void otrl_auth_clear(OtrlAuthInfo *auth)
+{
+    auth->authstate = OTRL_AUTHSTATE_NONE;
+    otrl_dh_keypair_free(&(auth->our_dh));
+    auth->our_keyid = 0;
+    free(auth->encgx);
+    auth->encgx = NULL;
+    auth->encgx_len = 0;
+    memset(auth->r, 0, 16);
+    memset(auth->hashgx, 0, 32);
+    gcry_mpi_release(auth->their_pub);
+    auth->their_pub = NULL;
+    auth->their_keyid = 0;
+    gcry_cipher_close(auth->enc_c);
+    gcry_cipher_close(auth->enc_cp);
+    gcry_md_close(auth->mac_m1);
+    gcry_md_close(auth->mac_m1p);
+    gcry_md_close(auth->mac_m2);
+    gcry_md_close(auth->mac_m2p);
+    auth->enc_c = NULL;
+    auth->enc_cp = NULL;
+    auth->mac_m1 = NULL;
+    auth->mac_m1p = NULL;
+    auth->mac_m2 = NULL;
+    auth->mac_m2p = NULL;
+    memset(auth->their_fingerprint, 0, 20);
+    auth->initiated = 0;
+    auth->protocol_version = 0;
+    memset(auth->secure_session_id, 0, 20);
+    auth->secure_session_id_len = 0;
+    free(auth->lastauthmsg);
+    auth->lastauthmsg = NULL;
+    auth->commit_sent_time = 0;
+}
+
+/*
+ * Start a fresh AKE (version 2 or 3) using the given OtrlAuthInfo.  Generate
+ * a fresh DH keypair to use.  If no error is returned, the message to
+ * transmit will be contained in auth->lastauthmsg.
+ */
+gcry_error_t otrl_auth_start_v23(OtrlAuthInfo *auth, int version)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+    size_t npub;
+    gcry_cipher_hd_t enc = NULL;
+    unsigned char ctr[16];
+    unsigned char *buf, *bufp;
+    size_t buflen, lenp;
+
+    /* Clear out this OtrlAuthInfo and start over */
+    otrl_auth_clear(auth);
+    auth->initiated = 1;
+    auth->protocol_version = version;
+    auth->context->protocol_version = version;
+
+    otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
+    auth->our_keyid = 1;
+
+    /* Pick an encryption key */
+    gcry_randomize(auth->r, 16, GCRY_STRONG_RANDOM);
+
+    /* Allocate space for the encrypted g^x */
+    gcry_mpi_print(format, NULL, 0, &npub, auth->our_dh.pub);
+    auth->encgx = malloc(4+npub);
+    if (auth->encgx == NULL) goto memerr;
+    auth->encgx_len = 4+npub;
+    bufp = auth->encgx;
+    lenp = auth->encgx_len;
+    write_mpi(auth->our_dh.pub, npub, "g^x");
+    assert(lenp == 0);
+
+    /* Hash g^x */
+    gcry_md_hash_buffer(GCRY_MD_SHA256, auth->hashgx, auth->encgx,
+	    auth->encgx_len);
+
+    /* Encrypt g^x using the key r */
+    err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
+	    GCRY_CIPHER_SECURE);
+    if (err) goto err;
+
+    err = gcry_cipher_setkey(enc, auth->r, 16);
+    if (err) goto err;
+
+    memset(ctr, 0, 16);
+    err = gcry_cipher_setctr(enc, ctr, 16);
+    if (err) goto err;
+
+    err = gcry_cipher_encrypt(enc, auth->encgx, auth->encgx_len, NULL, 0);
+    if (err) goto err;
+
+    gcry_cipher_close(enc);
+    enc = NULL;
+
+    /* Now serialize the message */
+    lenp = OTRL_HEADER_LEN + (auth->protocol_version == 3 ? 8 : 0) + 4
+	    + auth->encgx_len + 4 + 32;
+    bufp = malloc(lenp);
+    if (bufp == NULL) goto memerr;
+    buf = bufp;
+    buflen = lenp;
+
+    /* Header */
+    write_header(auth->protocol_version, '\x02');
+    if (auth->protocol_version == 3) {
+	/* instance tags */
+	write_int(auth->context->our_instance);
+	debug_int("Sender instag", bufp-4);
+	write_int(auth->context->their_instance);
+	debug_int("Recipient instag", bufp-4);
+    }
+
+    /* Encrypted g^x */
+    write_int(auth->encgx_len);
+    debug_int("Enc gx len", bufp-4);
+    memmove(bufp, auth->encgx, auth->encgx_len);
+    debug_data("Enc gx", bufp, auth->encgx_len);
+    bufp += auth->encgx_len; lenp -= auth->encgx_len;
+
+    /* Hashed g^x */
+    write_int(32);
+    debug_int("hashgx len", bufp-4);
+    memmove(bufp, auth->hashgx, 32);
+    debug_data("hashgx", bufp, 32);
+    bufp += 32; lenp -= 32;
+
+    assert(lenp == 0);
+
+    auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
+    free(buf);
+    if (auth->lastauthmsg == NULL) goto memerr;
+    auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY;
+
+    return err;
+
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    otrl_auth_clear(auth);
+    gcry_cipher_close(enc);
+    return err;
+}
+
+/*
+ * Create a D-H Key Message using the our_dh value in the given auth,
+ * and store it in auth->lastauthmsg.
+ */
+static gcry_error_t create_key_message(OtrlAuthInfo *auth)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+    unsigned char *buf, *bufp;
+    size_t buflen, lenp;
+    size_t npub;
+
+    gcry_mpi_print(format, NULL, 0, &npub, auth->our_dh.pub);
+    buflen = OTRL_HEADER_LEN + (auth->protocol_version == 3 ? 8 : 0) + 4 + npub;
+    buf = malloc(buflen);
+    if (buf == NULL) goto memerr;
+    bufp = buf;
+    lenp = buflen;
+
+    /* header */
+    write_header(auth->protocol_version, '\x0a');
+    if (auth->protocol_version == 3) {
+	/* instance tags */
+	write_int(auth->context->our_instance);
+	debug_int("Sender instag", bufp-4);
+	write_int(auth->context->their_instance);
+	debug_int("Recipient instag", bufp-4);
+    }
+
+    /* g^y */
+    write_mpi(auth->our_dh.pub, npub, "g^y");
+
+    assert(lenp == 0);
+
+    free(auth->lastauthmsg);
+    auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
+    free(buf);
+    if (auth->lastauthmsg == NULL) goto memerr;
+
+    return err;
+
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+    return err;
+}
+
+/*
+ * Handle an incoming D-H Commit Message.  If no error is returned, the
+ * message to send will be left in auth->lastauthmsg.  Generate a fresh
+ * keypair to use.
+ */
+gcry_error_t otrl_auth_handle_commit(OtrlAuthInfo *auth,
+	const char *commitmsg, int version)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    unsigned char *buf = NULL, *bufp = NULL, *encbuf = NULL;
+    unsigned char hashbuf[32];
+    size_t buflen, lenp, enclen, hashlen;
+    int res;
+
+    /* Are we the auth for the master context? */
+    int is_master = (auth->context->m_context == auth->context);
+
+    res = otrl_base64_otr_decode(commitmsg, &buf, &buflen);
+    if (res == -1) goto memerr;
+    if (res == -2) goto invval;
+
+    bufp = buf;
+    lenp = buflen;
+
+    /* Header */
+    auth->protocol_version = version;
+    auth->context->protocol_version = version;
+    skip_header('\x02');
+
+    if (version == 3) {
+	require_len(8);
+	bufp += 8; lenp -= 8;
+    }
+
+    /* Encrypted g^x */
+    read_int(enclen);
+    require_len(enclen);
+    encbuf = malloc(enclen);
+    if (encbuf == NULL && enclen > 0) goto memerr;
+    memmove(encbuf, bufp, enclen);
+    bufp += enclen; lenp -= enclen;
+
+    /* Hashed g^x */
+    read_int(hashlen);
+    if (hashlen != 32) goto invval;
+    require_len(32);
+    memmove(hashbuf, bufp, 32);
+    bufp += 32; lenp -= 32;
+
+    if (lenp != 0) goto invval;
+    free(buf);
+    buf = NULL;
+
+    switch(auth->authstate) {
+	case OTRL_AUTHSTATE_NONE:
+	case OTRL_AUTHSTATE_AWAITING_SIG:
+	case OTRL_AUTHSTATE_V1_SETUP:
+	    /* Store the incoming information */
+	    otrl_auth_clear(auth);
+	    auth->protocol_version = version;
+
+	    otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
+
+	    auth->our_keyid = 1;
+	    auth->encgx = encbuf;
+	    encbuf = NULL;
+	    auth->encgx_len = enclen;
+	    memmove(auth->hashgx, hashbuf, 32);
+
+	    /* Create a D-H Key Message */
+	    err = create_key_message(auth);
+	    if (err) goto err;
+	    auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG;
+	    break;
+
+	case OTRL_AUTHSTATE_AWAITING_DHKEY:
+	    /* We sent a D-H Commit Message, and we also received one
+	     * back.  If we're the master context, then the keypair in here
+	     * is probably stale; we just kept it around for a little
+	     * while in case some other logged in instance of our buddy
+	     * replied with a DHKEY message.  In that case, use the
+	     * incoming parameters.  Otherwise, compare the hashgx
+	     * values to see which one wins.
+	     *
+	     * This does NOT use constant time comparison because these
+	     * are two public values thus don't need it. Also, this checks
+	     * which pubkey is larger and not if they are the same. */
+	    if (!is_master && memcmp(auth->hashgx, hashbuf, 32) > 0) {
+		/* Ours wins.  Ignore the message we received, and just
+		 * resend the same D-H Commit message again. */
+		free(encbuf);
+		encbuf = NULL;
+	    } else {
+		/* Ours loses.  Use the incoming parameters instead. */
+		otrl_auth_clear(auth);
+		auth->protocol_version = version;
+		otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
+		auth->our_keyid = 1;
+		auth->encgx = encbuf;
+		encbuf = NULL;
+		auth->encgx_len = enclen;
+		memmove(auth->hashgx, hashbuf, 32);
+
+		/* Create a D-H Key Message */
+		err = create_key_message(auth);
+		if (err) goto err;
+		auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG;
+	    }
+	    break;
+	case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
+	    /* Use the incoming parameters, but just retransmit the old
+	     * D-H Key Message. */
+	    free(auth->encgx);
+	    auth->encgx = encbuf;
+	    encbuf = NULL;
+	    auth->encgx_len = enclen;
+	    memmove(auth->hashgx, hashbuf, 32);
+	    break;
+    }
+
+    return err;
+
+invval:
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    goto err;
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    free(encbuf);
+    return err;
+}
+
+/*
+ * Calculate the encrypted part of the Reveal Signature and Signature
+ * Messages, given a MAC key, an encryption key, two DH public keys, an
+ * authentication public key (contained in an OtrlPrivKey structure),
+ * and a keyid.  If no error is returned, *authbufp will point to the
+ * result, and *authlenp will point to its length.
+ */
+static gcry_error_t calculate_pubkey_auth(unsigned char **authbufp,
+	size_t *authlenp, gcry_md_hd_t mackey, gcry_cipher_hd_t enckey,
+	gcry_mpi_t our_dh_pub, gcry_mpi_t their_dh_pub,
+	OtrlPrivKey *privkey, unsigned int keyid)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+    size_t ourpublen, theirpublen, totallen, lenp;
+    unsigned char *buf = NULL, *bufp = NULL;
+    unsigned char macbuf[32];
+    unsigned char *sigbuf = NULL;
+    size_t siglen;
+
+    /* How big are the DH public keys? */
+    gcry_mpi_print(format, NULL, 0, &ourpublen, our_dh_pub);
+    gcry_mpi_print(format, NULL, 0, &theirpublen, their_dh_pub);
+
+    /* How big is the total structure to be MAC'd? */
+    totallen = 4 + ourpublen + 4 + theirpublen + 2 + privkey->pubkey_datalen
+	    + 4;
+    buf = malloc(totallen);
+    if (buf == NULL) goto memerr;
+
+    bufp = buf;
+    lenp = totallen;
+
+    /* Write the data to be MAC'd */
+    write_mpi(our_dh_pub, ourpublen, "Our DH pubkey");
+    write_mpi(their_dh_pub, theirpublen, "Their DH pubkey");
+    bufp[0] = ((privkey->pubkey_type) >> 8) & 0xff;
+    bufp[1] = (privkey->pubkey_type) & 0xff;
+    bufp += 2; lenp -= 2;
+    memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen);
+    debug_data("Pubkey", bufp, privkey->pubkey_datalen);
+    bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen;
+    write_int(keyid);
+    debug_int("Keyid", bufp-4);
+
+    assert(lenp == 0);
+
+    /* Do the MAC */
+    gcry_md_reset(mackey);
+    gcry_md_write(mackey, buf, totallen);
+    memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32);
+
+    free(buf);
+    buf = NULL;
+
+    /* Sign the MAC */
+    err = otrl_privkey_sign(&sigbuf, &siglen, privkey, macbuf, 32);
+    if (err) goto err;
+
+    /* Calculate the total size of the structure to be encrypted */
+    totallen = 2 + privkey->pubkey_datalen + 4 + siglen;
+    buf = malloc(totallen);
+    if (buf == NULL) goto memerr;
+    bufp = buf;
+    lenp = totallen;
+
+    /* Write the data to be encrypted */
+    bufp[0] = ((privkey->pubkey_type) >> 8) & 0xff;
+    bufp[1] = (privkey->pubkey_type) & 0xff;
+    bufp += 2; lenp -= 2;
+    memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen);
+    debug_data("Pubkey", bufp, privkey->pubkey_datalen);
+    bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen;
+    write_int(keyid);
+    debug_int("Keyid", bufp-4);
+    memmove(bufp, sigbuf, siglen);
+    debug_data("Signature", bufp, siglen);
+    bufp += siglen; lenp -= siglen;
+    free(sigbuf);
+    sigbuf = NULL;
+
+    assert(lenp == 0);
+
+    /* Now do the encryption */
+    err = gcry_cipher_encrypt(enckey, buf, totallen, NULL, 0);
+    if (err) goto err;
+
+    *authbufp = buf;
+    buf = NULL;
+    *authlenp = totallen;
+
+    return err;
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    free(sigbuf);
+    return err;
+}
+
+/*
+ * Decrypt the authenticator in the Reveal Signature and Signature
+ * Messages, given a MAC key, and encryption key, and two DH public
+ * keys.  The fingerprint of the received public key will get put into
+ * fingerprintbufp, and the received keyid will get put in *keyidp.
+ * The encrypted data pointed to by authbuf will be decrypted in place.
+ */
+static gcry_error_t check_pubkey_auth(unsigned char fingerprintbufp[20],
+	unsigned int *keyidp, unsigned char *authbuf, size_t authlen,
+	gcry_md_hd_t mackey, gcry_cipher_hd_t enckey,
+	gcry_mpi_t our_dh_pub, gcry_mpi_t their_dh_pub)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+    size_t ourpublen, theirpublen, totallen, lenp;
+    unsigned char *buf = NULL, *bufp = NULL;
+    unsigned char macbuf[32];
+    unsigned short pubkey_type;
+    gcry_mpi_t p,q,g,y;
+    gcry_sexp_t pubs = NULL;
+    unsigned int received_keyid;
+    unsigned char *fingerprintstart, *fingerprintend, *sigbuf;
+    size_t siglen;
+
+    /* Start by decrypting it */
+    err = gcry_cipher_decrypt(enckey, authbuf, authlen, NULL, 0);
+    if (err) goto err;
+
+    bufp = authbuf;
+    lenp = authlen;
+
+    /* Get the public key and calculate its fingerprint */
+    require_len(2);
+    pubkey_type = (bufp[0] << 8) + bufp[1];
+    bufp += 2; lenp -= 2;
+    if (pubkey_type != OTRL_PUBKEY_TYPE_DSA) goto invval;
+    fingerprintstart = bufp;
+    read_mpi(p);
+    read_mpi(q);
+    read_mpi(g);
+    read_mpi(y);
+    fingerprintend = bufp;
+    gcry_md_hash_buffer(GCRY_MD_SHA1, fingerprintbufp,
+	    fingerprintstart, fingerprintend-fingerprintstart);
+    gcry_sexp_build(&pubs, NULL,
+	"(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", p, q, g, y);
+    gcry_mpi_release(p);
+    gcry_mpi_release(q);
+    gcry_mpi_release(g);
+    gcry_mpi_release(y);
+
+    /* Get the keyid */
+    read_int(received_keyid);
+    if (received_keyid == 0) goto invval;
+
+    /* Get the signature */
+    sigbuf = bufp;
+    siglen = lenp;
+
+    /* How big are the DH public keys? */
+    gcry_mpi_print(format, NULL, 0, &ourpublen, our_dh_pub);
+    gcry_mpi_print(format, NULL, 0, &theirpublen, their_dh_pub);
+
+    /* Now calculate the message to be MAC'd. */
+    totallen = 4 + ourpublen + 4 + theirpublen + 2 +
+	(fingerprintend - fingerprintstart) + 4;
+    buf = malloc(totallen);
+    if (buf == NULL) goto memerr;
+
+    bufp = buf;
+    lenp = totallen;
+
+    write_mpi(their_dh_pub, theirpublen, "Their DH pubkey");
+    write_mpi(our_dh_pub, ourpublen, "Our DH pubkey");
+    bufp[0] = (pubkey_type >> 8) & 0xff;
+    bufp[1] = pubkey_type & 0xff;
+    bufp += 2; lenp -= 2;
+    memmove(bufp, fingerprintstart, fingerprintend - fingerprintstart);
+    debug_data("Pubkey", bufp, fingerprintend - fingerprintstart);
+    bufp += fingerprintend - fingerprintstart;
+    lenp -= fingerprintend - fingerprintstart;
+    write_int(received_keyid);
+    debug_int("Keyid", bufp-4);
+
+    assert(lenp == 0);
+
+    /* Do the MAC */
+    gcry_md_reset(mackey);
+    gcry_md_write(mackey, buf, totallen);
+    memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32);
+
+    free(buf);
+    buf = NULL;
+
+    /* Verify the signature on the MAC */
+    err = otrl_privkey_verify(sigbuf, siglen, pubkey_type, pubs, macbuf, 32);
+    if (err) goto err;
+    gcry_sexp_release(pubs);
+    pubs = NULL;
+
+    /* Everything checked out */
+    *keyidp = received_keyid;
+
+    return err;
+invval:
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    goto err;
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    gcry_sexp_release(pubs);
+    return err;
+}
+
+/*
+ * Create a Reveal Signature Message using the values in the given auth,
+ * and store it in auth->lastauthmsg.  Use the given privkey to sign the
+ * message.
+ */
+static gcry_error_t create_revealsig_message(OtrlAuthInfo *auth,
+	OtrlPrivKey *privkey)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    unsigned char *buf = NULL, *bufp, *startmac;
+    size_t buflen, lenp;
+
+    unsigned char *authbuf = NULL;
+    size_t authlen;
+
+    /* Get the encrypted authenticator */
+    err = calculate_pubkey_auth(&authbuf, &authlen, auth->mac_m1, auth->enc_c,
+	    auth->our_dh.pub, auth->their_pub, privkey, auth->our_keyid);
+    if (err) goto err;
+
+    buflen = OTRL_HEADER_LEN + (auth->protocol_version == 3 ? 8 : 0) + 4 + 16
+	    + 4 + authlen + 20;
+    buf = malloc(buflen);
+    if (buf == NULL) goto memerr;
+
+    bufp = buf;
+    lenp = buflen;
+
+    /* header */
+    write_header(auth->protocol_version, '\x11');
+    if (auth->protocol_version == 3) {
+	/* instance tags */
+	write_int(auth->context->our_instance);
+	debug_int("Sender instag", bufp-4);
+	write_int(auth->context->their_instance);
+	debug_int("Recipient instag", bufp-4);
+    }
+
+    /* r */
+    write_int(16);
+    memmove(bufp, auth->r, 16);
+    debug_data("r", bufp, 16);
+    bufp += 16; lenp -= 16;
+
+    /* Encrypted authenticator */
+    startmac = bufp;
+    write_int(authlen);
+    memmove(bufp, authbuf, authlen);
+    debug_data("auth", bufp, authlen);
+    bufp += authlen; lenp -= authlen;
+    free(authbuf);
+    authbuf = NULL;
+
+    /* MAC it, but only take the first 20 bytes */
+    gcry_md_reset(auth->mac_m2);
+    gcry_md_write(auth->mac_m2, startmac, bufp - startmac);
+    memmove(bufp, gcry_md_read(auth->mac_m2, GCRY_MD_SHA256), 20);
+    debug_data("MAC", bufp, 20);
+    bufp += 20; lenp -= 20;
+
+    assert(lenp == 0);
+
+    free(auth->lastauthmsg);
+    auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
+    if (auth->lastauthmsg == NULL) goto memerr;
+    free(buf);
+    buf = NULL;
+
+    return err;
+
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    free(authbuf);
+    return err;
+}
+
+/*
+ * Create a Signature Message using the values in the given auth, and
+ * store it in auth->lastauthmsg.  Use the given privkey to sign the
+ * message.
+ */
+static gcry_error_t create_signature_message(OtrlAuthInfo *auth,
+	OtrlPrivKey *privkey)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    unsigned char *buf = NULL, *bufp, *startmac;
+    size_t buflen, lenp;
+
+    unsigned char *authbuf = NULL;
+    size_t authlen;
+
+    /* Get the encrypted authenticator */
+    err = calculate_pubkey_auth(&authbuf, &authlen, auth->mac_m1p,
+	    auth->enc_cp, auth->our_dh.pub, auth->their_pub, privkey,
+	    auth->our_keyid);
+    if (err) goto err;
+
+    buflen = OTRL_HEADER_LEN + (auth->protocol_version == 3 ? 8 : 0) + 4
+	    + authlen + 20;
+    buf = malloc(buflen);
+    if (buf == NULL) goto memerr;
+
+    bufp = buf;
+    lenp = buflen;
+
+    /* header */
+    write_header(auth->protocol_version, '\x12');
+    if (auth->protocol_version == 3) {
+	/* instance tags */
+	write_int(auth->context->our_instance);
+	debug_int("Sender instag", bufp-4);
+	write_int(auth->context->their_instance);
+	debug_int("Recipient instag", bufp-4);
+    }
+
+    /* Encrypted authenticator */
+    startmac = bufp;
+    write_int(authlen);
+    memmove(bufp, authbuf, authlen);
+    debug_data("auth", bufp, authlen);
+    bufp += authlen; lenp -= authlen;
+    free(authbuf);
+    authbuf = NULL;
+
+    /* MAC it, but only take the first 20 bytes */
+    gcry_md_reset(auth->mac_m2p);
+    gcry_md_write(auth->mac_m2p, startmac, bufp - startmac);
+    memmove(bufp, gcry_md_read(auth->mac_m2p, GCRY_MD_SHA256), 20);
+    debug_data("MAC", bufp, 20);
+    bufp += 20; lenp -= 20;
+
+    assert(lenp == 0);
+
+    free(auth->lastauthmsg);
+    auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
+    if (auth->lastauthmsg == NULL) goto memerr;
+    free(buf);
+    buf = NULL;
+
+    return err;
+
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    free(authbuf);
+    return err;
+}
+
+/*
+ * Handle an incoming D-H Key Message.  If no error is returned, and
+ * *havemsgp is 1, the message to sent will be left in auth->lastauthmsg.
+ * Use the given private authentication key to sign messages.
+ */
+gcry_error_t otrl_auth_handle_key(OtrlAuthInfo *auth, const char *keymsg,
+	int *havemsgp, OtrlPrivKey *privkey)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    unsigned char *buf = NULL, *bufp = NULL;
+    size_t buflen, lenp;
+    gcry_mpi_t incoming_pub = NULL;
+    int res;
+    unsigned int msg_version;
+
+    *havemsgp = 0;
+
+    msg_version = otrl_proto_message_version(keymsg);
+
+    res = otrl_base64_otr_decode(keymsg, &buf, &buflen);
+    if (res == -1) goto memerr;
+    if (res == -2) goto invval;
+
+    bufp = buf;
+    lenp = buflen;
+
+    /* Header */
+    skip_header('\x0a');
+
+    if (msg_version == 3) {
+	require_len(8);
+	bufp += 8; lenp -= 8;
+    }
+
+    /* g^y */
+    read_mpi(incoming_pub);
+
+    if (lenp != 0) goto invval;
+    free(buf);
+    buf = NULL;
+
+    switch(auth->authstate) {
+	case OTRL_AUTHSTATE_AWAITING_DHKEY:
+	    /* The other party may also be establishing a session with
+	    another instance running a different version. Ignore any
+	    DHKEY messages we aren't expecting. */
+	    if (msg_version != auth->protocol_version) {
+	      goto err;
+	    }
+
+	    /* Store the incoming public key */
+	    gcry_mpi_release(auth->their_pub);
+	    auth->their_pub = incoming_pub;
+	    incoming_pub = NULL;
+
+	    /* Compute the encryption and MAC keys */
+	    err = otrl_dh_compute_v2_auth_keys(&(auth->our_dh),
+		    auth->their_pub, auth->secure_session_id,
+		    &(auth->secure_session_id_len),
+		    &(auth->enc_c), &(auth->enc_cp),
+		    &(auth->mac_m1), &(auth->mac_m1p),
+		    &(auth->mac_m2), &(auth->mac_m2p));
+	    if (err) goto err;
+
+	    /* Create the Reveal Signature Message */
+	    err = create_revealsig_message(auth, privkey);
+	    if (err) goto err;
+	    *havemsgp = 1;
+	    auth->authstate = OTRL_AUTHSTATE_AWAITING_SIG;
+
+	    break;
+
+	case OTRL_AUTHSTATE_AWAITING_SIG:
+	    if (gcry_mpi_cmp(incoming_pub, auth->their_pub) == 0) {
+		/* Retransmit the Reveal Signature Message */
+		*havemsgp = 1;
+	    } else {
+		/* Ignore this message */
+		*havemsgp = 0;
+	    }
+	    break;
+	case OTRL_AUTHSTATE_NONE:
+	case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
+	case OTRL_AUTHSTATE_V1_SETUP:
+	    /* Ignore this message */
+	    *havemsgp = 0;
+	    break;
+    }
+
+    gcry_mpi_release(incoming_pub);
+    return err;
+
+invval:
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    goto err;
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    gcry_mpi_release(incoming_pub);
+    return err;
+}
+
+/*
+ * Handle an incoming Reveal Signature Message.  If no error is
+ * returned, and *havemsgp is 1, the message to be sent will be left in
+ * auth->lastauthmsg.  Use the given private authentication key to sign
+ * messages.  Call the auth_succeeded callback if authentication is
+ * successful.
+ */
+gcry_error_t otrl_auth_handle_revealsig(OtrlAuthInfo *auth,
+	const char *revealmsg, int *havemsgp, OtrlPrivKey *privkey,
+	gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
+	void *asdata)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    unsigned char *buf = NULL, *bufp = NULL, *gxbuf = NULL;
+    unsigned char *authstart, *authend, *macstart;
+    size_t buflen, lenp, rlen, authlen;
+    gcry_cipher_hd_t enc = NULL;
+    gcry_mpi_t incoming_pub = NULL;
+    unsigned char ctr[16], hashbuf[32];
+    int res;
+    unsigned char version;
+
+    *havemsgp = 0;
+
+    res = otrl_base64_otr_decode(revealmsg, &buf, &buflen);
+    if (res == -1) goto memerr;
+    if (res == -2) goto invval;
+
+    bufp = buf;
+    lenp = buflen;
+
+    require_len(3);
+    version = bufp[1];
+
+    /* Header */
+    skip_header('\x11');
+
+    if (version == 3) {
+	require_len(8);
+	bufp += 8; lenp -= 8;
+    }
+
+    /* r */
+    read_int(rlen);
+    if (rlen != 16) goto invval;
+    require_len(rlen);
+    memmove(auth->r, bufp, rlen);
+    bufp += rlen; lenp -= rlen;
+
+    /* auth */
+    authstart = bufp;
+    read_int(authlen);
+    require_len(authlen);
+    bufp += authlen; lenp -= authlen;
+    authend = bufp;
+
+    /* MAC */
+    require_len(20);
+    macstart = bufp;
+    bufp += 20; lenp -= 20;
+
+    if (lenp != 0) goto invval;
+
+    switch(auth->authstate) {
+	case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
+	    gxbuf = malloc(auth->encgx_len);
+	    if (auth->encgx_len && gxbuf == NULL) goto memerr;
+
+	    /* Use r to decrypt the value of g^x we received earlier */
+	    err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
+		    GCRY_CIPHER_SECURE);
+	    if (err) goto err;
+
+	    err = gcry_cipher_setkey(enc, auth->r, 16);
+	    if (err) goto err;
+
+	    memset(ctr, 0, 16);
+	    err = gcry_cipher_setctr(enc, ctr, 16);
+	    if (err) goto err;
+
+	    err = gcry_cipher_decrypt(enc, gxbuf, auth->encgx_len,
+		    auth->encgx, auth->encgx_len);
+	    if (err) goto err;
+
+	    gcry_cipher_close(enc);
+	    enc = NULL;
+
+	    /* Check the hash */
+	    gcry_md_hash_buffer(GCRY_MD_SHA256, hashbuf, gxbuf,
+		    auth->encgx_len);
+	    /* This isn't comparing secret data, but may as well use the
+	     * constant-time version. */
+	    if (otrl_mem_differ(hashbuf, auth->hashgx, 32)) goto decfail;
+
+	    /* Extract g^x */
+	    bufp = gxbuf;
+	    lenp = auth->encgx_len;
+
+	    read_mpi(incoming_pub);
+	    free(gxbuf);
+	    gxbuf = NULL;
+
+	    if (lenp != 0) goto invval;
+
+	    gcry_mpi_release(auth->their_pub);
+	    auth->their_pub = incoming_pub;
+	    incoming_pub = NULL;
+
+	    /* Compute the encryption and MAC keys */
+	    err = otrl_dh_compute_v2_auth_keys(&(auth->our_dh),
+		    auth->their_pub, auth->secure_session_id,
+		    &(auth->secure_session_id_len),
+		    &(auth->enc_c), &(auth->enc_cp),
+		    &(auth->mac_m1), &(auth->mac_m1p),
+		    &(auth->mac_m2), &(auth->mac_m2p));
+	    if (err) goto err;
+
+	    /* Check the MAC */
+	    gcry_md_reset(auth->mac_m2);
+	    gcry_md_write(auth->mac_m2, authstart, authend - authstart);
+
+	    if (otrl_mem_differ(macstart,
+			gcry_md_read(auth->mac_m2, GCRY_MD_SHA256),
+			20)) goto invval;
+
+	    /* Check the auth */
+	    err = check_pubkey_auth(auth->their_fingerprint,
+		    &(auth->their_keyid), authstart + 4,
+		    authend - authstart - 4, auth->mac_m1, auth->enc_c,
+		    auth->our_dh.pub, auth->their_pub);
+	    if (err) goto err;
+
+	    authstart = NULL;
+	    authend = NULL;
+	    macstart = NULL;
+	    free(buf);
+	    buf = NULL;
+
+	    /* Create the Signature Message */
+	    err = create_signature_message(auth, privkey);
+	    if (err) goto err;
+
+	    /* No error?  Then we've completed our end of the
+	     * authentication. */
+	    auth->session_id_half = OTRL_SESSIONID_SECOND_HALF_BOLD;
+	    if (auth_succeeded) err = auth_succeeded(auth, asdata);
+	    *havemsgp = 1;
+	    auth->our_keyid = 0;
+	    auth->authstate = OTRL_AUTHSTATE_NONE;
+
+	    break;
+	case OTRL_AUTHSTATE_NONE:
+	case OTRL_AUTHSTATE_AWAITING_DHKEY:
+	case OTRL_AUTHSTATE_AWAITING_SIG:
+	case OTRL_AUTHSTATE_V1_SETUP:
+	    /* Ignore this message */
+	    *havemsgp = 0;
+	    free(buf);
+	    buf = NULL;
+	    break;
+    }
+
+    return err;
+
+decfail:
+    err = gcry_error(GPG_ERR_NO_ERROR);
+    goto err;
+invval:
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    goto err;
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    free(gxbuf);
+    gcry_cipher_close(enc);
+    gcry_mpi_release(incoming_pub);
+    return err;
+}
+
+/*
+ * Handle an incoming Signature Message.  If no error is returned, and
+ * *havemsgp is 1, the message to be sent will be left in
+ * auth->lastauthmsg.  Call the auth_succeeded callback if
+ * authentication is successful.
+ */
+gcry_error_t otrl_auth_handle_signature(OtrlAuthInfo *auth,
+	const char *sigmsg, int *havemsgp,
+	gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
+	void *asdata)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    unsigned char *buf = NULL, *bufp = NULL;
+    unsigned char *authstart, *authend, *macstart;
+    size_t buflen, lenp, authlen;
+    int res;
+    unsigned char version;
+
+    *havemsgp = 0;
+
+    res = otrl_base64_otr_decode(sigmsg, &buf, &buflen);
+    if (res == -1) goto memerr;
+    if (res == -2) goto invval;
+
+    bufp = buf;
+    lenp = buflen;
+
+    require_len(3);
+    version = bufp[1];
+
+    /* Header */
+    skip_header('\x12');
+
+    if (version == 3) {
+	require_len(8);
+	bufp += 8; lenp -= 8;
+    }
+
+    /* auth */
+    authstart = bufp;
+    read_int(authlen);
+    require_len(authlen);
+    bufp += authlen; lenp -= authlen;
+    authend = bufp;
+
+    /* MAC */
+    require_len(20);
+    macstart = bufp;
+    bufp += 20; lenp -= 20;
+
+    if (lenp != 0) goto invval;
+
+    switch(auth->authstate) {
+	case OTRL_AUTHSTATE_AWAITING_SIG:
+	    /* Check the MAC */
+	    gcry_md_reset(auth->mac_m2p);
+	    gcry_md_write(auth->mac_m2p, authstart, authend - authstart);
+	    if (otrl_mem_differ(macstart,
+			gcry_md_read(auth->mac_m2p, GCRY_MD_SHA256),
+			20)) goto invval;
+
+	    /* Check the auth */
+	    err = check_pubkey_auth(auth->their_fingerprint,
+		    &(auth->their_keyid), authstart + 4,
+		    authend - authstart - 4, auth->mac_m1p, auth->enc_cp,
+		    auth->our_dh.pub, auth->their_pub);
+	    if (err) goto err;
+
+	    authstart = NULL;
+	    authend = NULL;
+	    macstart = NULL;
+	    free(buf);
+	    buf = NULL;
+
+	    /* No error?  Then we've completed our end of the
+	     * authentication. */
+	    auth->session_id_half = OTRL_SESSIONID_FIRST_HALF_BOLD;
+	    if (auth_succeeded) err = auth_succeeded(auth, asdata);
+	    free(auth->lastauthmsg);
+	    auth->lastauthmsg = NULL;
+	    *havemsgp = 0;
+	    auth->our_keyid = 0;
+	    auth->authstate = OTRL_AUTHSTATE_NONE;
+
+	    break;
+	case OTRL_AUTHSTATE_NONE:
+	case OTRL_AUTHSTATE_AWAITING_DHKEY:
+	case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
+	case OTRL_AUTHSTATE_V1_SETUP:
+	    /* Ignore this message */
+	    *havemsgp = 0;
+	    free(buf);
+	    buf = NULL;
+	    break;
+    }
+
+    return err;
+
+invval:
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    goto err;
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    return err;
+}
+
+/* Version 1 routines, for compatibility */
+
+/*
+ * Create a verion 1 Key Exchange Message using the values in the given
+ * auth, and store it in auth->lastauthmsg.  Set the Reply field to the
+ * given value, and use the given privkey to sign the message.
+ */
+static gcry_error_t create_v1_key_exchange_message(OtrlAuthInfo *auth,
+	unsigned char reply, OtrlPrivKey *privkey)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+    unsigned char *buf = NULL, *bufp = NULL, *sigbuf = NULL;
+    size_t lenp, ourpublen, totallen, siglen;
+    unsigned char hashbuf[20];
+
+    if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA) {
+	return gpg_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* How big is the DH public key? */
+    gcry_mpi_print(format, NULL, 0, &ourpublen, auth->our_dh.pub);
+
+    totallen = 3 + 1 + privkey->pubkey_datalen + 4 + 4 + ourpublen + 40;
+    buf = malloc(totallen);
+    if (buf == NULL) goto memerr;
+
+    bufp = buf;
+    lenp = totallen;
+
+    memmove(bufp, "\x00\x01\x0a", 3); /* header */
+    debug_data("Header", bufp, 3);
+    bufp += 3; lenp -= 3;
+
+    bufp[0] = reply;
+    debug_data("Reply", bufp, 1);
+    bufp += 1; lenp -= 1;
+
+    memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen);
+    debug_data("Pubkey", bufp, privkey->pubkey_datalen);
+    bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen;
+
+    write_int(auth->our_keyid);
+    debug_int("Keyid", bufp-4);
+
+    write_mpi(auth->our_dh.pub, ourpublen, "D-H y");
+
+    /* Hash all the data written so far, and sign the hash */
+    gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf);
+
+    err = otrl_privkey_sign(&sigbuf, &siglen, privkey, hashbuf, 20);
+    if (err) goto err;
+
+    if (siglen != 40) goto invval;
+    memmove(bufp, sigbuf, 40);
+    debug_data("Signature", bufp, 40);
+    bufp += 40; lenp -= 40;
+    free(sigbuf);
+    sigbuf = NULL;
+
+    assert(lenp == 0);
+
+    free(auth->lastauthmsg);
+    auth->lastauthmsg = otrl_base64_otr_encode(buf, totallen);
+    if (auth->lastauthmsg == NULL) goto memerr;
+    free(buf);
+    buf = NULL;
+
+    return err;
+
+invval:
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    goto err;
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    free(sigbuf);
+    return err;
+}
+
+/*
+ * Start a fresh AKE (version 1) using the given OtrlAuthInfo.  If
+ * our_dh is NULL, generate a fresh DH keypair to use.  Otherwise, use a
+ * copy of the one passed (with the given keyid).  Use the given private
+ * key to sign the message.  If no error is returned, the message to
+ * transmit will be contained in auth->lastauthmsg.
+ */
+gcry_error_t otrl_auth_start_v1(OtrlAuthInfo *auth, DH_keypair *our_dh,
+	unsigned int our_keyid, OtrlPrivKey *privkey)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+
+    /* Clear out this OtrlAuthInfo and start over */
+    otrl_auth_clear(auth);
+    auth->initiated = 1;
+    auth->protocol_version = 1;
+
+    /* Import the given DH keypair, or else create a fresh one */
+    if (our_dh) {
+	otrl_dh_keypair_copy(&(auth->our_dh), our_dh);
+	auth->our_keyid = our_keyid;
+    } else {
+	otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
+	auth->our_keyid = 1;
+    }
+
+    err = create_v1_key_exchange_message(auth, 0, privkey);
+    if (!err) {
+	auth->authstate = OTRL_AUTHSTATE_V1_SETUP;
+    }
+
+    return err;
+}
+
+/*
+ * Handle an incoming v1 Key Exchange Message.  If no error is returned,
+ * and *havemsgp is 1, the message to be sent will be left in
+ * auth->lastauthmsg.  Use the given private authentication key to sign
+ * messages.  Call the auth_secceeded callback if authentication is
+ * successful.  If non-NULL, use a copy of the given D-H keypair, with
+ * the given keyid.
+ */
+gcry_error_t otrl_auth_handle_v1_key_exchange(OtrlAuthInfo *auth,
+	const char *keyexchmsg, int *havemsgp, OtrlPrivKey *privkey,
+	DH_keypair *our_dh, unsigned int our_keyid,
+	gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
+	void *asdata)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    unsigned char *buf = NULL, *bufp = NULL;
+    unsigned char *fingerprintstart, *fingerprintend;
+    unsigned char fingerprintbuf[20], hashbuf[20];
+    gcry_mpi_t p, q, g, y, received_pub = NULL;
+    gcry_sexp_t pubs = NULL;
+    size_t buflen, lenp;
+    unsigned char received_reply;
+    unsigned int received_keyid;
+    int res;
+
+    *havemsgp = 0;
+
+    res = otrl_base64_otr_decode(keyexchmsg, &buf, &buflen);
+    if (res == -1) goto memerr;
+    if (res == -2) goto invval;
+
+    bufp = buf;
+    lenp = buflen;
+
+    /* Header */
+    require_len(3);
+    if (memcmp(bufp, "\x00\x01\x0a", 3)) goto invval;
+    bufp += 3; lenp -= 3;
+
+    /* Reply */
+    require_len(1);
+    received_reply = bufp[0];
+    bufp += 1; lenp -= 1;
+
+    /* Public Key */
+    fingerprintstart = bufp;
+    read_mpi(p);
+    read_mpi(q);
+    read_mpi(g);
+    read_mpi(y);
+    fingerprintend = bufp;
+    gcry_md_hash_buffer(GCRY_MD_SHA1, fingerprintbuf,
+	    fingerprintstart, fingerprintend-fingerprintstart);
+    gcry_sexp_build(&pubs, NULL,
+	"(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", p, q, g, y);
+    gcry_mpi_release(p);
+    gcry_mpi_release(q);
+    gcry_mpi_release(g);
+    gcry_mpi_release(y);
+
+    /* keyid */
+    read_int(received_keyid);
+    if (received_keyid == 0) goto invval;
+
+    /* D-H pubkey */
+    read_mpi(received_pub);
+
+    /* Verify the signature */
+    if (lenp != 40) goto invval;
+    gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf);
+    err = otrl_privkey_verify(bufp, lenp, OTRL_PUBKEY_TYPE_DSA,
+	    pubs, hashbuf, 20);
+    if (err) goto err;
+    gcry_sexp_release(pubs);
+    pubs = NULL;
+    free(buf);
+    buf = NULL;
+
+    if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP && received_reply == 0x01) {
+	/* They're replying to something we never sent.  We must be
+	 * logged in more than once; ignore the message. */
+	err = gpg_error(GPG_ERR_NO_ERROR);
+	goto err;
+    }
+
+    if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP) {
+	/* Clear the auth and start over */
+	otrl_auth_clear(auth);
+    }
+
+    /* Everything checked out */
+    auth->their_keyid = received_keyid;
+    gcry_mpi_release(auth->their_pub);
+    auth->their_pub = received_pub;
+    received_pub = NULL;
+    memmove(auth->their_fingerprint, fingerprintbuf, 20);
+
+    if (received_reply == 0x01) {
+	/* Don't send a reply to this. */
+	*havemsgp = 0;
+    } else {
+	/* Import the given DH keypair, or else create a fresh one */
+	if (our_dh) {
+	    otrl_dh_keypair_copy(&(auth->our_dh), our_dh);
+	    auth->our_keyid = our_keyid;
+	} else if (auth->our_keyid == 0) {
+	    otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
+	    auth->our_keyid = 1;
+	}
+
+	/* Reply with our own Key Exchange Message */
+	err = create_v1_key_exchange_message(auth, 1, privkey);
+	if (err) goto err;
+	*havemsgp = 1;
+    }
+
+    /* Compute the session id */
+    err = otrl_dh_compute_v1_session_id(&(auth->our_dh),
+	    auth->their_pub, auth->secure_session_id,
+	    &(auth->secure_session_id_len),
+	    &(auth->session_id_half));
+    if (err) goto err;
+
+    /* We've completed our end of the authentication */
+    auth->protocol_version = 1;
+    if (auth_succeeded) err = auth_succeeded(auth, asdata);
+    auth->our_keyid = 0;
+    auth->authstate = OTRL_AUTHSTATE_NONE;
+
+    return err;
+
+invval:
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    goto err;
+memerr:
+    err = gcry_error(GPG_ERR_ENOMEM);
+err:
+    free(buf);
+    gcry_sexp_release(pubs);
+    gcry_mpi_release(received_pub);
+    return err;
+}
+
+/*
+ * Copy relevant information from the master OtrlAuthInfo to an
+ * instance OtrlAuthInfo in response to a D-H Key with a new
+ * instance. The fields copied will depend on the state of the
+ * master auth.
+ */
+void otrl_auth_copy_on_key(OtrlAuthInfo *m_auth, OtrlAuthInfo *auth)
+{
+    switch(m_auth->authstate) {
+	case OTRL_AUTHSTATE_AWAITING_DHKEY:
+	case OTRL_AUTHSTATE_AWAITING_SIG:
+	    /* Copy our D-H Commit information to the new instance */
+	    otrl_dh_keypair_free(&(auth->our_dh));
+	    auth->initiated = m_auth->initiated;
+	    otrl_dh_keypair_copy(&(auth->our_dh), &(m_auth->our_dh));
+	    auth->our_keyid = m_auth->our_keyid;
+	    memmove(auth->r, m_auth->r, 16);
+	    if (auth->encgx) free(auth->encgx);
+	    auth->encgx = malloc(m_auth->encgx_len);
+	    memmove(auth->encgx, m_auth->encgx, m_auth->encgx_len);
+	    memmove(auth->hashgx, m_auth->hashgx, 32);
+
+	    auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY;
+	    break;
+
+	default:
+	    /* This bad state will be detected and handled later */
+	    break;
+    }
+}
+
+#ifdef OTRL_TESTING_AUTH
+#include "mem.h"
+#include "privkey.h"
+
+#define CHECK_ERR if (err) { printf("Error: %s\n", gcry_strerror(err)); \
+			return 1; }
+
+static gcry_error_t starting(const OtrlAuthInfo *auth, void *asdata)
+{
+    char *name = asdata;
+
+    fprintf(stderr, "\nStarting ENCRYPTED mode for %s (v%d).\n",
+	    name, auth->protocol_version);
+
+    fprintf(stderr, "\nour_dh (%d):", auth->our_keyid);
+    gcry_mpi_dump(auth->our_dh.pub);
+    fprintf(stderr, "\ntheir_pub (%d):", auth->their_keyid);
+    gcry_mpi_dump(auth->their_pub);
+
+    debug_data("\nTheir fingerprint", auth->their_fingerprint, 20);
+    debug_data("\nSecure session id", auth->secure_session_id,
+	    auth->secure_session_id_len);
+    fprintf(stderr, "Sessionid half: %d\n\n", auth->session_id_half);
+
+    return gpg_error(GPG_ERR_NO_ERROR);
+}
+
+int main(int argc, char **argv)
+{
+    OtrlAuthInfo alice, bob;
+    gcry_error_t err;
+    int havemsg;
+    OtrlUserState us;
+    OtrlPrivKey *alicepriv, *bobpriv;
+
+    otrl_mem_init();
+    otrl_dh_init();
+    otrl_auth_new(&alice);
+    otrl_auth_new(&bob);
+
+    us = otrl_userstate_create();
+    otrl_privkey_read(us, "/home/iang/.gaim/otr.private_key");
+    alicepriv = otrl_privkey_find(us, "oneeyedian", "prpl-oscar");
+    bobpriv = otrl_privkey_find(us, "otr4ian", "prpl-oscar");
+
+    printf("\n\n  ***** V2 *****\n\n");
+
+    err = otrl_auth_start_v23(&bob, NULL, 0);
+    CHECK_ERR
+    printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
+    err = otrl_auth_handle_commit(&alice, bob.lastauthmsg, NULL, 0);
+    CHECK_ERR
+    printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg);
+    err = otrl_auth_handle_key(&bob, alice.lastauthmsg, &havemsg, bobpriv);
+    CHECK_ERR
+    if (havemsg) {
+	printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
+    } else {
+	printf("\nIGNORE\n\n");
+    }
+    err = otrl_auth_handle_revealsig(&alice, bob.lastauthmsg, &havemsg,
+	    alicepriv, starting, "Alice");
+    CHECK_ERR
+    if (havemsg) {
+	printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg),
+		alice.lastauthmsg);
+    } else {
+	printf("\nIGNORE\n\n");
+    }
+    err = otrl_auth_handle_signature(&bob, alice.lastauthmsg, &havemsg,
+	    starting, "Bob");
+    CHECK_ERR
+
+    printf("\n\n  ***** V1 *****\n\n");
+
+    err = otrl_auth_start_v1(&bob, NULL, 0, bobpriv);
+    CHECK_ERR
+    printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
+    err = otrl_auth_handle_v1_key_exchange(&alice, bob.lastauthmsg,
+	    &havemsg, alicepriv, NULL, 0, starting, "Alice");
+    CHECK_ERR
+    if (havemsg) {
+	printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg),
+		alice.lastauthmsg);
+    } else {
+	printf("\nIGNORE\n\n");
+    }
+    err = otrl_auth_handle_v1_key_exchange(&bob, alice.lastauthmsg,
+	    &havemsg, bobpriv, NULL, 0, starting, "Bob");
+    CHECK_ERR
+    if (havemsg) {
+	printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
+    } else {
+	printf("\nIGNORE\n\n");
+    }
+
+    otrl_userstate_free(us);
+    otrl_auth_clear(&alice);
+    otrl_auth_clear(&bob);
+    return 0;
+}
+#endif
diff --git a/libotr/libotr-4.1.1/src/auth.h b/libotr/libotr-4.1.1/src/auth.h
new file mode 100644
index 0000000..0b9db54
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/auth.h
@@ -0,0 +1,177 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Rob Smits, Chris Alexander,
+ *  			      Willy Lew, Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __AUTH_H__
+#define __AUTH_H__
+
+#include <gcrypt.h>
+#include <time.h>
+#include "dh.h"
+
+
+typedef enum {
+    OTRL_AUTHSTATE_NONE,
+    OTRL_AUTHSTATE_AWAITING_DHKEY,
+    OTRL_AUTHSTATE_AWAITING_REVEALSIG,
+    OTRL_AUTHSTATE_AWAITING_SIG,
+    OTRL_AUTHSTATE_V1_SETUP
+} OtrlAuthState;
+
+typedef struct {
+    OtrlAuthState authstate;              /* Our state */
+
+    struct context *context;              /* The context which points to us */
+
+    DH_keypair our_dh;                    /* Our D-H key */
+    unsigned int our_keyid;               /* ...and its keyid */
+
+    unsigned char *encgx;                 /* The encrypted value of g^x */
+    size_t encgx_len;                     /*  ...and its length */
+    unsigned char r[16];                  /* The encryption key */
+
+    unsigned char hashgx[32];             /* SHA256(g^x) */
+
+    gcry_mpi_t their_pub;                 /* Their D-H public key */
+    unsigned int their_keyid;             /*  ...and its keyid */
+
+
+    gcry_cipher_hd_t enc_c, enc_cp;       /* c and c' encryption keys */
+    gcry_md_hd_t mac_m1, mac_m1p;         /* m1 and m1' MAC keys */
+    gcry_md_hd_t mac_m2, mac_m2p;         /* m2 and m2' MAC keys */
+
+    unsigned char their_fingerprint[20];  /* The fingerprint of their
+					     long-term signing key */
+
+    int initiated;                        /* Did we initiate this
+					     authentication? */
+
+    unsigned int protocol_version;        /* The protocol version number
+					     used to authenticate. */
+
+    unsigned char secure_session_id[20];  /* The secure session id */
+    size_t secure_session_id_len;         /* And its actual length,
+					     which may be either 20 (for
+					     v1) or 8 (for v2) */
+    OtrlSessionIdHalf session_id_half;    /* Which half of the session
+					     id gets shown in bold */
+
+    char *lastauthmsg;                    /* The last auth message
+					     (base-64 encoded) we sent,
+					     in case we need to
+					     retransmit it. */
+
+    time_t commit_sent_time;              /* The time we last sent the
+                                             lastauthmsg, if it was a
+					     COMMIT message, and this is
+					     a master context.  0
+					     otherwise. */
+} OtrlAuthInfo;
+
+#include "privkey-t.h"
+
+/*
+ * Initialize the fields of an OtrlAuthInfo (already allocated).
+ */
+void otrl_auth_new(struct context *context);
+
+/*
+ * Clear the fields of an OtrlAuthInfo (but leave it allocated).
+ */
+void otrl_auth_clear(OtrlAuthInfo *auth);
+
+/*
+ * Start a fresh AKE (version 2 or 3) using the given OtrlAuthInfo.  Generate
+ * a fresh DH keypair to use.  If no error is returned, the message to
+ * transmit will be contained in auth->lastauthmsg.
+ */
+gcry_error_t otrl_auth_start_v23(OtrlAuthInfo *auth, int version);
+
+/*
+ * Handle an incoming D-H Commit Message.  If no error is returned, the
+ * message to send will be left in auth->lastauthmsg.  Generate a fresh
+ * keypair to use.
+ */
+gcry_error_t otrl_auth_handle_commit(OtrlAuthInfo *auth,
+	const char *commitmsg, int version);
+
+/*
+ * Handle an incoming D-H Key Message.  If no error is returned, and
+ * *havemsgp is 1, the message to sent will be left in auth->lastauthmsg.
+ * Use the given private authentication key to sign messages.
+ */
+gcry_error_t otrl_auth_handle_key(OtrlAuthInfo *auth, const char *keymsg,
+	int *havemsgp, OtrlPrivKey *privkey);
+
+/*
+ * Handle an incoming Reveal Signature Message.  If no error is
+ * returned, and *havemsgp is 1, the message to be sent will be left in
+ * auth->lastauthmsg.  Use the given private authentication key to sign
+ * messages.  Call the auth_succeeded callback if authentication is
+ * successful.
+ */
+gcry_error_t otrl_auth_handle_revealsig(OtrlAuthInfo *auth,
+	const char *revealmsg, int *havemsgp, OtrlPrivKey *privkey,
+	gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
+	void *asdata);
+
+/*
+ * Handle an incoming Signature Message.  If no error is returned, and
+ * *havemsgp is 1, the message to be sent will be left in
+ * auth->lastauthmsg.  Call the auth_succeeded callback if
+ * authentication is successful.
+ */
+gcry_error_t otrl_auth_handle_signature(OtrlAuthInfo *auth,
+	const char *sigmsg, int *havemsgp,
+	gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
+	void *asdata);
+
+/*
+ * Start a fresh AKE (version 1) using the given OtrlAuthInfo.  If
+ * our_dh is NULL, generate a fresh DH keypair to use.  Otherwise, use a
+ * copy of the one passed (with the given keyid).  Use the given private
+ * key to sign the message.  If no error is returned, the message to
+ * transmit will be contained in auth->lastauthmsg.
+ */
+gcry_error_t otrl_auth_start_v1(OtrlAuthInfo *auth, DH_keypair *our_dh,
+	unsigned int our_keyid, OtrlPrivKey *privkey);
+
+/*
+ * Handle an incoming v1 Key Exchange Message.  If no error is returned,
+ * and *havemsgp is 1, the message to be sent will be left in
+ * auth->lastauthmsg.  Use the given private authentication key to sign
+ * messages.  Call the auth_secceeded callback if authentication is
+ * successful.  If non-NULL, use a copy of the given D-H keypair, with
+ * the given keyid.
+ */
+gcry_error_t otrl_auth_handle_v1_key_exchange(OtrlAuthInfo *auth,
+	const char *keyexchmsg, int *havemsgp, OtrlPrivKey *privkey,
+	DH_keypair *our_dh, unsigned int our_keyid,
+	gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
+	void *asdata);
+
+/*
+ * Copy relevant information from the master OtrlAuthInfo to an
+ * instance OtrlAuthInfo in response to a D-H Key with a new
+ * instance. The fields copied will depend on the state of the
+ * master auth.
+ */
+void otrl_auth_copy_on_key(OtrlAuthInfo *m_auth, OtrlAuthInfo *auth);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/b64.c b/libotr/libotr-4.1.1/src/b64.c
new file mode 100644
index 0000000..a7d53aa
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/b64.c
@@ -0,0 +1,267 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Modified from: */
+
+/*********************************************************************\
+
+MODULE NAME:    b64.c
+
+AUTHOR:         Bob Trower 08/04/01
+
+LICENCE:        Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
+
+		Permission is hereby granted, free of charge, to any person
+		obtaining a copy of this software and associated
+		documentation files (the "Software"), to deal in the
+		Software without restriction, including without limitation
+		the rights to use, copy, modify, merge, publish, distribute,
+		sublicense, and/or sell copies of the Software, and to
+		permit persons to whom the Software is furnished to do so,
+		subject to the following conditions:
+
+		The above copyright notice and this permission notice shall
+		be included in all copies or substantial portions of the
+		Software.
+
+		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+		KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+		WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+		PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+		OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+		OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+		OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+		SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+VERSION HISTORY:
+		Bob Trower 08/04/01 -- Create Version 0.00.00B
+
+\******************************************************************* */
+
+/* system headers */
+#include <stdio.h>
+#include <string.h>
+
+/* libotr headers */
+#include "b64.h"
+
+/*
+** Translation Table as described in RFC1113
+*/
+static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/*
+** Translation Table to decode (created by author)
+*/
+static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
+
+/*
+** encodeblock
+**
+** encode up to 3 8-bit binary bytes as 4 '6-bit' characters.
+** len must be 1, 2, or 3.
+*/
+static void encodeblock( char *out, const unsigned char *in, size_t len )
+{
+    unsigned char in0, in1, in2;
+    in0 = in[0];
+    in1 = len > 1 ? in[1] : 0;
+    in2 = len > 2 ? in[2] : 0;
+
+    out[0] = cb64[ in0 >> 2 ];
+    out[1] = cb64[ ((in0 & 0x03) << 4) | ((in1 & 0xf0) >> 4) ];
+    out[2] = len > 1 ? cb64[ ((in1 & 0x0f) << 2) | ((in2 & 0xc0) >> 6) ]
+		     : '=';
+    out[3] = len > 2 ? cb64[ in2 & 0x3f ]
+		     : '=';
+}
+
+/*
+ * base64 encode data.  Insert no linebreaks or whitespace.
+ *
+ * The buffer base64data must contain at least ((datalen+2)/3)*4 bytes of
+ * space.  This function will return the number of bytes actually used.
+ */
+size_t otrl_base64_encode(char *base64data, const unsigned char *data,
+	size_t datalen)
+{
+    size_t base64len = 0;
+
+    while(datalen > 2) {
+	encodeblock(base64data, data, 3);
+	base64data += 4;
+	base64len += 4;
+	data += 3;
+	datalen -= 3;
+    }
+    if (datalen > 0) {
+	encodeblock(base64data, data, datalen);
+	base64len += 4;
+    }
+
+    return base64len;
+}
+
+static size_t decode(unsigned char *out, const char *in, size_t b64len)
+{
+    size_t written = 0;
+    unsigned char c = 0;
+
+    if (b64len > 0) {
+	c = in[0] << 2;
+    }
+    if (b64len > 1) {
+	out[0] = c | in[1] >> 4;
+	written = 1;
+	c = in[1] << 4;
+    }
+    if (b64len > 2) {
+	out[1] = c | in[2] >> 2;
+	written = 2;
+	c = in[2] << 6;
+    }
+    if (b64len > 3) {
+	out[2] = c | in[3];
+	written = 3;
+    }
+    return written;
+}
+
+/*
+ * base64 decode data.  Skip non-base64 chars, and terminate at the
+ * first '=', or the end of the buffer.
+ *
+ * The buffer data must contain at least ((base64len+3) / 4) * 3 bytes
+ * of space.  This function will return the number of bytes actually
+ * used.
+ */
+size_t otrl_base64_decode(unsigned char *data, const char *base64data,
+	size_t base64len)
+{
+    size_t datalen = 0;
+    char b64[4];
+    size_t b64accum = 0;
+
+    while(base64len > 0) {
+	char b = *base64data;
+	unsigned char bdecode;
+	++base64data;
+	--base64len;
+	if (b < '+' || b > 'z') continue;  /* Skip non-base64 chars */
+	if (b == '=') {
+	    /* Force termination */
+	    datalen += decode(data, b64, b64accum);
+	    base64len = 0;
+	} else {
+	    bdecode = cd64[b-'+'];
+	    if (bdecode == '$') continue;  /* Skip non-base64 chars */
+	    b64[b64accum++] = bdecode-'>';
+	    if (b64accum == 4) {
+		/* We have a complete block; decode it. */
+		size_t written = decode(data, b64, b64accum);
+		data += written;
+		datalen += written;
+		b64accum = 0;
+	    }
+	}
+    }
+
+    /* Just discard any short block at the end. */
+
+    return datalen;
+}
+
+/*
+ * Base64-encode a block of data, stick "?OTR:" and "." around it, and
+ * return the result, or NULL in the event of a memory error.  The
+ * caller must free() the return value.
+ */
+char *otrl_base64_otr_encode(const unsigned char *buf, size_t buflen)
+{
+    char *base64buf;
+    size_t base64len;
+    const size_t HALF_MAX_SIZE_T = ((size_t)-1) >> 1;
+
+    if (buflen > HALF_MAX_SIZE_T) {
+	/* You somehow have a buffer that's of size more than half of
+	 * all addressable memory, and you now want a base64 version in
+	 * a new buffer 33% larger?  Not going to happen.  Exit now,
+	 * rather in the malloc below, to avoid integer overflowing the
+	 * computation of base64len. */
+	 return NULL;
+    }
+
+    /* Make the base64-encoding. */
+    base64len = ((buflen + 2) / 3) * 4;
+    base64buf = malloc(5 + base64len + 1 + 1);
+    if (base64buf == NULL) {
+	return NULL;
+    }
+    memmove(base64buf, "?OTR:", 5);
+    otrl_base64_encode(base64buf+5, buf, buflen);
+    base64buf[5 + base64len] = '.';
+    base64buf[5 + base64len + 1] = '\0';
+
+    return base64buf;
+}
+
+/*
+ * Base64-decode the portion of the given message between "?OTR:" and
+ * ".".  Set *bufp to the decoded data, and set *lenp to its length.
+ * The caller must free() the result.  Return 0 on success, -1 on a
+ * memory error, or -2 on invalid input.
+ */
+int otrl_base64_otr_decode(const char *msg, unsigned char **bufp,
+	size_t *lenp)
+{
+    char *otrtag, *endtag;
+    size_t msglen, rawlen;
+    unsigned char *rawmsg;
+
+    otrtag = strstr(msg, "?OTR:");
+    if (!otrtag) {
+	return -2;
+    }
+
+    endtag = strchr(otrtag, '.');
+    if (endtag) {
+	msglen = endtag-otrtag;
+    } else {
+	return -2;
+    }
+
+    /* Skip over the "?OTR:" */
+    otrtag += 5;
+    msglen -= 5;
+
+    /* Base64-decode the message */
+    rawlen = OTRL_B64_MAX_DECODED_SIZE(msglen);   /* maximum possible */
+    rawmsg = malloc(rawlen);
+    if (!rawmsg && rawlen > 0) {
+	return -1;
+    }
+
+    rawlen = otrl_base64_decode(rawmsg, otrtag, msglen);  /* actual size */
+
+    *bufp = rawmsg;
+    *lenp = rawlen;
+
+    return 0;
+}
diff --git a/libotr/libotr-4.1.1/src/b64.h b/libotr/libotr-4.1.1/src/b64.h
new file mode 100644
index 0000000..bdd584a
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/b64.h
@@ -0,0 +1,72 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __B64_H__
+#define __B64_H__
+
+#include <stdlib.h>
+
+/* Base64 encodes blocks of this many bytes: */
+#define OTRL_B64_DECODED_LEN 3
+/* into blocks of this many bytes: */
+#define OTRL_B64_ENCODED_LEN 4
+
+/* An encoded block of length encoded_len can turn into a maximum of
+ * this many decoded bytes: */
+#define OTRL_B64_MAX_DECODED_SIZE(encoded_len) \
+    (((encoded_len + OTRL_B64_ENCODED_LEN - 1) / OTRL_B64_ENCODED_LEN) \
+	* OTRL_B64_DECODED_LEN)
+
+/*
+ * base64 encode data.  Insert no linebreaks or whitespace.
+ *
+ * The buffer base64data must contain at least ((datalen+2)/3)*4 bytes of
+ * space.  This function will return the number of bytes actually used.
+ */
+size_t otrl_base64_encode(char *base64data, const unsigned char *data,
+	size_t datalen);
+
+/*
+ * base64 decode data.  Skip non-base64 chars, and terminate at the
+ * first '=', or the end of the buffer.
+ *
+ * The buffer data must contain at least ((base64len+3) / 4) * 3 bytes
+ * of space.  This function will return the number of bytes actually
+ * used.
+ */
+size_t otrl_base64_decode(unsigned char *data, const char *base64data,
+	size_t base64len);
+
+/*
+ * Base64-encode a block of data, stick "?OTR:" and "." around it, and
+ * return the result, or NULL in the event of a memory error.
+ */
+char *otrl_base64_otr_encode(const unsigned char *buf, size_t buflen);
+
+/*
+ * Base64-decode the portion of the given message between "?OTR:" and
+ * ".".  Set *bufp to the decoded data, and set *lenp to its length.
+ * The caller must free() the result.  Return 0 on success, -1 on a
+ * memory error, or -2 on invalid input.
+ */
+int otrl_base64_otr_decode(const char *msg, unsigned char **bufp,
+	size_t *lenp);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/context.c b/libotr/libotr-4.1.1/src/context.c
new file mode 100644
index 0000000..44d8b86
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/context.c
@@ -0,0 +1,547 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2014  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdlib.h>
+#include <assert.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "context.h"
+#include "instag.h"
+
+#if OTRL_DEBUGGING
+#include <stdio.h>
+
+void otrl_auth_dump(FILE *f, const OtrlAuthInfo *auth);
+void otrl_sm_dump(FILE *f, const OtrlSMState *sm);
+
+/* Dump the contents of a context to the FILE *f. */
+void otrl_context_dump(FILE *f, const ConnContext *context)
+{
+    const Fingerprint *fing;
+
+    fprintf(f, "Context %p:\n\n", context);
+
+    fprintf(f, "  Username: %s\n", context->username);
+    fprintf(f, "  Accountname: %s\n", context->accountname);
+    fprintf(f, "  Protocol: %s\n\n", context->protocol);
+    fprintf(f, "  Master context: %p%s\n", context->m_context,
+	    context->m_context == context ? " IS MASTER" : "");
+    fprintf(f, "  Recent recv child: %p\n", context->recent_rcvd_child);
+    fprintf(f, "  Recent sent child: %p\n", context->recent_sent_child);
+    fprintf(f, "  Recent child: %p\n\n", context->recent_child);
+    fprintf(f, "  Our instance:   %08x\n", context->our_instance);
+    fprintf(f, "  Their instance: %08x\n\n", context->their_instance);
+    fprintf(f, "  Msgstate: %d (%s)\n\n", context->msgstate,
+	context->msgstate == OTRL_MSGSTATE_PLAINTEXT ? "PLAINTEXT" :
+	context->msgstate == OTRL_MSGSTATE_ENCRYPTED ? "ENCRYPTED" :
+	context->msgstate == OTRL_MSGSTATE_FINISHED ? "FINISHED" :
+	"INVALID");
+    otrl_auth_dump(f, &context->auth);
+    fprintf(f, "\n  Fingerprints:\n");
+    for (fing = context->fingerprint_root.next; fing; fing = fing->next) {
+	fprintf(f, "    %p ", fing);
+	if (fing->fingerprint == NULL) {
+	    fprintf(f, "(null)");
+	} else {
+	    int i;
+	    for (i=0;i<20;++i) {
+		fprintf(f, "%02x", fing->fingerprint[i]);
+	    }
+	}
+	fprintf(f, " %p", fing->context);
+	if (fing->trust && fing->trust[0]) {
+	    fprintf(f, " %s", fing->trust);
+	}
+	fprintf(f, "\n");
+    }
+    fprintf(f, "\n  Active fingerprint: %p\n\n", context->active_fingerprint);
+    fprintf(f, "  Protocol version: %d\n", context->protocol_version);
+    fprintf(f, "  OTR offer: %d (%s)\n\n", context->otr_offer,
+	context->otr_offer == OFFER_NOT ? "NOT" :
+	context->otr_offer == OFFER_SENT ? "SENT" :
+	context->otr_offer == OFFER_REJECTED ? "REJECTED" :
+	context->otr_offer == OFFER_ACCEPTED ? "ACCEPTED" :
+	"INVALID");
+
+    fprintf(f, "  Application data: %p\n", context->app_data);
+    if (context->smstate == NULL) {
+	fprintf(f, "  SM state: NULL\n");
+    } else {
+	otrl_sm_dump(f, context->smstate);
+    }
+    fprintf(f, "\n");
+}
+
+/* Dump the master context of this context, and all of its children. */
+void otrl_context_siblings_dump(FILE *f, const ConnContext *context)
+{
+    const ConnContext *citer;
+    for (citer = context->m_context;
+	    citer && citer->m_context == context->m_context;
+	    citer = citer->next) {
+	if (citer == context) {
+	    fprintf(f, "*** ");
+	}
+	otrl_context_dump(f, citer);
+    }
+}
+
+/* Dump all contexts. */
+void otrl_context_all_dump(FILE *f, OtrlUserState us)
+{
+    const ConnContext *citer;
+    unsigned int ctxnum = 1;
+    for (citer = us->context_root; citer; citer = citer->next, ++ctxnum) {
+	fprintf(f, "%u. ", ctxnum);
+	otrl_context_dump(f, citer);
+    }
+}
+#endif
+
+/* Create a new connection context. */
+static ConnContext * new_context(const char * user, const char * accountname,
+	const char * protocol)
+{
+    ConnContext * context;
+    OtrlSMState *smstate;
+
+    context = malloc(sizeof(ConnContext));
+    assert(context != NULL);
+
+    context->username = strdup(user);
+    context->accountname = strdup(accountname);
+    context->protocol = strdup(protocol);
+
+    context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
+    otrl_auth_new(context);
+
+    smstate = malloc(sizeof(OtrlSMState));
+    assert(smstate != NULL);
+    otrl_sm_state_new(smstate);
+    context->smstate = smstate;
+
+    context->our_instance = 0;
+    context->their_instance = OTRL_INSTAG_MASTER;
+    context->fingerprint_root.fingerprint = NULL;
+    context->fingerprint_root.context = context;
+    context->fingerprint_root.next = NULL;
+    context->fingerprint_root.tous = NULL;
+    context->active_fingerprint = NULL;
+    memset(context->sessionid, 0, 20);
+    context->sessionid_len = 0;
+    context->protocol_version = 0;
+    context->otr_offer = OFFER_NOT;
+    context->app_data = NULL;
+    context->app_data_free = NULL;
+    context->context_priv = otrl_context_priv_new();
+    assert(context->context_priv != NULL);
+    context->next = NULL;
+    context->m_context = context;
+    context->recent_rcvd_child = NULL;
+    context->recent_sent_child = NULL;
+    context->recent_child = NULL;
+
+    return context;
+}
+
+ConnContext * otrl_context_find_recent_instance(ConnContext * context,
+	otrl_instag_t recent_instag) {
+    ConnContext * m_context;
+
+    if (!context) return NULL;
+
+    m_context = context->m_context;
+
+    if (!m_context) return NULL;
+
+    switch(recent_instag) {
+	case OTRL_INSTAG_RECENT:
+	    return m_context->recent_child;
+	case OTRL_INSTAG_RECENT_RECEIVED:
+	    return m_context->recent_rcvd_child;
+	case OTRL_INSTAG_RECENT_SENT:
+	    return m_context->recent_sent_child;
+	default:
+	    return NULL;
+    }
+}
+
+/* Find the instance of this context that has the best security level,
+   and for which we have most recently received a message from. Note that most
+   recent in this case is limited to a one-second resolution. */
+ConnContext * otrl_context_find_recent_secure_instance(ConnContext * context)
+{
+    ConnContext *curp; /* for iteration */
+    ConnContext *m_context; /* master */
+    ConnContext *cresult = context;  /* best so far */
+
+    if (!context) {
+	return cresult;
+    }
+
+    m_context = context->m_context;
+
+    for (curp = m_context; curp && curp->m_context == m_context;
+	    curp = curp->next) {
+	int msgstate_improved = 0; /* 0 == same, 1 == improved   */
+	int trust_improved = 0;    /* (will immediately 'continue' if worse
+				    * than) */
+
+	if (cresult->msgstate == curp->msgstate) {
+	    msgstate_improved = 0;
+	} else if (curp->msgstate == OTRL_MSGSTATE_ENCRYPTED ||
+		(cresult->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
+		curp->msgstate == OTRL_MSGSTATE_FINISHED)) {
+	    msgstate_improved = 1;
+	} else {
+	    continue;
+	}
+
+
+	if (otrl_context_is_fingerprint_trusted(cresult->active_fingerprint) ==
+		otrl_context_is_fingerprint_trusted(curp->active_fingerprint)) {
+
+	    trust_improved = 0;
+	} else if
+		(otrl_context_is_fingerprint_trusted(curp->active_fingerprint)){
+
+	    trust_improved = 1;
+	} else {
+	    continue;
+	}
+
+	if (msgstate_improved || trust_improved ||
+		(!msgstate_improved && !trust_improved &&
+		curp->context_priv->lastrecv >=
+		cresult->context_priv->lastrecv)) {
+	    cresult = curp;
+	}
+    }
+
+    return cresult;
+}
+
+/* Look up a connection context by name/account/protocol/instag from the given
+ * OtrlUserState.  If add_if_missing is true, allocate and return a new
+ * context if one does not currently exist.  In that event, call
+ * add_app_data(data, context) so that app_data and app_data_free can be
+ * filled in by the application, and set *addedp to 1.
+ * In the 'their_instance' field note that you can also specify a 'meta-
+ * instance' value such as OTRL_INSTAG_MASTER, OTRL_INSTAG_RECENT,
+ * OTRL_INSTAG_RECENT_RECEIVED and OTRL_INSTAG_RECENT_SENT. */
+ConnContext * otrl_context_find(OtrlUserState us, const char *user,
+	const char *accountname, const char *protocol,
+	otrl_instag_t their_instance, int add_if_missing, int *addedp,
+	void (*add_app_data)(void *data, ConnContext *context), void *data)
+{
+    ConnContext ** curp;
+    int usercmp = 1, acctcmp = 1, protocmp = 1;
+    if (addedp) *addedp = 0;
+    if (!user || !accountname || !protocol) return NULL;
+
+    for (curp = &(us->context_root); *curp; curp = &((*curp)->next)) {
+	if ((usercmp = strcmp((*curp)->username, user)) > 0 ||
+		(usercmp == 0 &&
+		(acctcmp = strcmp((*curp)->accountname, accountname)) > 0) ||
+		(usercmp == 0 && acctcmp == 0 &&
+		(protocmp = strcmp((*curp)->protocol, protocol)) > 0) ||
+		(usercmp == 0 && acctcmp == 0 && protocmp == 0
+		&& (their_instance < OTRL_MIN_VALID_INSTAG ||
+		    ((*curp)->their_instance >= their_instance))))
+	    /* We're at the right place in the list.  We've either found
+	     * it, or gone too far. */
+	    break;
+    }
+
+    if (usercmp == 0 && acctcmp == 0 && protocmp == 0 && *curp &&
+	    (their_instance < OTRL_MIN_VALID_INSTAG ||
+	    (their_instance == (*curp)->their_instance))) {
+	/* Found one! */
+	if (their_instance >= OTRL_MIN_VALID_INSTAG ||
+		their_instance == OTRL_INSTAG_MASTER) {
+	    return *curp;
+	}
+
+	/* We need to go back and check more values in the context */
+	switch(their_instance) {
+	    case OTRL_INSTAG_BEST:
+		return otrl_context_find_recent_secure_instance(*curp);
+	    case OTRL_INSTAG_RECENT:
+	    case OTRL_INSTAG_RECENT_RECEIVED:
+	    case OTRL_INSTAG_RECENT_SENT:
+		return otrl_context_find_recent_instance(*curp, their_instance);
+	    default:
+		return NULL;
+	}
+    }
+
+    if (add_if_missing) {
+	ConnContext *newctx;
+	OtrlInsTag *our_instag = (OtrlInsTag *)otrl_instag_find(us, accountname,
+		protocol);
+
+	if (addedp) *addedp = 1;
+	newctx = new_context(user, accountname, protocol);
+	newctx->next = *curp;
+	if (*curp) {
+	    (*curp)->tous = &(newctx->next);
+	}
+	*curp = newctx;
+	newctx->tous = curp;
+	if (add_app_data) {
+	    add_app_data(data, *curp);
+	}
+
+	/* Initialize specified instance tags */
+	if (our_instag) {
+	    newctx->our_instance = our_instag->instag;
+	}
+
+	if (their_instance >= OTRL_MIN_VALID_INSTAG ||
+		their_instance == OTRL_INSTAG_MASTER) {
+	    newctx->their_instance = their_instance;
+	}
+
+	if (their_instance >= OTRL_MIN_VALID_INSTAG) {
+	    newctx->m_context = otrl_context_find(us, user, accountname,
+		protocol, OTRL_INSTAG_MASTER, 1, NULL, add_app_data, data);
+	}
+
+	if (their_instance == OTRL_INSTAG_MASTER) {
+	    /* if we're adding a master, there are no children, so the most
+	     * recent context is the one we add. */
+	    newctx->recent_child = newctx;
+	    newctx->recent_rcvd_child = newctx;
+	    newctx->recent_sent_child = newctx;
+	}
+
+	return *curp;
+    }
+    return NULL;
+}
+
+/* Return true iff the given fingerprint is marked as trusted. */
+int otrl_context_is_fingerprint_trusted(Fingerprint *fprint) {
+    return fprint && fprint->trust && fprint->trust[0] != '\0';
+}
+
+/* This method gets called after sending or receiving a message, to
+ * update the master context's "recent context" pointers. */
+void otrl_context_update_recent_child(ConnContext *context,
+	unsigned int sent_msg) {
+    ConnContext *m_context = context->m_context;
+
+    if (sent_msg) {
+	m_context->recent_sent_child = context;
+    } else {
+	m_context->recent_rcvd_child = context;
+    }
+
+    m_context->recent_child = context;
+
+}
+
+/* Find a fingerprint in a given context, perhaps adding it if not
+ * present. */
+Fingerprint *otrl_context_find_fingerprint(ConnContext *context,
+	unsigned char fingerprint[20], int add_if_missing, int *addedp)
+{
+    Fingerprint *f;
+    if (addedp) *addedp = 0;
+
+    if (!context || !context->m_context) return NULL;
+
+    context = context->m_context;
+
+    f = context->fingerprint_root.next;
+    while(f) {
+	if (!memcmp(f->fingerprint, fingerprint, 20)) return f;
+	f = f->next;
+    }
+
+    /* Didn't find it. */
+    if (add_if_missing) {
+	if (addedp) *addedp = 1;
+	f = malloc(sizeof(*f));
+	assert(f != NULL);
+	f->fingerprint = malloc(20);
+	assert(f->fingerprint != NULL);
+	memmove(f->fingerprint, fingerprint, 20);
+	f->context = context;
+	f->trust = NULL;
+	f->next = context->fingerprint_root.next;
+	if (f->next) {
+	    f->next->tous = &(f->next);
+	}
+	context->fingerprint_root.next = f;
+	f->tous = &(context->fingerprint_root.next);
+	return f;
+    }
+    return NULL;
+}
+
+/* Set the trust level for a given fingerprint */
+void otrl_context_set_trust(Fingerprint *fprint, const char *trust)
+{
+    if (fprint == NULL) return;
+
+    free(fprint->trust);
+    fprint->trust = trust ? strdup(trust) : NULL;
+}
+
+/* Force a context into the OTRL_MSGSTATE_FINISHED state. */
+void otrl_context_force_finished(ConnContext *context)
+{
+    context->msgstate = OTRL_MSGSTATE_FINISHED;
+    otrl_auth_clear(&(context->auth));
+    context->active_fingerprint = NULL;
+    memset(context->sessionid, 0, 20);
+    context->sessionid_len = 0;
+    context->protocol_version = 0;
+    otrl_sm_state_free(context->smstate);
+    otrl_context_priv_force_finished(context->context_priv);
+}
+
+/* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */
+void otrl_context_force_plaintext(ConnContext *context)
+{
+    /* First clean up everything we'd need to do for the FINISHED state */
+    otrl_context_force_finished(context);
+
+    /* And just set the state properly */
+    context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
+}
+
+/* Forget a fingerprint (so long as it's not the active one.  If it's a
+ * fingerprint_root, forget the whole context (as long as
+ * and_maybe_context is set, and it's PLAINTEXT).  Also, if it's not
+ * the fingerprint_root, but it's the only fingerprint, and we're
+ * PLAINTEXT, forget the whole context if and_maybe_context is set. */
+void otrl_context_forget_fingerprint(Fingerprint *fprint,
+	int and_maybe_context)
+{
+    ConnContext *context = fprint->context;
+    if (fprint == &(context->fingerprint_root)) {
+	if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
+		and_maybe_context) {
+	    otrl_context_forget(context);
+	}
+    } else {
+	if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT ||
+		context->active_fingerprint != fprint) {
+
+	    free(fprint->fingerprint);
+	    free(fprint->trust);
+	    *(fprint->tous) = fprint->next;
+	    if (fprint->next) {
+		fprint->next->tous = fprint->tous;
+	    }
+	    free(fprint);
+	    if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
+		    context->fingerprint_root.next == NULL &&
+		    and_maybe_context) {
+		/* We just deleted the only fingerprint.  Forget the
+		 * whole thing. */
+		otrl_context_forget(context);
+	    }
+	}
+    }
+}
+
+/* Forget a whole context, so long as it's PLAINTEXT. If a context has child
+ * instances, don't remove this instance unless children are also all in
+ * PLAINTEXT state. In this case, the children will also be removed.
+ * Returns 0 on success, 1 on failure. */
+int otrl_context_forget(ConnContext *context)
+{
+    if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1;
+
+    if (context->their_instance == OTRL_INSTAG_MASTER) {
+	ConnContext *c_iter;
+
+	for (c_iter = context; c_iter &&
+		c_iter->m_context == context->m_context;
+		c_iter = c_iter->next) {
+	    if (c_iter->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1;
+	}
+
+	c_iter = context->next;
+	while (c_iter && c_iter->m_context == context->m_context) {
+	    if (!otrl_context_forget(c_iter)) {
+		c_iter = context->next;
+	    } else {
+		return 1;
+	    }
+	}
+
+    }
+
+    /* Just to be safe, force to plaintext.  This also frees any
+     * extraneous data lying around. */
+    otrl_context_force_plaintext(context);
+
+    /* First free all the Fingerprints */
+    while(context->fingerprint_root.next) {
+	otrl_context_forget_fingerprint(context->fingerprint_root.next, 0);
+    }
+    /* Now free all the dynamic info here */
+    free(context->username);
+    free(context->accountname);
+    free(context->protocol);
+    free(context->smstate);
+    context->username = NULL;
+    context->accountname = NULL;
+    context->protocol = NULL;
+    context->smstate = NULL;
+
+    /* Free the application data, if it exists */
+    if (context->app_data && context->app_data_free) {
+	(context->app_data_free)(context->app_data);
+	context->app_data = NULL;
+    }
+
+    /* Fix the list linkages */
+    *(context->tous) = context->next;
+    if (context->next) {
+	context->next->tous = context->tous;
+    }
+
+    free(context);
+    return 0;
+}
+
+/* Forget all the contexts in a given OtrlUserState. */
+void otrl_context_forget_all(OtrlUserState us)
+{
+    ConnContext *c_iter;
+
+    for (c_iter = us->context_root; c_iter; c_iter = c_iter->next) {
+	otrl_context_force_plaintext(c_iter);
+    }
+
+    while (us->context_root) {
+	otrl_context_forget(us->context_root);
+    }
+}
diff --git a/libotr/libotr-4.1.1/src/context.h b/libotr/libotr-4.1.1/src/context.h
new file mode 100644
index 0000000..55cd082
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/context.h
@@ -0,0 +1,193 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2014  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __CONTEXT_H__
+#define __CONTEXT_H__
+
+#include "context_priv.h"
+
+#include <gcrypt.h>
+
+#include "dh.h"
+#include "auth.h"
+#include "sm.h"
+
+typedef struct context ConnContext;    /* Forward declare */
+
+#include "instag.h"
+
+typedef enum {
+    OTRL_MSGSTATE_PLAINTEXT,           /* Not yet started an encrypted
+					  conversation */
+    OTRL_MSGSTATE_ENCRYPTED,           /* Currently in an encrypted
+					  conversation */
+    OTRL_MSGSTATE_FINISHED             /* The remote side has sent us a
+					  notification that he has ended
+					  his end of the encrypted
+					  conversation; prevent any
+					  further messages from being
+					  sent to him. */
+} OtrlMessageState;
+
+typedef struct s_fingerprint {
+    struct s_fingerprint *next;        /* The next fingerprint in the list */
+    struct s_fingerprint **tous;       /* A pointer to the pointer to us */
+    unsigned char *fingerprint;        /* The fingerprint, or NULL */
+    struct context *context;           /* The context to which we belong */
+    char *trust;                       /* The trust level of the fingerprint */
+} Fingerprint;
+
+struct context {
+    struct context * next;             /* Linked list pointer */
+    struct context ** tous;            /* A pointer to the pointer to us */
+
+    /* Context information that is meant for internal use */
+
+    ConnContextPriv *context_priv;
+
+    /* Context information that is meant for application use */
+
+    char * username;                   /* The user this context is for */
+    char * accountname;                /* The username is relative to
+					  this account... */
+    char * protocol;                   /* ... and this protocol */
+
+    struct context *m_context;         /* If this is a child context, this
+					  field will point to the master
+					  context. Otherwise it will point to
+					  itself. */
+    struct context *recent_rcvd_child; /* If this is a master context, this
+					  points to the child context that
+					  has received a message most recently.
+					  By default, it will point to the
+					  master context. In child contexts
+					  this field is NULL. */
+    struct context *recent_sent_child; /* Similar to above, but it points to
+					  the child who has sent most
+					  recently. */
+    struct context *recent_child;      /* Similar to above, but will point to
+					  the most recent of recent_rcvd_child
+					  and recent_sent_child */
+
+    otrl_instag_t our_instance;        /* Our instance tag for this computer*/
+    otrl_instag_t their_instance;      /* The user's instance tag */
+
+    OtrlMessageState msgstate;         /* The state of message disposition
+					  with this user */
+    OtrlAuthInfo auth;                 /* The state of ongoing
+					  authentication with this user */
+
+    Fingerprint fingerprint_root;      /* The root of a linked list of
+					  Fingerprints entries. This list will
+					  only be populated in master contexts.
+					  For child contexts,
+					  fingerprint_root.next will always
+					  point to NULL. */
+    Fingerprint *active_fingerprint;   /* Which fingerprint is in use now?
+					  A pointer into the above list */
+
+    unsigned char sessionid[20];       /* The sessionid and bold half */
+    size_t sessionid_len;              /* determined when this private */
+    OtrlSessionIdHalf sessionid_half;  /* connection was established. */
+
+    unsigned int protocol_version;     /* The version of OTR in use */
+
+    enum {
+	OFFER_NOT,
+	OFFER_SENT,
+	OFFER_REJECTED,
+	OFFER_ACCEPTED
+    } otr_offer;          /* Has this correspondent repsponded to our
+			     OTR offers? */
+
+    /* Application data to be associated with this context */
+    void *app_data;
+    /* A function to free the above data when we forget this context */
+    void (*app_data_free)(void *);
+
+    OtrlSMState *smstate;              /* The state of the current
+					  socialist millionaires exchange */
+};
+
+#include "userstate.h"
+
+/* Look up a connection context by name/account/protocol/instance from the
+ * given OtrlUserState.  If add_if_missing is true, allocate and return a
+ * new context if one does not currently exist.  In that event, call
+ * add_app_data(data, context) so that app_data and app_data_free can be
+ * filled in by the application, and set *addedp to 1.
+ * In the 'their_instance' field note that you can also specify a 'meta-
+ * instance' value such as OTRL_INSTAG_MASTER, OTRL_INSTAL_RECENT,
+ * OTRL_INSTAG_RECENT_RECEIVED and OTRL_INSTAG_RECENT_SENT. */
+ConnContext * otrl_context_find(OtrlUserState us, const char *user,
+	const char *accountname, const char *protocol,
+	otrl_instag_t their_instance, int add_if_missing, int *addedp,
+	void (*add_app_data)(void *data, ConnContext *context), void *data);
+
+/* Return true iff the given fingerprint is marked as trusted. */
+int otrl_context_is_fingerprint_trusted(Fingerprint *fprint);
+
+/* This method gets called after sending or receiving a message, to
+ * update the master context's "recent context" pointers. */
+void otrl_context_update_recent_child(ConnContext *context,
+	unsigned int sent_msg);
+
+/* Find a fingerprint in a given context, perhaps adding it if not
+ * present. */
+Fingerprint *otrl_context_find_fingerprint(ConnContext *context,
+	unsigned char fingerprint[20], int add_if_missing, int *addedp);
+
+/* Set the trust level for a given fingerprint */
+void otrl_context_set_trust(Fingerprint *fprint, const char *trust);
+
+/* Force a context into the OTRL_MSGSTATE_FINISHED state. */
+void otrl_context_force_finished(ConnContext *context);
+
+/* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */
+void otrl_context_force_plaintext(ConnContext *context);
+
+/* Forget a fingerprint (so long as it's not the active one.  If it's a
+ * fingerprint_root, forget the whole context (as long as
+ * and_maybe_context is set, and it's PLAINTEXT).  Also, if it's not
+ * the fingerprint_root, but it's the only fingerprint, and we're
+ * PLAINTEXT, forget the whole context if and_maybe_context is set. */
+void otrl_context_forget_fingerprint(Fingerprint *fprint,
+	int and_maybe_context);
+
+/* Forget a whole context, so long as it's PLAINTEXT. If a context has child
+ * instances, don't remove this instance unless children are also all in
+ * PLAINTEXT state. In this case, the children will also be removed.
+ * Returns 0 on success, 1 on failure. */
+int otrl_context_forget(ConnContext *context);
+
+/* Forget all the contexts in a given OtrlUserState. */
+void otrl_context_forget_all(OtrlUserState us);
+
+/* Find requested recent instance */
+ConnContext * otrl_context_find_recent_instance(ConnContext * context,
+		otrl_instag_t recent_instag);
+
+/* Find the instance of this context that has the best security level, and for
+ * which we have most recently received a message from. Note that most recent
+ * in this case is limited to a one-second resolution. */
+ConnContext * otrl_context_find_recent_secure_instance(ConnContext * context);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/context_priv.c b/libotr/libotr-4.1.1/src/context_priv.c
new file mode 100644
index 0000000..47d05b9
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/context_priv.c
@@ -0,0 +1,95 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *			     Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdlib.h>
+#include <assert.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "context_priv.h"
+
+/* Create a new private connection context */
+ConnContextPriv *otrl_context_priv_new()
+{
+	ConnContextPriv *context_priv;
+	context_priv = malloc(sizeof(*context_priv));
+	assert(context_priv != NULL);
+
+	context_priv->fragment = NULL;
+	context_priv->fragment_len = 0;
+	context_priv->fragment_n = 0;
+	context_priv->fragment_k = 0;
+	context_priv->numsavedkeys = 0;
+	context_priv->saved_mac_keys = NULL;
+	context_priv->generation = 0;
+	context_priv->lastsent = 0;
+	context_priv->lastmessage = NULL;
+	context_priv->lastrecv = 0;
+	context_priv->may_retransmit = 0;
+	context_priv->their_keyid = 0;
+	context_priv->their_y = NULL;
+	context_priv->their_old_y = NULL;
+	context_priv->our_keyid = 0;
+	context_priv->our_dh_key.groupid = 0;
+	context_priv->our_dh_key.priv = NULL;
+	context_priv->our_dh_key.pub = NULL;
+	context_priv->our_old_dh_key.groupid = 0;
+	context_priv->our_old_dh_key.priv = NULL;
+	context_priv->our_old_dh_key.pub = NULL;
+	otrl_dh_session_blank(&(context_priv->sesskeys[0][0]));
+	otrl_dh_session_blank(&(context_priv->sesskeys[0][1]));
+	otrl_dh_session_blank(&(context_priv->sesskeys[1][0]));
+	otrl_dh_session_blank(&(context_priv->sesskeys[1][1]));
+
+	return context_priv;
+}
+
+/* Resets the appropriate variables when a context
+ * is being force finished
+ */
+void otrl_context_priv_force_finished(ConnContextPriv *context_priv)
+{
+	free(context_priv->fragment);
+	context_priv->fragment = NULL;
+	context_priv->fragment_len = 0;
+	context_priv->fragment_n = 0;
+	context_priv->fragment_k = 0;
+	context_priv->numsavedkeys = 0;
+	free(context_priv->saved_mac_keys);
+	context_priv->saved_mac_keys = NULL;
+	gcry_free(context_priv->lastmessage);
+	context_priv->lastmessage = NULL;
+	context_priv->may_retransmit = 0;
+	context_priv->their_keyid = 0;
+	gcry_mpi_release(context_priv->their_y);
+	context_priv->their_y = NULL;
+	gcry_mpi_release(context_priv->their_old_y);
+	context_priv->their_old_y = NULL;
+	context_priv->our_keyid = 0;
+	otrl_dh_keypair_free(&(context_priv->our_dh_key));
+	otrl_dh_keypair_free(&(context_priv->our_old_dh_key));
+	otrl_dh_session_free(&(context_priv->sesskeys[0][0]));
+	otrl_dh_session_free(&(context_priv->sesskeys[0][1]));
+	otrl_dh_session_free(&(context_priv->sesskeys[1][0]));
+	otrl_dh_session_free(&(context_priv->sesskeys[1][1]));
+}
diff --git a/libotr/libotr-4.1.1/src/context_priv.h b/libotr/libotr-4.1.1/src/context_priv.h
new file mode 100644
index 0000000..0748074
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/context_priv.h
@@ -0,0 +1,94 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *			     Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __CONTEXT_PRIV_H__
+#define __CONTEXT_PRIV_H__
+
+#include <gcrypt.h>
+
+#include "dh.h"
+#include "auth.h"
+#include "sm.h"
+
+typedef struct context_priv {
+	/* The part of the fragmented message we've seen so far */
+	char *fragment;
+
+	/* The length of fragment */
+	size_t fragment_len;
+
+	/* The total number of fragments in this message */
+	unsigned short fragment_n;
+
+	/* The highest fragment number we've seen so far for this message */
+	unsigned short fragment_k;
+
+	/* current keyid used by other side; this is set to 0 if we get
+	 * a OTRL_TLV_DISCONNECTED message from them. */
+	unsigned int their_keyid;
+
+	/* Y[their_keyid] (their DH pubkey) */
+	gcry_mpi_t their_y;
+
+	/* Y[their_keyid-1] (their prev DH pubkey) */
+	gcry_mpi_t their_old_y;
+
+	/* current keyid used by us */
+	unsigned int our_keyid;
+
+	/* DH key[our_keyid] */
+	DH_keypair our_dh_key;
+
+	/* DH key[our_keyid-1] */
+	DH_keypair our_old_dh_key;
+
+	/* sesskeys[i][j] are the session keys derived from DH
+	 * key[our_keyid-i] and mpi Y[their_keyid-j] */
+	DH_sesskeys sesskeys[2][2];
+
+	/* saved mac keys to be revealed later */
+	unsigned int numsavedkeys;
+	unsigned char *saved_mac_keys;
+
+	/* generation number: increment every time we go private, and never
+	 * reset to 0 (unless we remove the context entirely) */
+	unsigned int generation;
+
+	/* The last time a Data Message was sent */
+	time_t lastsent;
+
+	/* The last time a Data Message was received */
+	time_t lastrecv;
+
+	/* The plaintext of the last Data Message sent */
+	char *lastmessage;
+
+	/* Is the last message eligible for retransmission? */
+	int may_retransmit;
+
+} ConnContextPriv;
+
+/* Create a new private connection context. */
+ConnContextPriv *otrl_context_priv_new();
+
+/* Frees up memory that was used in otrl_context_priv_new */
+void otrl_context_priv_force_finished(ConnContextPriv *context_priv);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/dh.c b/libotr/libotr-4.1.1/src/dh.c
new file mode 100644
index 0000000..d8bc45d
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/dh.c
@@ -0,0 +1,476 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2014  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdlib.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "dh.h"
+
+
+static const char* DH1536_MODULUS_S = "0x"
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
+static const char *DH1536_GENERATOR_S = "0x02";
+static const int DH1536_MOD_LEN_BITS = 1536;
+static const int DH1536_MOD_LEN_BYTES = 192;
+
+static gcry_mpi_t DH1536_MODULUS = NULL;
+static gcry_mpi_t DH1536_MODULUS_MINUS_2 = NULL;
+static gcry_mpi_t DH1536_GENERATOR = NULL;
+
+/*
+ * Call this once, at plugin load time.  It sets up the modulus and
+ * generator MPIs.
+ */
+void otrl_dh_init(void)
+{
+    gcry_mpi_scan(&DH1536_MODULUS, GCRYMPI_FMT_HEX,
+	(const unsigned char *)DH1536_MODULUS_S, 0, NULL);
+    gcry_mpi_scan(&DH1536_GENERATOR, GCRYMPI_FMT_HEX,
+	(const unsigned char *)DH1536_GENERATOR_S, 0, NULL);
+    DH1536_MODULUS_MINUS_2 = gcry_mpi_new(DH1536_MOD_LEN_BITS);
+    gcry_mpi_sub_ui(DH1536_MODULUS_MINUS_2, DH1536_MODULUS, 2);
+}
+
+/*
+ * Initialize the fields of a DH keypair.
+ */
+void otrl_dh_keypair_init(DH_keypair *kp)
+{
+    kp->groupid = 0;
+    kp->priv = NULL;
+    kp->pub = NULL;
+}
+
+/*
+ * Copy a DH_keypair.
+ */
+void otrl_dh_keypair_copy(DH_keypair *dst, const DH_keypair *src)
+{
+    dst->groupid = src->groupid;
+    dst->priv = gcry_mpi_copy(src->priv);
+    dst->pub = gcry_mpi_copy(src->pub);
+}
+
+/*
+ * Deallocate the contents of a DH_keypair (but not the DH_keypair
+ * itself)
+ */
+void otrl_dh_keypair_free(DH_keypair *kp)
+{
+    gcry_mpi_release(kp->priv);
+    gcry_mpi_release(kp->pub);
+    kp->priv = NULL;
+    kp->pub = NULL;
+}
+
+/*
+ * Generate a DH keypair for a specified group.
+ */
+gcry_error_t otrl_dh_gen_keypair(unsigned int groupid, DH_keypair *kp)
+{
+    unsigned char *secbuf = NULL;
+    gcry_mpi_t privkey = NULL;
+
+    if (groupid != DH1536_GROUP_ID) {
+	/* Invalid group id */
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Generate the secret key: a random 320-bit value */
+    secbuf = gcry_random_bytes_secure(40, GCRY_STRONG_RANDOM);
+    gcry_mpi_scan(&privkey, GCRYMPI_FMT_USG, secbuf, 40, NULL);
+    gcry_free(secbuf);
+
+    kp->groupid = groupid;
+    kp->priv = privkey;
+    kp->pub = gcry_mpi_new(DH1536_MOD_LEN_BITS);
+    gcry_mpi_powm(kp->pub, DH1536_GENERATOR, privkey, DH1536_MODULUS);
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/*
+ * Construct session keys from a DH keypair and someone else's public
+ * key.
+ */
+gcry_error_t otrl_dh_session(DH_sesskeys *sess, const DH_keypair *kp,
+	gcry_mpi_t y)
+{
+    gcry_mpi_t gab;
+    size_t gablen;
+    unsigned char *gabdata;
+    unsigned char *hashdata;
+    unsigned char sendbyte, rcvbyte;
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+
+    otrl_dh_session_blank(sess);
+
+    if (kp->groupid != DH1536_GROUP_ID) {
+	/* Invalid group id */
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Calculate the shared secret MPI */
+    gab = gcry_mpi_snew(DH1536_MOD_LEN_BITS);
+    gcry_mpi_powm(gab, y, kp->priv, DH1536_MODULUS);
+
+    /* Output it in the right format */
+    gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &gablen, gab);
+    gabdata = gcry_malloc_secure(gablen + 5);
+    if (!gabdata) {
+	gcry_mpi_release(gab);
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    gabdata[1] = (gablen >> 24) & 0xff;
+    gabdata[2] = (gablen >> 16) & 0xff;
+    gabdata[3] = (gablen >> 8) & 0xff;
+    gabdata[4] = gablen & 0xff;
+    gcry_mpi_print(GCRYMPI_FMT_USG, gabdata+5, gablen, NULL, gab);
+    gcry_mpi_release(gab);
+
+    hashdata = gcry_malloc_secure(20);
+    if (!hashdata) {
+	gcry_free(gabdata);
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+
+    /* Are we the "high" or "low" end of the connection? */
+    if ( gcry_mpi_cmp(kp->pub, y) > 0 ) {
+	sendbyte = 0x01;
+	rcvbyte = 0x02;
+    } else {
+	sendbyte = 0x02;
+	rcvbyte = 0x01;
+    }
+
+    /* Calculate the sending encryption key */
+    gabdata[0] = sendbyte;
+    gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen+5);
+    err = gcry_cipher_open(&(sess->sendenc), GCRY_CIPHER_AES,
+	    GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
+    if (err) goto err;
+    err = gcry_cipher_setkey(sess->sendenc, hashdata, 16);
+    if (err) goto err;
+
+    /* Calculate the sending MAC key */
+    gcry_md_hash_buffer(GCRY_MD_SHA1, sess->sendmackey, hashdata, 16);
+    err = gcry_md_open(&(sess->sendmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
+    if (err) goto err;
+    err = gcry_md_setkey(sess->sendmac, sess->sendmackey, 20);
+    if (err) goto err;
+
+    /* Calculate the receiving encryption key */
+    gabdata[0] = rcvbyte;
+    gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen+5);
+    err = gcry_cipher_open(&(sess->rcvenc), GCRY_CIPHER_AES,
+	    GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
+    if (err) goto err;
+    err = gcry_cipher_setkey(sess->rcvenc, hashdata, 16);
+    if (err) goto err;
+
+    /* Calculate the receiving MAC key (and save it in the DH_sesskeys
+     * struct, so we can reveal it later) */
+    gcry_md_hash_buffer(GCRY_MD_SHA1, sess->rcvmackey, hashdata, 16);
+    err = gcry_md_open(&(sess->rcvmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
+    if (err) goto err;
+    err = gcry_md_setkey(sess->rcvmac, sess->rcvmackey, 20);
+    if (err) goto err;
+
+    /* Calculate the extra key (used if applications wish to extract a
+     * symmetric key for transferring files, or something like that) */
+    gabdata[0] = 0xff;
+    gcry_md_hash_buffer(GCRY_MD_SHA256, sess->extrakey, gabdata, gablen+5);
+
+    gcry_free(gabdata);
+    gcry_free(hashdata);
+    return gcry_error(GPG_ERR_NO_ERROR);
+err:
+    otrl_dh_session_free(sess);
+    gcry_free(gabdata);
+    gcry_free(hashdata);
+    return err;
+}
+
+/*
+ * Compute the secure session id, two encryption keys, and four MAC keys
+ * given our DH key and their DH public key.
+ */
+gcry_error_t otrl_dh_compute_v2_auth_keys(const DH_keypair *our_dh,
+	gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp,
+	gcry_cipher_hd_t *enc_c, gcry_cipher_hd_t *enc_cp,
+	gcry_md_hd_t *mac_m1, gcry_md_hd_t *mac_m1p,
+	gcry_md_hd_t *mac_m2, gcry_md_hd_t *mac_m2p)
+{
+    gcry_mpi_t s;
+    size_t slen;
+    unsigned char *sdata;
+    unsigned char *hashdata;
+    unsigned char ctr[16];
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+
+    *enc_c = NULL;
+    *enc_cp = NULL;
+    *mac_m1 = NULL;
+    *mac_m1p = NULL;
+    *mac_m2 = NULL;
+    *mac_m2p = NULL;
+    memset(ctr, 0, 16);
+
+    if (our_dh->groupid != DH1536_GROUP_ID) {
+	/* Invalid group id */
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Check that their_pub is in range */
+    if (gcry_mpi_cmp_ui(their_pub, 2) < 0 ||
+	    gcry_mpi_cmp(their_pub, DH1536_MODULUS_MINUS_2) > 0) {
+	/* Invalid pubkey */
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Calculate the shared secret MPI */
+    s = gcry_mpi_snew(DH1536_MOD_LEN_BITS);
+    gcry_mpi_powm(s, their_pub, our_dh->priv, DH1536_MODULUS);
+
+    /* Output it in the right format */
+    gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s);
+    sdata = gcry_malloc_secure(slen + 5);
+    if (!sdata) {
+	gcry_mpi_release(s);
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    sdata[1] = (slen >> 24) & 0xff;
+    sdata[2] = (slen >> 16) & 0xff;
+    sdata[3] = (slen >> 8) & 0xff;
+    sdata[4] = slen & 0xff;
+    gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s);
+    gcry_mpi_release(s);
+
+    /* Calculate the session id */
+    hashdata = gcry_malloc_secure(32);
+    if (!hashdata) {
+	gcry_free(sdata);
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    sdata[0] = 0x00;
+    gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
+    memmove(sessionid, hashdata, 8);
+    *sessionidlenp = 8;
+
+    /* Calculate the encryption keys */
+    sdata[0] = 0x01;
+    gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
+
+    err = gcry_cipher_open(enc_c, GCRY_CIPHER_AES,
+	    GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
+    if (err) goto err;
+    err = gcry_cipher_setkey(*enc_c, hashdata, 16);
+    if (err) goto err;
+    err = gcry_cipher_setctr(*enc_c, ctr, 16);
+    if (err) goto err;
+
+    err = gcry_cipher_open(enc_cp, GCRY_CIPHER_AES,
+	    GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
+    if (err) goto err;
+    err = gcry_cipher_setkey(*enc_cp, hashdata+16, 16);
+    if (err) goto err;
+    err = gcry_cipher_setctr(*enc_cp, ctr, 16);
+    if (err) goto err;
+
+    /* Calculate the MAC keys */
+    sdata[0] = 0x02;
+    gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
+    err = gcry_md_open(mac_m1, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+    if (err) goto err;
+    err = gcry_md_setkey(*mac_m1, hashdata, 32);
+    if (err) goto err;
+
+    sdata[0] = 0x03;
+    gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
+    err = gcry_md_open(mac_m2, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+    if (err) goto err;
+    err = gcry_md_setkey(*mac_m2, hashdata, 32);
+    if (err) goto err;
+
+    sdata[0] = 0x04;
+    gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
+    err = gcry_md_open(mac_m1p, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+    if (err) goto err;
+    err = gcry_md_setkey(*mac_m1p, hashdata, 32);
+    if (err) goto err;
+
+    sdata[0] = 0x05;
+    gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
+    err = gcry_md_open(mac_m2p, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+    if (err) goto err;
+    err = gcry_md_setkey(*mac_m2p, hashdata, 32);
+    if (err) goto err;
+
+    gcry_free(sdata);
+    gcry_free(hashdata);
+    return gcry_error(GPG_ERR_NO_ERROR);
+
+err:
+    gcry_cipher_close(*enc_c);
+    gcry_cipher_close(*enc_cp);
+    gcry_md_close(*mac_m1);
+    gcry_md_close(*mac_m1p);
+    gcry_md_close(*mac_m2);
+    gcry_md_close(*mac_m2p);
+    *enc_c = NULL;
+    *enc_cp = NULL;
+    *mac_m1 = NULL;
+    *mac_m1p = NULL;
+    *mac_m2 = NULL;
+    *mac_m2p = NULL;
+    gcry_free(sdata);
+    gcry_free(hashdata);
+    return err;
+}
+
+/*
+ * Compute the secure session id, given our DH key and their DH public
+ * key.
+ */
+gcry_error_t otrl_dh_compute_v1_session_id(const DH_keypair *our_dh,
+	gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp,
+	OtrlSessionIdHalf *halfp)
+{
+    gcry_mpi_t s;
+    size_t slen;
+    unsigned char *sdata;
+    unsigned char *hashdata;
+
+    if (our_dh->groupid != DH1536_GROUP_ID) {
+	/* Invalid group id */
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Check that their_pub is in range */
+    if (gcry_mpi_cmp_ui(their_pub, 2) < 0 ||
+	    gcry_mpi_cmp(their_pub, DH1536_MODULUS_MINUS_2) > 0) {
+	/* Invalid pubkey */
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Calculate the shared secret MPI */
+    s = gcry_mpi_snew(DH1536_MOD_LEN_BITS);
+    gcry_mpi_powm(s, their_pub, our_dh->priv, DH1536_MODULUS);
+
+    /* Output it in the right format */
+    gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s);
+    sdata = gcry_malloc_secure(slen + 5);
+    if (!sdata) {
+	gcry_mpi_release(s);
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    sdata[1] = (slen >> 24) & 0xff;
+    sdata[2] = (slen >> 16) & 0xff;
+    sdata[3] = (slen >> 8) & 0xff;
+    sdata[4] = slen & 0xff;
+    gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s);
+    gcry_mpi_release(s);
+
+    /* Calculate the session id */
+    hashdata = gcry_malloc_secure(20);
+    if (!hashdata) {
+	gcry_free(sdata);
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    sdata[0] = 0x00;
+    gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, sdata, slen+5);
+    memmove(sessionid, hashdata, 20);
+    *sessionidlenp = 20;
+
+    /* Which half should be bold? */
+    if (gcry_mpi_cmp(our_dh->pub, their_pub) > 0) {
+	*halfp = OTRL_SESSIONID_SECOND_HALF_BOLD;
+    } else {
+	*halfp = OTRL_SESSIONID_FIRST_HALF_BOLD;
+    }
+
+    gcry_free(hashdata);
+    gcry_free(sdata);
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/*
+ * Deallocate the contents of a DH_sesskeys (but not the DH_sesskeys
+ * itself)
+ */
+void otrl_dh_session_free(DH_sesskeys *sess)
+{
+    gcry_cipher_close(sess->sendenc);
+    gcry_cipher_close(sess->rcvenc);
+    gcry_md_close(sess->sendmac);
+    gcry_md_close(sess->rcvmac);
+
+    otrl_dh_session_blank(sess);
+}
+
+/*
+ * Blank out the contents of a DH_sesskeys (without releasing it)
+ */
+void otrl_dh_session_blank(DH_sesskeys *sess)
+{
+    sess->sendenc = NULL;
+    sess->sendmac = NULL;
+    sess->rcvenc = NULL;
+    sess->rcvmac = NULL;
+    memset(sess->sendctr, 0, 16);
+    memset(sess->rcvctr, 0, 16);
+    memset(sess->sendmackey, 0, 20);
+    memset(sess->rcvmackey, 0, 20);
+    sess->sendmacused = 0;
+    sess->rcvmacused = 0;
+    memset(sess->extrakey, 0, OTRL_EXTRAKEY_BYTES);
+}
+
+/* Increment the top half of a counter block */
+void otrl_dh_incctr(unsigned char *ctr)
+{
+    int i;
+    for (i=8;i;--i) {
+	if (++ctr[i-1]) break;
+    }
+}
+
+/* Compare two counter values (8 bytes each).  Return 0 if ctr1 == ctr2,
+ * < 0 if ctr1 < ctr2 (as unsigned 64-bit values), > 0 if ctr1 > ctr2. */
+int otrl_dh_cmpctr(const unsigned char *ctr1, const unsigned char *ctr2)
+{
+    int i;
+    for (i=0;i<8;++i) {
+	int c = ctr1[i] - ctr2[i];
+	if (c) return c;
+    }
+    return 0;
+}
diff --git a/libotr/libotr-4.1.1/src/dh.h b/libotr/libotr-4.1.1/src/dh.h
new file mode 100644
index 0000000..742c408
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/dh.h
@@ -0,0 +1,123 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DH_H__
+#define __DH_H__
+
+#define DH1536_GROUP_ID 5
+
+typedef struct {
+    unsigned int groupid;
+    gcry_mpi_t priv, pub;
+} DH_keypair;
+
+/* Which half of the secure session id should be shown in bold? */
+typedef enum {
+    OTRL_SESSIONID_FIRST_HALF_BOLD,
+    OTRL_SESSIONID_SECOND_HALF_BOLD
+} OtrlSessionIdHalf;
+
+#define OTRL_EXTRAKEY_BYTES 32
+
+typedef struct {
+    unsigned char sendctr[16];
+    unsigned char rcvctr[16];
+    gcry_cipher_hd_t sendenc;
+    gcry_cipher_hd_t rcvenc;
+    gcry_md_hd_t sendmac;
+    unsigned char sendmackey[20];
+    int sendmacused;
+    gcry_md_hd_t rcvmac;
+    unsigned char rcvmackey[20];
+    int rcvmacused;
+    unsigned char extrakey[OTRL_EXTRAKEY_BYTES];
+} DH_sesskeys;
+
+/*
+ * Call this once, at plugin load time.  It sets up the modulus and
+ * generator MPIs.
+ */
+void otrl_dh_init(void);
+
+/*
+ * Initialize the fields of a DH keypair.
+ */
+void otrl_dh_keypair_init(DH_keypair *kp);
+
+/*
+ * Copy a DH_keypair.
+ */
+void otrl_dh_keypair_copy(DH_keypair *dst, const DH_keypair *src);
+
+/*
+ * Deallocate the contents of a DH_keypair (but not the DH_keypair
+ * itself)
+ */
+void otrl_dh_keypair_free(DH_keypair *kp);
+
+/*
+ * Generate a DH keypair for a specified group.
+ */
+gcry_error_t otrl_dh_gen_keypair(unsigned int groupid, DH_keypair *kp);
+
+/*
+ * Construct session keys from a DH keypair and someone else's public
+ * key.
+ */
+gcry_error_t otrl_dh_session(DH_sesskeys *sess, const DH_keypair *kp,
+	gcry_mpi_t y);
+
+/*
+ * Compute the secure session id, two encryption keys, and four MAC keys
+ * given our DH key and their DH public key.
+ */
+gcry_error_t otrl_dh_compute_v2_auth_keys(const DH_keypair *our_dh,
+	gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp,
+	gcry_cipher_hd_t *enc_c, gcry_cipher_hd_t *enc_cp,
+	gcry_md_hd_t *mac_m1, gcry_md_hd_t *mac_m1p,
+	gcry_md_hd_t *mac_m2, gcry_md_hd_t *mac_m2p);
+
+/*
+ * Compute the secure session id, given our DH key and their DH public
+ * key.
+ */
+gcry_error_t otrl_dh_compute_v1_session_id(const DH_keypair *our_dh,
+	gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp,
+	OtrlSessionIdHalf *halfp);
+
+/*
+ * Deallocate the contents of a DH_sesskeys (but not the DH_sesskeys
+ * itself)
+ */
+void otrl_dh_session_free(DH_sesskeys *sess);
+
+/*
+ * Blank out the contents of a DH_sesskeys (without releasing it)
+ */
+void otrl_dh_session_blank(DH_sesskeys *sess);
+
+/* Increment the top half of a counter block */
+void otrl_dh_incctr(unsigned char *ctr);
+
+/* Compare two counter values (8 bytes each).  Return 0 if ctr1 == ctr2,
+ * < 0 if ctr1 < ctr2 (as unsigned 64-bit values), > 0 if ctr1 > ctr2. */
+int otrl_dh_cmpctr(const unsigned char *ctr1, const unsigned char *ctr2);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/instag.c b/libotr/libotr-4.1.1/src/instag.c
new file mode 100644
index 0000000..cccd94f
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/instag.c
@@ -0,0 +1,277 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2015  Ian Goldberg, Rob Smits, Chris Alexander,
+ *  			      Willy Lew, Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdio.h>
+#include <stdlib.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "instag.h"
+#include "userstate.h"
+
+/* Forget the given instag. */
+void otrl_instag_forget(OtrlInsTag* instag) {
+    if (!instag) return;
+
+    if (instag->accountname) free(instag->accountname);
+    if (instag->protocol) free(instag->protocol);
+
+    /* Re-link the list */
+    *(instag->tous) = instag->next;
+    if (instag->next) {
+	instag->next->tous = instag->tous;
+    }
+
+    free(instag);
+}
+
+/* Forget all instags in a given OtrlUserState. */
+void otrl_instag_forget_all(OtrlUserState us) {
+    while(us->instag_root) {
+	otrl_instag_forget(us->instag_root);
+    }
+}
+
+/* Fetch the instance tag from the given OtrlUserState associated with
+ * the given account */
+OtrlInsTag * otrl_instag_find(OtrlUserState us, const char *accountname,
+	const char *protocol)
+{
+    OtrlInsTag *p;
+
+    for(p=us->instag_root; p; p=p->next) {
+	if (!strcmp(p->accountname, accountname) &&
+		!strcmp(p->protocol, protocol)) {
+	    return p;
+	}
+    }
+    return NULL;
+}
+
+/* Read our instance tag from a file on disk into the given
+ * OtrlUserState. */
+gcry_error_t otrl_instag_read(OtrlUserState us, const char *filename)
+{
+    gcry_error_t err;
+    FILE *instf;
+
+    /* Open the instance tag file. */
+    instf = fopen(filename, "rb");
+    if (!instf) {
+	return gcry_error_from_errno(errno);
+    }
+
+    err = otrl_instag_read_FILEp(us, instf);
+    fclose(instf);
+    return err;
+}
+
+/* Read our instance tag from a file on disk into the given
+ * OtrlUserState. The FILE* must be open for reading. */
+gcry_error_t otrl_instag_read_FILEp(OtrlUserState us, FILE *instf)
+{
+    if (!instf) return gcry_error(GPG_ERR_NO_ERROR);
+
+    OtrlInsTag *p;
+    char storeline[1000];
+    size_t maxsize = sizeof(storeline);
+
+    while(fgets(storeline, maxsize, instf)) {
+	char *prevpos;
+	char *pos;
+	unsigned int instag = 0;
+
+	p = malloc(sizeof(*p));
+	if (!p) {
+	    return gcry_error(GPG_ERR_ENOMEM);
+	}
+
+	/* Parse the line, which should be of the form:
+	 * accountname\tprotocol\t40_hex_nybbles\n          */
+	prevpos = storeline;
+	pos = strchr(prevpos, '\t');
+	if (!pos) {
+	    free(p);
+	    continue;
+	}
+	*pos = '\0';
+	pos++;
+	p->accountname = malloc(pos - prevpos);
+	if (!(p->accountname)) {
+	    free(p);
+	    return gcry_error(GPG_ERR_ENOMEM);
+	}
+	memmove(p->accountname, prevpos, pos - prevpos);
+
+	prevpos = pos;
+	pos = strchr(prevpos, '\t');
+	if (!pos) {
+	    free(p->accountname);
+	    free(p);
+	    continue;
+	}
+	*pos = '\0';
+	pos++;
+	p->protocol = malloc(pos - prevpos);
+	if (!(p->protocol)) {
+	    free(p->accountname);
+	    free(p);
+	    return gcry_error(GPG_ERR_ENOMEM);
+	}
+	memmove(p->protocol, prevpos, pos - prevpos);
+
+	prevpos = pos;
+	pos = strchr(prevpos, '\r');
+	if (!pos) pos = strchr(prevpos, '\n');
+	if (!pos) {
+	    free(p->accountname);
+	    free(p->protocol);
+	    free(p);
+	    continue;
+	}
+	*pos = '\0';
+	pos++;
+	/* hex str of length 8 */
+	if (strlen(prevpos) != 8) {
+	    free(p->accountname);
+	    free(p->protocol);
+	    free(p);
+	    continue;
+	}
+
+	sscanf(prevpos, "%08x", &instag);
+
+	if (instag < OTRL_MIN_VALID_INSTAG) {
+	    free(p->accountname);
+	    free(p->protocol);
+	    free(p);
+	    continue;
+	}
+	p->instag = instag;
+
+	/* Link it up */
+	p->next = us->instag_root;
+	if (p->next) {
+	    p->next->tous = &(p->next);
+	}
+	p->tous = &(us->instag_root);
+	us->instag_root = p;
+    }
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Generate a new instance tag for the given account and write to file */
+gcry_error_t otrl_instag_generate(OtrlUserState us, const char *filename,
+	const char *accountname, const char *protocol)
+{
+    gcry_error_t err;
+    FILE *instf;
+
+    /* Open the instance tag file. */
+    instf = fopen(filename, "wb");
+    if (!instf) {
+	return gcry_error_from_errno(errno);
+    }
+
+    err = otrl_instag_generate_FILEp(us, instf, accountname, protocol);
+    fclose(instf);
+    return err;
+}
+
+/* Return a new valid instance tag */
+otrl_instag_t otrl_instag_get_new()
+{
+    otrl_instag_t result = 0;
+
+    while(result < OTRL_MIN_VALID_INSTAG) {
+	otrl_instag_t * instag = (otrl_instag_t *)gcry_random_bytes(
+		sizeof(otrl_instag_t), GCRY_STRONG_RANDOM);
+	result = *instag;
+	gcry_free(instag);
+    }
+
+    return result;
+}
+
+/* Generate a new instance tag for the given account and write to file
+ * The FILE* must be open for writing. */
+gcry_error_t otrl_instag_generate_FILEp(OtrlUserState us, FILE *instf,
+	const char *accountname, const char *protocol)
+{
+    OtrlInsTag *p;
+    if (!accountname || !protocol) return gcry_error(GPG_ERR_NO_ERROR);
+
+    p = (OtrlInsTag *)malloc(sizeof(OtrlInsTag));
+    p->accountname = strdup(accountname);
+    p->protocol = strdup(protocol);
+
+    p->instag = otrl_instag_get_new();
+
+    /* Add to our list in OtrlUserState */
+    p->next = us->instag_root;
+    if (p->next) {
+	p->next->tous = &(p->next);
+    }
+    p->tous = &(us->instag_root);
+    us->instag_root = p;
+
+    otrl_instag_write_FILEp(us, instf);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Write our instance tags to a file on disk. */
+gcry_error_t otrl_instag_write(OtrlUserState us, const char *filename)
+{
+    gcry_error_t err;
+    FILE *instf;
+
+    /* Open the instance tag file. */
+    instf = fopen(filename, "wb");
+    if (!instf) {
+	return gcry_error_from_errno(errno);
+    }
+
+    err = otrl_instag_write_FILEp(us, instf);
+    fclose(instf);
+    return err;
+}
+
+/* Write our instance tags to a file on disk.
+ * The FILE* must be open for writing. */
+gcry_error_t otrl_instag_write_FILEp(OtrlUserState us, FILE *instf)
+{
+    OtrlInsTag *p;
+    /* This line should be ignored when read back in, since there are no
+    tabs. */
+    fprintf(instf, "# WARNING! You shouldn't copy this file to another"
+    " computer. It is unnecessary and can cause problems.\n");
+    for(p=us->instag_root; p; p=p->next) {
+	fprintf(instf, "%s\t%s\t%08x\n", p->accountname, p->protocol,
+		p->instag);
+    }
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
diff --git a/libotr/libotr-4.1.1/src/instag.h b/libotr/libotr-4.1.1/src/instag.h
new file mode 100644
index 0000000..c8aabb3
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/instag.h
@@ -0,0 +1,89 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Rob Smits, Chris Alexander,
+ *  			      Willy Lew, Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __INSTAG_H__
+#define __INSTAG_H__
+
+#include <stdio.h>
+#include <errno.h>
+
+#define OTRL_INSTAG_MASTER 0
+#define OTRL_INSTAG_BEST 1 /* Most secure, based on: conv status,
+			    * then fingerprint status, then most recent. */
+#define OTRL_INSTAG_RECENT 2
+#define OTRL_INSTAG_RECENT_RECEIVED 3
+#define OTRL_INSTAG_RECENT_SENT 4
+
+#define OTRL_MIN_VALID_INSTAG 0x100 /* Instag values below this are reserved
+				     * for meta instags, defined above, */
+
+typedef unsigned int otrl_instag_t;
+
+/* The list of instance tags used for our accounts */
+typedef struct s_OtrlInsTag {
+    struct s_OtrlInsTag *next;
+    struct s_OtrlInsTag **tous;
+
+    char *accountname;
+    char *protocol;
+    otrl_instag_t instag;
+} OtrlInsTag;
+
+#include "userstate.h"
+
+/* Forget the given instag. */
+void otrl_instag_forget(OtrlInsTag* instag);
+
+/* Forget all instags in a given OtrlUserState. */
+void otrl_instag_forget_all(OtrlUserState us);
+
+/* Fetch the instance tag from the given OtrlUserState associated with
+ * the given account */
+OtrlInsTag * otrl_instag_find(OtrlUserState us, const char *accountname,
+	const char *protocol);
+
+/* Read our instance tag from a file on disk into the given
+ * OtrlUserState. */
+gcry_error_t otrl_instag_read(OtrlUserState us, const char *filename);
+
+/* Read our instance tag from a file on disk into the given
+ * OtrlUserState. The FILE* must be open for reading. */
+gcry_error_t otrl_instag_read_FILEp(OtrlUserState us, FILE *instf);
+
+/* Return a new valid instance tag */
+otrl_instag_t otrl_instag_get_new();
+
+/* Get a new instance tag for the given account and write to file*/
+gcry_error_t otrl_instag_generate(OtrlUserState us, const char *filename,
+	const char *accountname, const char *protocol);
+
+/* Get a new instance tag for the given account and write to file
+ * The FILE* must be open for writing. */
+gcry_error_t otrl_instag_generate_FILEp(OtrlUserState us, FILE *instf,
+	const char *accountname, const char *protocol);
+
+/* Write our instance tags to a file on disk. */
+gcry_error_t otrl_instag_write(OtrlUserState us, const char *filename);
+
+/* Write our instance tags to a file on disk.
+ * The FILE* must be open for writing. */
+gcry_error_t otrl_instag_write_FILEp(OtrlUserState us, FILE *instf);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/mem.c b/libotr/libotr-4.1.1/src/mem.c
new file mode 100644
index 0000000..29330ae
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/mem.c
@@ -0,0 +1,180 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2014  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Memory allocation routines for libgcrypt.  All of the session key
+ * information gets allocated through here, so we can wipe it out when
+ * it's free()d.  We don't use the built-in secmem functions of
+ * libgcrypt because you need to declare a fixed amount of it when you
+ * start up.
+ *
+ * Because "secure" and "insecure" allocations from libgcrypt will get
+ * handled the same way (since we're not going to be running as root,
+ * and so won't actually have pinned memory), pretend all allocated
+ * memory (but just from libgcrypt) is requested secure, and wipe it on
+ * free(). */
+
+/* Uncomment the following to add a check that our free() and realloc() only
+ * get called on things returned from our malloc(). */
+/* #define OTRL_MEM_MAGIC 0x31415926 */
+
+/* system headers */
+#ifdef OTRL_MEM_MAGIC
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "mem.h"
+
+static size_t header_size;
+
+static void *otrl_mem_malloc(size_t n)
+{
+    void *p;
+    size_t new_n = n;
+    new_n += header_size;
+
+    /* Check for overflow attack */
+    if (new_n < n) return NULL;
+    p = malloc(new_n);
+    if (p == NULL) return NULL;
+
+    ((size_t *)p)[0] = new_n;  /* Includes header size */
+#ifdef OTRL_MEM_MAGIC
+    ((size_t *)p)[1] = OTRL_MEM_MAGIC;
+#endif
+
+    return (void *)((char *)p + header_size);
+}
+
+static int otrl_mem_is_secure(const void *p)
+{
+    return 1;
+}
+
+static void otrl_mem_free(void *p)
+{
+    void *real_p = (void *)((char *)p - header_size);
+    size_t n = ((size_t *)real_p)[0];
+#ifdef OTRL_MEM_MAGIC
+    if (((size_t *)real_p)[1] != OTRL_MEM_MAGIC) {
+	fprintf(stderr, "Illegal free!\n");
+	return;
+    }
+#endif
+
+    /* Wipe the memory (in the same way the built-in deallocator in
+     * libgcrypt would) */
+    memset(real_p, 0xff, n);
+    memset(real_p, 0xaa, n);
+    memset(real_p, 0x55, n);
+    memset(real_p, 0x00, n);
+
+    free(real_p);
+}
+
+static void *otrl_mem_realloc(void *p, size_t n)
+{
+    if (p == NULL) {
+	return otrl_mem_malloc(n);
+    } else if (n == 0) {
+	otrl_mem_free(p);
+	return NULL;
+    } else {
+	void *real_p = (void *)((char *)p - header_size);
+	void *new_p;
+	size_t old_n = ((size_t *)real_p)[0];
+#ifdef OTRL_MEM_MAGIC
+	size_t magic = ((size_t *)real_p)[1];
+#endif
+	size_t new_n = n;
+	new_n += header_size;
+
+	/* Check for overflow attack */
+	if (new_n < n) return NULL;
+
+#ifdef OTRL_MEM_MAGIC
+	if (magic != OTRL_MEM_MAGIC) {
+	    fprintf(stderr, "Illegal realloc!\n");
+	    return NULL;
+	}
+#endif
+
+	if (new_n < old_n) {
+	    /* Overwrite the space we're about to stop using */
+	    void *p = (void *)((char *)real_p + new_n);
+	    size_t excess = old_n - new_n;
+	    memset(p, 0xff, excess);
+	    memset(p, 0xaa, excess);
+	    memset(p, 0x55, excess);
+	    memset(p, 0x00, excess);
+
+	    /* We don't actually need to realloc() */
+	    new_p = real_p;
+	} else {
+	    new_p = realloc(real_p, new_n);
+	    if (new_p == NULL) return NULL;
+	}
+
+	((size_t *)new_p)[0] = new_n;  /* Includes header size */
+	return (void *)((char *)new_p + header_size);
+    }
+}
+
+void otrl_mem_init(void)
+{
+    header_size = 8;
+#ifdef OTRL_MEM_MAGIC
+    if (header_size < 2*sizeof(size_t)) {
+	header_size = 2*sizeof(size_t);
+    }
+#else
+    if (header_size < sizeof(size_t)) {
+	header_size = sizeof(size_t);
+    }
+#endif
+
+    gcry_set_allocation_handler(
+	    otrl_mem_malloc,
+	    otrl_mem_malloc,
+	    otrl_mem_is_secure,
+	    otrl_mem_realloc,
+	    otrl_mem_free
+	);
+}
+
+/* Compare two memory blocks in time dependent on the length of the
+ * blocks, but not their contents.  Returns 1 if they differ, 0 if they
+ * are the same. */
+int otrl_mem_differ(const unsigned char *buf1, const unsigned char *buf2,
+    size_t len)
+{
+    volatile unsigned char diff = 0;
+    size_t i;
+
+    for (i = 0; i < len; ++i) {
+        diff |= (buf1[i] ^ buf2[i]);
+    }
+    return (diff != 0);
+}
diff --git a/libotr/libotr-4.1.1/src/mem.h b/libotr/libotr-4.1.1/src/mem.h
new file mode 100644
index 0000000..2baf8f2
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/mem.h
@@ -0,0 +1,35 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2014  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __MEM_H__
+#define __MEM_H__
+
+#include <stdlib.h>
+
+void otrl_mem_init(void);
+
+/* Compare two memory blocks in time dependent on the length of the
+ * blocks, but not their contents.  Returns 1 if they differ, 0 if they
+ * are the same. */
+int otrl_mem_differ(const unsigned char *buf1, const unsigned char *buf2,
+    size_t len);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/message.c b/libotr/libotr-4.1.1/src/message.c
new file mode 100644
index 0000000..c44ce7b
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/message.c
@@ -0,0 +1,2058 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2015  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "privkey.h"
+#include "userstate.h"
+#include "proto.h"
+#include "auth.h"
+#include "message.h"
+#include "sm.h"
+#include "instag.h"
+
+#if OTRL_DEBUGGING
+#include <stdio.h>
+
+/* If OTRL_DEBUGGING is on, and the user types this string, the current
+ * context and its siblings will be dumped to stderr. */
+const char *OTRL_DEBUGGING_DEBUGSTR = "?OTR!";
+
+void otrl_context_all_dump(FILE *f, OtrlUserState us);
+void otrl_context_siblings_dump(FILE *f, const ConnContext *context);
+#endif
+
+/* The API version */
+extern unsigned int otrl_api_version;
+
+/* How long after sending a packet should we wait to send a heartbeat? */
+#define HEARTBEAT_INTERVAL 60
+
+/* How old are messages allowed to be in order to be candidates for
+ * resending in response to a rekey? */
+#define RESEND_INTERVAL 60
+
+/* How long should we wait for the last of the logged-in instances of
+ * our buddy to respond before marking our private key as a candidate
+ * for wiping (in seconds)? */
+#define MAX_AKE_WAIT_TIME 60
+
+/* How frequently should we check our ConnContexts for wipeable private
+ * keys (and wipe them) (in seconds)? */
+#define POLL_DEFAULT_INTERVAL 70
+
+/* Send a message to the network, fragmenting first if necessary.
+ * All messages to be sent to the network should go through this
+ * method immediately before they are sent, ie after encryption. */
+static gcry_error_t fragment_and_send(const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context, const char *message,
+	OtrlFragmentPolicy fragPolicy, char **returnFragment)
+{
+    int mms = 0;
+
+    if (message && ops->inject_message) {
+	int msglen;
+
+	if (ops->max_message_size) {
+	    mms = ops->max_message_size(opdata, context);
+	}
+	msglen = strlen(message);
+
+	/* Don't incur overhead of fragmentation unless necessary */
+	if(mms != 0 && msglen > mms) {
+	    char **fragments;
+	    gcry_error_t err;
+	    int i;
+	    int headerlen = context->protocol_version == 3 ? 37 : 19;
+	    /* Like ceil(msglen/(mms - headerlen)) */
+	    int fragment_count = ((msglen - 1) / (mms - headerlen)) + 1;
+
+	    err = otrl_proto_fragment_create(mms, fragment_count, &fragments,
+		    context, message);
+	    if (err) {
+		return err;
+	    }
+
+	    /* Determine which fragments to send and which to return
+	     * based on given Fragment Policy.  If the first fragment
+	     * should be returned instead of sent, store it. */
+	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_FIRST) {
+		*returnFragment = strdup(fragments[0]);
+	    } else {
+		ops->inject_message(opdata, context->accountname,
+			context->protocol, context->username, fragments[0]);
+	    }
+	    for (i=1; i<fragment_count-1; i++) {
+		ops->inject_message(opdata, context->accountname,
+			context->protocol, context->username, fragments[i]);
+	    }
+	    /* If the last fragment should be stored instead of sent,
+	     * store it */
+	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_LAST) {
+		*returnFragment = strdup(fragments[fragment_count-1]);
+	    } else {
+		ops->inject_message(opdata, context->accountname,
+			context->protocol, context->username,
+			fragments[fragment_count-1]);
+	    }
+	    /* Now free all fragment memory */
+	    otrl_proto_fragment_free(&fragments, fragment_count);
+
+	} else {
+	    /* No fragmentation necessary */
+	    if (fragPolicy == OTRL_FRAGMENT_SEND_ALL) {
+		ops->inject_message(opdata, context->accountname,
+			context->protocol, context->username, message);
+	    } else {
+		/* Copy and return the entire given message. */
+		*returnFragment = strdup(message);
+	    }
+	}
+    }
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+static void populate_context_instag(OtrlUserState us, const OtrlMessageAppOps
+	*ops, void *opdata, const char *accountname, const char *protocol,
+	ConnContext *context) {
+    OtrlInsTag *p_instag;
+
+    p_instag = otrl_instag_find(us, accountname, protocol);
+    if ((!p_instag) && ops->create_instag) {
+	ops->create_instag(opdata, accountname, protocol);
+	p_instag = otrl_instag_find(us, accountname, protocol);
+    }
+
+    if (p_instag && p_instag->instag >= OTRL_MIN_VALID_INSTAG) {
+	context->our_instance = p_instag->instag;
+    } else {
+	context->our_instance = otrl_instag_get_new();
+    }
+}
+
+/* Deallocate a message allocated by other otrl_message_* routines. */
+void otrl_message_free(char *message)
+{
+    free(message);
+}
+
+/* Handle a message about to be sent to the network.  It is safe to pass
+ * all messages about to be sent to this routine.  add_appdata is a
+ * function that will be called in the event that a new ConnContext is
+ * created.  It will be passed the data that you supplied, as well as a
+ * pointer to the new ConnContext.  You can use this to add
+ * application-specific information to the ConnContext using the
+ * "context->app" field, for example.  If you don't need to do this, you
+ * can pass NULL for the last two arguments of otrl_message_sending.
+ *
+ * tlvs is a chain of OtrlTLVs to append to the private message.  It is
+ * usually correct to just pass NULL here.
+ *
+ * If non-NULL, ops->convert_msg will be called just before encrypting a
+ * message.
+ *
+ * "instag" specifies the instance tag of the buddy (protocol version 3 only).
+ * Meta-instances may also be specified (e.g., OTRL_INSTAG_MOST_SECURE).
+ * If "contextp" is not NULL, it will be set to the ConnContext used for
+ * sending the message.
+ *
+ * If no fragmentation or msg injection is wanted, use OTRL_FRAGMENT_SEND_SKIP
+ * as the OtrlFragmentPolicy. In this case, this function will assign *messagep
+ * with the encrypted msg. If the routine returns non-zero, then the library
+ * tried to encrypt the message, but for some reason failed. DO NOT send the
+ * message in the clear in that case. If *messagep gets set by the call to
+ * something non-NULL, then you should replace your message with the contents
+ * of *messagep, and send that instead.
+ *
+ * Other fragmentation policies are OTRL_FRAGMENT_SEND_ALL,
+ * OTRL_FRAGMENT_SEND_ALL_BUT_LAST, or OTRL_FRAGMENT_SEND_ALL_BUT_FIRST. In
+ * these cases, the appropriate fragments will be automatically sent. For the
+ * last two policies, the remaining fragment will be passed in *original_msg.
+ *
+ * Call otrl_message_free(*messagep) if you don't need *messagep or when you're
+ * done with it. */
+gcry_error_t otrl_message_sending(OtrlUserState us,
+	const OtrlMessageAppOps *ops,
+	void *opdata, const char *accountname, const char *protocol,
+	const char *recipient, otrl_instag_t their_instag,
+	const char *original_msg, OtrlTLV *tlvs, char **messagep,
+	OtrlFragmentPolicy fragPolicy, ConnContext **contextp,
+	void (*add_appdata)(void *data, ConnContext *context),
+	void *data)
+{
+    ConnContext * context = NULL;
+    char * msgtosend;
+    const char * err_msg;
+    gcry_error_t err_code, err;
+    OtrlPolicy policy = OTRL_POLICY_DEFAULT;
+    int context_added = 0;
+    int convert_called = 0;
+    char *converted_msg = NULL;
+
+    if (messagep) {
+	*messagep = NULL;
+    }
+
+    err = gcry_error(GPG_ERR_NO_ERROR);	/* Default to no error */
+
+    if (contextp) {
+	*contextp = NULL;
+    }
+
+    if (!accountname || !protocol || !recipient ||
+		!original_msg || !messagep) {
+	err = gcry_error(GPG_ERR_INV_VALUE);
+	goto fragment;
+    }
+
+    /* See if we have a fingerprint for this user */
+    context = otrl_context_find(us, recipient, accountname, protocol,
+	    their_instag, 1, &context_added, add_appdata, data);
+
+    /* Update the context list if we added one */
+    if (context_added && ops->update_context_list) {
+	ops->update_context_list(opdata);
+    }
+
+    /* Find or generate the instance tag if needed */
+    if (!context->our_instance) {
+	populate_context_instag(us, ops, opdata, accountname, protocol,
+	    context);
+    }
+
+    if (contextp) {
+	*contextp = context;
+    }
+
+    /* Check the policy */
+    if (ops->policy) {
+	policy = ops->policy(opdata, context);
+    }
+
+    /* Should we go on at all? */
+    if ((policy & OTRL_POLICY_VERSION_MASK) == 0) {
+	err =  gcry_error(GPG_ERR_NO_ERROR);
+	goto fragment;
+    }
+
+#if OTRL_DEBUGGING
+    /* If the user typed the magic debug string, dump this context and
+     * its siblings. */
+    {
+	const char *debugtag = strstr(original_msg, OTRL_DEBUGGING_DEBUGSTR);
+
+	if (debugtag) {
+	    const char *debugargs =
+		debugtag + strlen(OTRL_DEBUGGING_DEBUGSTR);
+	    if (debugargs[0] == '!') { /* typed ?OTR!! */
+		otrl_context_all_dump(stderr, us);
+	    } else { /* typed ?OTR! without extra command chars */
+		otrl_context_siblings_dump(stderr, context);
+	    }
+
+	    /* Don't actually send the message */
+	    *messagep = strdup("");
+	    if (!(*messagep)) {
+		err = gcry_error(GPG_ERR_ENOMEM);
+	    }
+	    goto fragment;
+	}
+    }
+#endif
+
+    /* If this is an OTR Query message, don't encrypt it. */
+    if (otrl_proto_message_type(original_msg) == OTRL_MSGTYPE_QUERY) {
+	/* Replace the "?OTR?" with a custom message */
+	char *bettermsg = otrl_proto_default_query_msg(accountname, policy);
+	if (bettermsg) {
+	    *messagep = bettermsg;
+	}
+	context->otr_offer = OFFER_SENT;
+	err = gcry_error(GPG_ERR_NO_ERROR);
+	goto fragment;
+    }
+
+    /* What is the current message disposition? */
+    switch(context->msgstate) {
+
+	case OTRL_MSGSTATE_PLAINTEXT:
+	    if ((policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) {
+		/* We're trying to send an unencrypted message with a policy
+		 * that disallows that.  Don't do that, but try to start
+		 * up OTR instead. */
+		if (ops->handle_msg_event) {
+		    ops->handle_msg_event(opdata,
+			    OTRL_MSGEVENT_ENCRYPTION_REQUIRED,
+			    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
+		}
+
+		context->context_priv->lastmessage =
+			gcry_malloc_secure(strlen(original_msg) + 1);
+		if (context->context_priv->lastmessage) {
+		    char *bettermsg = otrl_proto_default_query_msg(accountname,
+			    policy);
+		    strcpy(context->context_priv->lastmessage, original_msg);
+		    context->context_priv->lastsent = time(NULL);
+		    otrl_context_update_recent_child(context, 1);
+		    context->context_priv->may_retransmit = 2;
+		    if (bettermsg) {
+			*messagep = bettermsg;
+			context->otr_offer = OFFER_SENT;
+		    } else {
+			err = gcry_error(GPG_ERR_ENOMEM);
+			goto fragment;
+		    }
+		}
+	    } else {
+		if ((policy & OTRL_POLICY_SEND_WHITESPACE_TAG) &&
+			context->otr_offer != OFFER_REJECTED) {
+		    /* See if this user can speak OTR.  Append the
+		     * OTR_MESSAGE_TAG to the plaintext message, and see
+		     * if he responds. */
+		    size_t msglen = strlen(original_msg);
+		    size_t basetaglen = strlen(OTRL_MESSAGE_TAG_BASE);
+		    size_t v1taglen = (policy & OTRL_POLICY_ALLOW_V1) ?
+			strlen(OTRL_MESSAGE_TAG_V1) : 0;
+		    size_t v2taglen = (policy & OTRL_POLICY_ALLOW_V2) ?
+			strlen(OTRL_MESSAGE_TAG_V2) : 0;
+		    size_t v3taglen = (policy & OTRL_POLICY_ALLOW_V3) ?
+			strlen(OTRL_MESSAGE_TAG_V3) : 0;
+		    char *taggedmsg = malloc(msglen + basetaglen + v1taglen
+			    + v2taglen + v3taglen + 1);
+		    if (taggedmsg) {
+			strcpy(taggedmsg, original_msg);
+			strcpy(taggedmsg + msglen, OTRL_MESSAGE_TAG_BASE);
+			if (v1taglen) {
+			    strcpy(taggedmsg + msglen + basetaglen,
+				    OTRL_MESSAGE_TAG_V1);
+			}
+			if (v2taglen) {
+			    strcpy(taggedmsg + msglen + basetaglen + v1taglen,
+				    OTRL_MESSAGE_TAG_V2);
+			}
+			if (v3taglen) {
+			    strcpy(taggedmsg + msglen + basetaglen + v1taglen
+				    + v2taglen, OTRL_MESSAGE_TAG_V3);
+			}
+			*messagep = taggedmsg;
+			context->otr_offer = OFFER_SENT;
+		    }
+		}
+	    }
+	    break;
+	case OTRL_MSGSTATE_ENCRYPTED:
+	    /* convert the original message if necessary */
+	    if (ops->convert_msg) {
+		ops->convert_msg(opdata, context, OTRL_CONVERT_SENDING,
+			&converted_msg, original_msg);
+
+		if (converted_msg) {
+		    convert_called = 1;
+		}
+	    }
+
+	    /* Create the new, encrypted message */
+	    if (convert_called) {
+		err_code = otrl_proto_create_data(&msgtosend, context,
+			converted_msg, tlvs, 0, NULL);
+
+		if (ops->convert_free) {
+		    ops->convert_free(opdata, context, converted_msg);
+		    converted_msg = NULL;
+		}
+	    } else {
+		err_code = otrl_proto_create_data(&msgtosend, context,
+			original_msg, tlvs, 0, NULL);
+	    }
+	    if (!err_code) {
+		context->context_priv->lastsent = time(NULL);
+		otrl_context_update_recent_child(context, 1);
+		*messagep = msgtosend;
+	    } else {
+		/* Uh, oh.  Whatever we do, *don't* send the message in the
+		 * clear. */
+		if (ops->handle_msg_event) {
+		    ops->handle_msg_event(opdata,
+			    OTRL_MSGEVENT_ENCRYPTION_ERROR,
+			    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
+		}
+		if (ops->otr_error_message) {
+		    err_msg = ops->otr_error_message(opdata, context,
+			OTRL_ERRCODE_ENCRYPTION_ERROR);
+		    *messagep = malloc(strlen(OTR_ERROR_PREFIX) +
+			strlen(err_msg) + 1);
+		    if (*messagep) {
+			strcpy(*messagep, OTR_ERROR_PREFIX);
+			strcat(*messagep, err_msg);
+		    }
+		    if (ops->otr_error_message_free) {
+			ops->otr_error_message_free(opdata, err_msg);
+		    }
+		    if (!(*messagep)) {
+			err = gcry_error(GPG_ERR_ENOMEM);
+			goto fragment;
+		    }
+		}
+	    }
+	    break;
+	case OTRL_MSGSTATE_FINISHED:
+	    if (ops->handle_msg_event) {
+		ops->handle_msg_event(opdata, OTRL_MSGEVENT_CONNECTION_ENDED,
+		    context, NULL, gcry_error(GPG_ERR_NO_ERROR));
+	    }
+	    *messagep = strdup("");
+	    if (!(*messagep)) {
+		err = gcry_error(GPG_ERR_ENOMEM);
+		goto fragment;
+	    }
+	    break;
+    }
+
+fragment:
+    if (fragPolicy == OTRL_FRAGMENT_SEND_SKIP ) {
+	/* Do not fragment/inject. Default behaviour of libotr3.2.0 */
+	return err;
+    } else {
+	/* Fragment and send according to policy */
+	if (!err && messagep && *messagep) {
+	    if (context) {
+		char *rmessagep = NULL;
+		err = fragment_and_send(ops, opdata, context, *messagep,
+					fragPolicy, &rmessagep);
+		if (rmessagep) {
+		    /* Free the current message pointer and return back the
+		     * returned fragmented one. */
+		    free(*messagep);
+		    *messagep = rmessagep;
+		}
+	    }
+	}
+	return err;
+    }
+}
+
+/* If err == 0, send the last auth message for the given context to the
+ * appropriate user.  Otherwise, display an appripriate error dialog.
+ * Return the value of err that was passed. */
+static gcry_error_t send_or_error_auth(const OtrlMessageAppOps *ops,
+	void *opdata, gcry_error_t err, ConnContext *context,
+	OtrlUserState us)
+{
+    if (!err) {
+	const char *msg = context->auth.lastauthmsg;
+	if (msg && *msg) {
+	    fragment_and_send(ops, opdata, context, msg,
+		    OTRL_FRAGMENT_SEND_ALL, NULL);
+	    time_t now = time(NULL);
+	    /* Update the "last sent" fields, unless this is a version 3
+	     * message typing to update the master context (as happens
+	     * when sending a v3 COMMIT message, for example). */
+	    if (context != context->m_context ||
+		    context->auth.protocol_version != 3) {
+		context->context_priv->lastsent = now;
+		otrl_context_update_recent_child(context, 1);
+	    }
+
+	    /* If this is a master context, and we're sending a v3 COMMIT
+	     * message, update the commit_sent_time timestamp, so we can
+	     * expire it. */
+	    if (context == context->m_context &&
+		    context->auth.authstate == OTRL_AUTHSTATE_AWAITING_DHKEY &&
+		    context->auth.protocol_version == 3) {
+		context->auth.commit_sent_time = now;
+		/* If there's not already a timer running to clean up
+		 * this private key, try to start one. */
+		if (us->timer_running == 0 && ops && ops->timer_control) {
+		    ops->timer_control(opdata, POLL_DEFAULT_INTERVAL);
+		    us->timer_running = 1;
+		}
+	    }
+	}
+    } else {
+	if (ops->handle_msg_event) {
+	    ops->handle_msg_event(opdata, OTRL_MSGEVENT_SETUP_ERROR,
+		    context, NULL, err);
+	}
+    }
+    return err;
+}
+
+typedef struct {
+    int gone_encrypted;
+    OtrlUserState us;
+    const OtrlMessageAppOps *ops;
+    void *opdata;
+    ConnContext *context;
+    int ignore_message;
+    char **messagep;
+} EncrData;
+
+static gcry_error_t go_encrypted(const OtrlAuthInfo *auth, void *asdata)
+{
+    EncrData *edata = asdata;
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+    Fingerprint *found_print = NULL;
+    int fprint_added = 0;
+    OtrlMessageState oldstate = edata->context->msgstate;
+    Fingerprint *oldprint = edata->context->active_fingerprint;
+
+    /* See if we're talking to ourselves */
+    if (!gcry_mpi_cmp(auth->their_pub, auth->our_dh.pub)) {
+	/* Yes, we are. */
+	if (edata->ops->handle_msg_event) {
+	    edata->ops->handle_msg_event(edata->opdata,
+		    OTRL_MSGEVENT_MSG_REFLECTED, edata->context,
+		    NULL, gcry_error(GPG_ERR_NO_ERROR));
+	}
+	edata->ignore_message = 1;
+	return gcry_error(GPG_ERR_NO_ERROR);
+    }
+
+    found_print = otrl_context_find_fingerprint(edata->context,
+	    edata->context->auth.their_fingerprint, 1, &fprint_added);
+
+    if (fprint_added) {
+	/* Inform the user of the new fingerprint */
+	if (edata->ops->new_fingerprint) {
+	    edata->ops->new_fingerprint(edata->opdata, edata->us,
+		    edata->context->accountname, edata->context->protocol,
+		    edata->context->username,
+		    edata->context->auth.their_fingerprint);
+	}
+	/* Arrange that the new fingerprint be written to disk */
+	if (edata->ops->write_fingerprints) {
+	    edata->ops->write_fingerprints(edata->opdata);
+	}
+    }
+
+    /* Is this a new session or just a refresh of an existing one? */
+    if (edata->context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+	    oldprint == found_print &&
+	    edata->context->context_priv->our_keyid - 1 ==
+	    edata->context->auth.our_keyid &&
+	    !gcry_mpi_cmp(edata->context->context_priv->our_old_dh_key.pub,
+		edata->context->auth.our_dh.pub) &&
+	    ((edata->context->context_priv->their_keyid > 0 &&
+	      edata->context->context_priv->their_keyid ==
+		    edata->context->auth.their_keyid &&
+	      !gcry_mpi_cmp(edata->context->context_priv->their_y,
+		  edata->context->auth.their_pub)) ||
+	    (edata->context->context_priv->their_keyid > 1 &&
+	     edata->context->context_priv->their_keyid - 1 ==
+		    edata->context->auth.their_keyid &&
+	     edata->context->context_priv->their_old_y != NULL &&
+	     !gcry_mpi_cmp(edata->context->context_priv->their_old_y,
+		 edata->context->auth.their_pub)))) {
+	/* This is just a refresh of the existing session. */
+	if (edata->ops->still_secure) {
+	    edata->ops->still_secure(edata->opdata, edata->context,
+		    edata->context->auth.initiated);
+	}
+	edata->ignore_message = 1;
+	return gcry_error(GPG_ERR_NO_ERROR);
+    }
+
+    /* Copy the information from the auth into the context */
+    memmove(edata->context->sessionid,
+	    edata->context->auth.secure_session_id, 20);
+    edata->context->sessionid_len =
+	    edata->context->auth.secure_session_id_len;
+    edata->context->sessionid_half =
+	    edata->context->auth.session_id_half;
+    edata->context->protocol_version =
+	    edata->context->auth.protocol_version;
+
+    edata->context->context_priv->their_keyid =
+	    edata->context->auth.their_keyid;
+    gcry_mpi_release(edata->context->context_priv->their_y);
+    gcry_mpi_release(edata->context->context_priv->their_old_y);
+    edata->context->context_priv->their_y =
+	    gcry_mpi_copy(edata->context->auth.their_pub);
+    edata->context->context_priv->their_old_y = NULL;
+
+    if (edata->context->context_priv->our_keyid - 1 !=
+	edata->context->auth.our_keyid ||
+	gcry_mpi_cmp(edata->context->context_priv->our_old_dh_key.pub,
+		edata->context->auth.our_dh.pub)) {
+	otrl_dh_keypair_free(&(edata->context->context_priv->our_dh_key));
+	otrl_dh_keypair_free(&(edata->context->context_priv->our_old_dh_key));
+	otrl_dh_keypair_copy(&(edata->context->context_priv->our_old_dh_key),
+		&(edata->context->auth.our_dh));
+	otrl_dh_gen_keypair(
+		edata->context->context_priv->our_old_dh_key.groupid,
+		&(edata->context->context_priv->our_dh_key));
+	edata->context->context_priv->our_keyid = edata->context->auth.our_keyid
+		+ 1;
+    }
+
+    /* Create the session keys from the DH keys */
+    otrl_dh_session_free(&(edata->context->context_priv->sesskeys[0][0]));
+    err = otrl_dh_session(&(edata->context->context_priv->sesskeys[0][0]),
+	    &(edata->context->context_priv->our_dh_key),
+	    edata->context->context_priv->their_y);
+    if (err) return err;
+    otrl_dh_session_free(&(edata->context->context_priv->sesskeys[1][0]));
+    err = otrl_dh_session(&(edata->context->context_priv->sesskeys[1][0]),
+	    &(edata->context->context_priv->our_old_dh_key),
+	    edata->context->context_priv->their_y);
+    if (err) return err;
+
+    edata->context->context_priv->generation++;
+    edata->context->active_fingerprint = found_print;
+    edata->context->msgstate = OTRL_MSGSTATE_ENCRYPTED;
+
+    if (edata->ops->update_context_list) {
+	edata->ops->update_context_list(edata->opdata);
+    }
+    if (oldstate == OTRL_MSGSTATE_ENCRYPTED && oldprint == found_print) {
+	if (edata->ops->still_secure) {
+	    edata->ops->still_secure(edata->opdata, edata->context,
+		    edata->context->auth.initiated);
+	}
+    } else {
+	if (edata->ops->gone_secure) {
+	    edata->ops->gone_secure(edata->opdata, edata->context);
+	}
+    }
+
+    edata->gone_encrypted = 1;
+
+    return gpg_error(GPG_ERR_NO_ERROR);
+}
+
+static void maybe_resend(EncrData *edata)
+{
+    gcry_error_t err;
+    time_t now;
+
+    if (!edata->gone_encrypted) return;
+
+    /* See if there's a message we sent recently that should be resent. */
+    now = time(NULL);
+    if (edata->context->context_priv->lastmessage != NULL &&
+	    edata->context->context_priv->may_retransmit &&
+	    edata->context->context_priv->lastsent >= (now - RESEND_INTERVAL)) {
+	char *resendmsg;
+	char *msg_to_send;
+	int resending = (edata->context->context_priv->may_retransmit == 1);
+
+	/* Initialize msg_to_send */
+	if (resending) {
+	    const char *resent_prefix;
+	    int used_ops_resentmp = 1;
+	    resent_prefix = edata->ops->resent_msg_prefix ?
+				    edata->ops->resent_msg_prefix(edata->opdata,
+				    edata->context) : NULL;
+	    if (!resent_prefix) {
+		resent_prefix = "[resent]"; /* Assign default prefix */
+		used_ops_resentmp = 0;
+	    }
+	    msg_to_send = malloc(
+		    strlen(edata->context->context_priv->lastmessage) +
+		    strlen(resent_prefix) + 2);
+	    if (msg_to_send) {
+		strcpy(msg_to_send, resent_prefix);
+		strcat(msg_to_send, " ");
+		strcat(msg_to_send, edata->context->context_priv->lastmessage);
+	    } else {
+		return;  /* Out of memory; don't try to resend */
+	    }
+	    if (used_ops_resentmp) {
+		edata->ops->resent_msg_prefix_free(edata->opdata,
+			resent_prefix);
+	    }
+	} else {
+	    msg_to_send = edata->context->context_priv->lastmessage;
+	}
+
+	/* Re-encrypt the message with the new keys */
+	err = otrl_proto_create_data(&resendmsg,
+		edata->context, msg_to_send, NULL, 0, NULL);
+	if (resending) {
+		free(msg_to_send);
+	}
+	if (!err) {
+	    /* Resend the message */
+	    fragment_and_send(edata->ops, edata->opdata, edata->context,
+		    resendmsg, OTRL_FRAGMENT_SEND_ALL, NULL);
+	    free(resendmsg);
+	    edata->context->context_priv->lastsent = now;
+	    otrl_context_update_recent_child(edata->context, 1);
+	    if (resending) {
+		/* We're not sending it for the first time; let the user
+		 * know we resent it */
+		if (edata->ops->handle_msg_event) {
+		    edata->ops->handle_msg_event(edata->opdata,
+			    OTRL_MSGEVENT_MSG_RESENT, edata->context,
+			    NULL, gcry_error(GPG_ERR_NO_ERROR));
+		}
+	    }
+	    edata->ignore_message = 1;
+	}
+    }
+}
+
+/* Set the trust level based on the result of the SMP */
+static void set_smp_trust(const OtrlMessageAppOps *ops, void *opdata,
+	ConnContext *context, int trusted)
+{
+    otrl_context_set_trust(context->active_fingerprint, trusted ? "smp" : "");
+
+    /* Write the new info to disk, redraw the ui, and redraw the
+     * OTR buttons. */
+    if (ops->write_fingerprints) {
+	ops->write_fingerprints(opdata);
+    }
+}
+
+static void init_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context, const char *question,
+	const unsigned char *secret, size_t secretlen, int initiating)
+{
+    unsigned char *smpmsg = NULL;
+    int smpmsglen;
+    unsigned char combined_secret[SM_DIGEST_SIZE];
+    gcry_error_t err;
+    unsigned char our_fp[20];
+    unsigned char *combined_buf;
+    size_t combined_buf_len;
+    OtrlTLV *sendtlv;
+    char *sendsmp = NULL;
+
+    if (!context || context->msgstate != OTRL_MSGSTATE_ENCRYPTED) return;
+
+    /*
+     * Construct the combined secret as a SHA256 hash of:
+     * Version byte (0x01), Initiator fingerprint (20 bytes),
+     * responder fingerprint (20 bytes), secure session id, input secret
+     */
+    otrl_privkey_fingerprint_raw(us, our_fp, context->accountname,
+	    context->protocol);
+
+    combined_buf_len = 41 + context->sessionid_len + secretlen;
+    combined_buf = malloc(combined_buf_len);
+    combined_buf[0] = 0x01;
+    if (initiating) {
+	memmove(combined_buf + 1, our_fp, 20);
+	memmove(combined_buf + 21,
+		context->active_fingerprint->fingerprint, 20);
+    } else {
+	memmove(combined_buf + 1,
+		context->active_fingerprint->fingerprint, 20);
+	memmove(combined_buf + 21, our_fp, 20);
+    }
+    memmove(combined_buf + 41, context->sessionid,
+	    context->sessionid_len);
+    memmove(combined_buf + 41 + context->sessionid_len,
+	    secret, secretlen);
+    gcry_md_hash_buffer(SM_HASH_ALGORITHM, combined_secret, combined_buf,
+	    combined_buf_len);
+    free(combined_buf);
+
+    if (initiating) {
+	otrl_sm_step1(context->smstate, combined_secret, SM_DIGEST_SIZE,
+		&smpmsg, &smpmsglen);
+    } else {
+	otrl_sm_step2b(context->smstate, combined_secret, SM_DIGEST_SIZE,
+		&smpmsg, &smpmsglen);
+    }
+
+    /* If we've got a question, attach it to the smpmsg */
+    if (question != NULL) {
+	size_t qlen = strlen(question);
+	unsigned char *qsmpmsg = malloc(qlen + 1 + smpmsglen);
+	if (!qsmpmsg) {
+	    free(smpmsg);
+	    return;
+	}
+	strcpy((char *)qsmpmsg, question);
+	memmove(qsmpmsg + qlen + 1, smpmsg, smpmsglen);
+	free(smpmsg);
+	smpmsg = qsmpmsg;
+	smpmsglen += qlen + 1;
+    }
+
+    /* Send msg with next smp msg content */
+    sendtlv = otrl_tlv_new(initiating ?
+	    (question != NULL ? OTRL_TLV_SMP1Q : OTRL_TLV_SMP1)
+	    : OTRL_TLV_SMP2,
+	    smpmsglen, smpmsg);
+    err = otrl_proto_create_data(&sendsmp, context, "", sendtlv,
+	    OTRL_MSGFLAGS_IGNORE_UNREADABLE, NULL);
+    if (!err) {
+	/*  Send it, and set the next expected message to the
+	 *  logical response */
+	err = fragment_and_send(ops, opdata, context,
+		sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL);
+	context->smstate->nextExpected =
+		initiating ? OTRL_SMP_EXPECT2 : OTRL_SMP_EXPECT3;
+    }
+    free(sendsmp);
+    otrl_tlv_free(sendtlv);
+    free(smpmsg);
+}
+
+/* Initiate the Socialist Millionaires' Protocol */
+void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context, const unsigned char *secret,
+	size_t secretlen)
+{
+    init_respond_smp(us, ops, opdata, context, NULL, secret, secretlen, 1);
+}
+
+/* Initiate the Socialist Millionaires' Protocol and send a prompt
+ * question to the buddy */
+void otrl_message_initiate_smp_q(OtrlUserState us,
+	const OtrlMessageAppOps *ops, void *opdata, ConnContext *context,
+	const char *question, const unsigned char *secret, size_t secretlen)
+{
+    init_respond_smp(us, ops, opdata, context, question, secret, secretlen, 1);
+}
+
+/* Respond to a buddy initiating the Socialist Millionaires' Protocol */
+void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context, const unsigned char *secret,
+	size_t secretlen)
+{
+    init_respond_smp(us, ops, opdata, context, NULL, secret, secretlen, 0);
+}
+
+/* Abort the SMP.  Called when an unexpected SMP message breaks the
+ * normal flow. */
+void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context)
+{
+    OtrlTLV *sendtlv = otrl_tlv_new(OTRL_TLV_SMP_ABORT, 0,
+	    (const unsigned char *)"");
+    char *sendsmp = NULL;
+    gcry_error_t err;
+
+    context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+
+    err = otrl_proto_create_data(&sendsmp,
+	    context, "", sendtlv,
+	    OTRL_MSGFLAGS_IGNORE_UNREADABLE, NULL);
+    if (!err) {
+	/* Send the abort signal so our buddy knows we've stopped */
+	err = fragment_and_send(ops, opdata, context,
+		sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL);
+    }
+    free(sendsmp);
+    otrl_tlv_free(sendtlv);
+}
+
+static void message_malformed(const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context) {
+    if (ops->handle_msg_event) {
+	ops->handle_msg_event(opdata, OTRL_MSGEVENT_RCVDMSG_MALFORMED, context,
+	    NULL, gcry_error(GPG_ERR_NO_ERROR));
+    }
+
+    if (ops->inject_message && ops->otr_error_message) {
+	const char *err_msg = ops->otr_error_message(opdata, context,
+		OTRL_ERRCODE_MSG_MALFORMED);
+
+	if (err_msg) {
+	    char *buf = malloc(strlen(OTR_ERROR_PREFIX) + strlen(err_msg) + 1);
+
+	    if (buf) {
+		strcpy(buf, OTR_ERROR_PREFIX);
+		strcat(buf, err_msg);
+		ops->inject_message(opdata, context->accountname,
+			context->protocol, context->username, buf);
+		free(buf);
+	    }
+
+	    if (ops->otr_error_message_free) {
+		ops->otr_error_message_free(opdata, err_msg);
+	    }
+	}
+    }
+}
+
+
+/* Handle a message just received from the network.  It is safe to pass
+ * all received messages to this routine.  add_appdata is a function
+ * that will be called in the event that a new ConnContext is created.
+ * It will be passed the data that you supplied, as well as
+ * a pointer to the new ConnContext.  You can use this to add
+ * application-specific information to the ConnContext using the
+ * "context->app" field, for example.  If you don't need to do this, you
+ * can pass NULL for the last two arguments of otrl_message_receiving.
+ *
+ * If non-NULL, ops->convert_msg will be called after a data message is
+ * decrypted.
+ *
+ * If "contextp" is not NULL, it will be set to the ConnContext used for
+ * receiving the message.
+ *
+ * If otrl_message_receiving returns 1, then the message you received
+ * was an internal protocol message, and no message should be delivered
+ * to the user.
+ *
+ * If it returns 0, then check if *messagep was set to non-NULL.  If
+ * so, replace the received message with the contents of *messagep, and
+ * deliver that to the user instead.  You must call
+ * otrl_message_free(*messagep) when you're done with it.  If tlvsp is
+ * non-NULL, *tlvsp will be set to a chain of any TLVs that were
+ * transmitted along with this message.  You must call
+ * otrl_tlv_free(*tlvsp) when you're done with those.
+ *
+ * If otrl_message_receiving returns 0 and *messagep is NULL, then this
+ * was an ordinary, non-OTR message, which should just be delivered to
+ * the user without modification. */
+int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, const char *accountname, const char *protocol,
+	const char *sender, const char *message, char **newmessagep,
+	OtrlTLV **tlvsp, ConnContext **contextp,
+	void (*add_appdata)(void *data, ConnContext *context),
+	void *data)
+{
+    ConnContext *context, *m_context, *best_context;
+    OtrlMessageType msgtype;
+    int context_added = 0;
+    OtrlPolicy policy = OTRL_POLICY_DEFAULT;
+    char *unfragmessage = NULL, *otrtag = NULL;
+    EncrData edata;
+    otrl_instag_t our_instance = 0, their_instance = 0;
+    int version;
+    gcry_error_t err;
+
+    if (!accountname || !protocol || !sender || !message || !newmessagep)
+	return 0;
+
+    *newmessagep = NULL;
+    if (tlvsp) *tlvsp = NULL;
+
+    if (contextp) {
+	*contextp = NULL;
+    }
+
+    /* Find the master context and state with this correspondent */
+    m_context = otrl_context_find(us, sender, accountname,
+	    protocol, OTRL_INSTAG_MASTER, 1, &context_added, add_appdata, data);
+    context = m_context;
+
+    /* Update the context list if we added one */
+    if (context_added && ops->update_context_list) {
+	ops->update_context_list(opdata);
+    }
+
+    best_context = otrl_context_find(us, sender, accountname,
+	    protocol, OTRL_INSTAG_BEST, 0, NULL, add_appdata, data);
+
+    /* Find or generate the instance tag if needed */
+    if (!context->our_instance) {
+	populate_context_instag(us, ops, opdata, accountname, protocol,
+		context);
+    }
+
+
+    /* Check the policy */
+    if (ops->policy) {
+	policy = ops->policy(opdata, context);
+    }
+
+    /* Should we go on at all? */
+    if ((policy & OTRL_POLICY_VERSION_MASK) == 0) {
+	return 0;
+    }
+
+    otrtag = strstr(message, "?OTR");
+    if (otrtag) {
+	/* See if we have a V3 fragment.  The '4' in the next line is
+	 * strlen("?OTR").  otrtag[4] is the character immediately after
+	 * the "?OTR", and is guaranteed to exist, because in the worst
+	 * case, it is the NUL terminating 'message'. */
+	if (otrtag[4] == '|') {
+	    /* Get the instance tag from fragment header*/
+	    sscanf(otrtag, "?OTR|%x|%x,", &their_instance, &our_instance);
+	    /* Ignore message if it is intended for a different instance */
+	    if (our_instance && context->our_instance != our_instance) {
+
+		    if (ops->handle_msg_event) {
+			ops->handle_msg_event(opdata,
+				OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE,
+				m_context, NULL, gcry_error(GPG_ERR_NO_ERROR));
+		    }
+		    return 1;
+	    }
+	    /* Get the context for this instance */
+	    if (their_instance >= OTRL_MIN_VALID_INSTAG) {
+		context = otrl_context_find(us, sender, accountname,
+			protocol, their_instance, 1, &context_added,
+			add_appdata, data);
+	    } else {
+		message_malformed(ops, opdata, context);
+		return 1;
+	    }
+	}
+	switch(otrl_proto_fragment_accumulate(&unfragmessage,
+		context, message)) {
+	    case OTRL_FRAGMENT_UNFRAGMENTED:
+		/* Do nothing */
+		break;
+	    case OTRL_FRAGMENT_INCOMPLETE:
+		/* We've accumulated this fragment, but we don't have a
+		 * complete message yet */
+		return 1;
+	    case OTRL_FRAGMENT_COMPLETE:
+		/* We've got a new complete message, in unfragmessage. */
+		message = unfragmessage;
+		otrtag = strstr(message, "?OTR");
+		break;
+	}
+    }
+
+    /* What type of message is it?  Note that this just checks the
+     * header; it's not necessarily a _valid_ message of this type. */
+    msgtype = otrl_proto_message_type(message);
+    version = otrl_proto_message_version(message);
+
+    /* See if they responded to our OTR offer */
+    if ((policy & OTRL_POLICY_SEND_WHITESPACE_TAG)) {
+	if (msgtype != OTRL_MSGTYPE_NOTOTR) {
+	    context->otr_offer = OFFER_ACCEPTED;
+	} else if (context->otr_offer == OFFER_SENT) {
+	    context->otr_offer = OFFER_REJECTED;
+	}
+    }
+
+    /* Check that this version is allowed by the policy */
+    if (((version == 3) && !(policy & OTRL_POLICY_ALLOW_V3))
+	|| ((version == 2) && !(policy & OTRL_POLICY_ALLOW_V2))
+	|| ((version == 1) && !(policy & OTRL_POLICY_ALLOW_V1))) {
+	    edata.ignore_message = 1;
+	    goto end;
+    }
+    /* Check the to and from instance tags */
+    if (version == 3) {
+	err = gcry_error(GPG_ERR_INV_VALUE);
+	if (otrtag) {
+	    err = otrl_proto_instance(otrtag, &their_instance, &our_instance);
+	}
+	if (!err) {
+	    if ((msgtype == OTRL_MSGTYPE_DH_COMMIT && our_instance &&
+		    context->our_instance != our_instance) ||
+		    (msgtype != OTRL_MSGTYPE_DH_COMMIT &&
+		    context->our_instance != our_instance)) {
+		if (ops->handle_msg_event) {
+		    ops->handle_msg_event(opdata,
+			    OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE,
+			    m_context, NULL, gcry_error(GPG_ERR_NO_ERROR));
+		}
+		/* ignore message intended for a different instance */
+		edata.ignore_message = 1;
+		goto end;
+	    }
+
+	    if (their_instance >= OTRL_MIN_VALID_INSTAG) {
+		context = otrl_context_find(us, sender, accountname,
+			protocol, their_instance, 1, &context_added,
+			add_appdata, data);
+	    }
+	}
+
+	if (err || their_instance < OTRL_MIN_VALID_INSTAG) {
+	    message_malformed(ops, opdata, context);
+	    edata.ignore_message = 1;
+	    goto end;
+	}
+
+	if (context_added) {
+	    /* Context added because of new instance (either here or when
+	     * accumulating fragments */
+	    /* Copy information from m_context to the new instance context */
+	    context->auth.protocol_version = 3;
+	    context->protocol_version = 3;
+	    context->msgstate = m_context->msgstate;
+
+	    if (m_context->context_priv->may_retransmit) {
+		gcry_free(context->context_priv->lastmessage);
+		context->context_priv->lastmessage = m_context->context_priv->lastmessage;
+		m_context->context_priv->lastmessage = NULL;
+		context->context_priv->may_retransmit = m_context->context_priv->may_retransmit;
+		m_context->context_priv->may_retransmit = 0;
+	    }
+
+	    if (msgtype == OTRL_MSGTYPE_DH_KEY) {
+		otrl_auth_copy_on_key(&(m_context->auth), &(context->auth));
+	    } else if (msgtype != OTRL_MSGTYPE_DH_COMMIT) {
+		edata.ignore_message = 1;
+		goto end;
+	    }
+
+	    /* Update the context list */
+	    if (ops->update_context_list) {
+		ops->update_context_list(opdata);
+	    }
+	} else if (m_context != context) {
+	    /* Switching from m_context to existing instance context */
+	    if (msgtype == OTRL_MSGTYPE_DH_KEY && m_context->auth.authstate
+		    == OTRL_AUTHSTATE_AWAITING_DHKEY &&
+		    !(context->auth.authstate ==
+		    OTRL_AUTHSTATE_AWAITING_DHKEY)) {
+		context->msgstate = m_context->msgstate;
+		context->auth.protocol_version = 3;
+		context->protocol_version = 3;
+		otrl_auth_copy_on_key(&(m_context->auth), &(context->auth));
+	    }
+	}
+    }
+
+    if (contextp) {
+	*contextp = context;
+    }
+
+    /* update time of last received message */
+    context->context_priv->lastrecv = time(NULL);
+    otrl_context_update_recent_child(context, 0);
+
+    edata.gone_encrypted = 0;
+    edata.us = us;
+    edata.context = context;
+    edata.ops = ops;
+    edata.opdata = opdata;
+    edata.ignore_message = -1;
+    edata.messagep = newmessagep;
+
+    switch(msgtype) {
+	unsigned int bestversion;
+	const char *startwhite, *endwhite;
+	DH_keypair *our_dh;
+	unsigned int our_keyid;
+	OtrlPrivKey *privkey;
+	int haveauthmsg;
+
+	case OTRL_MSGTYPE_QUERY:
+	    /* See if we should use an existing DH keypair, or generate
+	     * a fresh one. */
+	    if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+		our_dh = &(context->context_priv->our_old_dh_key);
+		our_keyid = context->context_priv->our_keyid - 1;
+	    } else {
+		our_dh = NULL;
+		our_keyid = 0;
+	    }
+
+	    /* Find the best version of OTR that we both speak */
+	    switch(otrl_proto_query_bestversion(message, policy)) {
+		case 3:
+		    err = otrl_auth_start_v23(&(context->auth), 3);
+		    send_or_error_auth(ops, opdata, err, context, us);
+		    break;
+		case 2:
+		    err = otrl_auth_start_v23(&(context->auth), 2);
+		    send_or_error_auth(ops, opdata, err, context, us);
+		    break;
+		case 1:
+		    /* Get our private key */
+		    privkey = otrl_privkey_find(us, context->accountname,
+			    context->protocol);
+		    if (privkey == NULL) {
+			/* We've got no private key! */
+			if (ops->create_privkey) {
+			    ops->create_privkey(opdata, context->accountname,
+				    context->protocol);
+			    privkey = otrl_privkey_find(us,
+				    context->accountname, context->protocol);
+			}
+		    }
+		    if (privkey) {
+			err = otrl_auth_start_v1(&(context->auth), our_dh,
+				our_keyid, privkey);
+			send_or_error_auth(ops, opdata, err, context, us);
+		    }
+		    break;
+		default:
+		    /* Just ignore this message */
+		    break;
+	    }
+	    /* Don't display the Query message to the user. */
+	    if (edata.ignore_message == -1) edata.ignore_message = 1;
+	    break;
+
+	case OTRL_MSGTYPE_DH_COMMIT:
+	    err = otrl_auth_handle_commit(&(context->auth), otrtag, version);
+	    send_or_error_auth(ops, opdata, err, context, us);
+
+	    if (edata.ignore_message == -1) edata.ignore_message = 1;
+	    break;
+
+	case OTRL_MSGTYPE_DH_KEY:
+	    /* Get our private key */
+	    privkey = otrl_privkey_find(us, context->accountname,
+		    context->protocol);
+	    if (privkey == NULL) {
+		/* We've got no private key! */
+		if (ops->create_privkey) {
+		    ops->create_privkey(opdata, context->accountname,
+			    context->protocol);
+		    privkey = otrl_privkey_find(us,
+			    context->accountname, context->protocol);
+		}
+	    }
+	    if (privkey) {
+		err = otrl_auth_handle_key(&(context->auth), otrtag,
+			&haveauthmsg, privkey);
+		if (err || haveauthmsg) {
+		    send_or_error_auth(ops, opdata, err, context, us);
+		}
+	    }
+
+	    if (edata.ignore_message == -1) edata.ignore_message = 1;
+	    break;
+
+	case OTRL_MSGTYPE_REVEALSIG:
+	    /* Get our private key */
+	    privkey = otrl_privkey_find(us, context->accountname,
+		    context->protocol);
+	    if (privkey == NULL) {
+		/* We've got no private key! */
+		if (ops->create_privkey) {
+		    ops->create_privkey(opdata, context->accountname,
+			    context->protocol);
+		    privkey = otrl_privkey_find(us,
+			    context->accountname, context->protocol);
+		}
+	    }
+	    if (privkey) {
+		err = otrl_auth_handle_revealsig(&(context->auth),
+			otrtag, &haveauthmsg, privkey, go_encrypted,
+			&edata);
+		if (err || haveauthmsg) {
+		    send_or_error_auth(ops, opdata, err, context, us);
+		    maybe_resend(&edata);
+		}
+	    }
+
+	    if (edata.ignore_message == -1) edata.ignore_message = 1;
+	    break;
+
+	case OTRL_MSGTYPE_SIGNATURE:
+	    err = otrl_auth_handle_signature(&(context->auth),
+		    otrtag, &haveauthmsg, go_encrypted, &edata);
+	    if (err || haveauthmsg) {
+		send_or_error_auth(ops, opdata, err, context, us);
+		maybe_resend(&edata);
+	    }
+
+	    if (edata.ignore_message == -1) edata.ignore_message = 1;
+	    break;
+
+	case OTRL_MSGTYPE_V1_KEYEXCH:
+	    /* See if we should use an existing DH keypair, or generate
+	     * a fresh one. */
+	    if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+		our_dh = &(context->context_priv->our_old_dh_key);
+		our_keyid = context->context_priv->our_keyid - 1;
+	    } else {
+		our_dh = NULL;
+		our_keyid = 0;
+	    }
+
+	    /* Get our private key */
+	    privkey = otrl_privkey_find(us, context->accountname,
+		    context->protocol);
+	    if (privkey == NULL) {
+		/* We've got no private key! */
+		if (ops->create_privkey) {
+		    ops->create_privkey(opdata, context->accountname,
+			    context->protocol);
+		    privkey = otrl_privkey_find(us, context->accountname,
+			    context->protocol);
+		}
+	    }
+	    if (privkey) {
+		err = otrl_auth_handle_v1_key_exchange(&(context->auth),
+			message, &haveauthmsg, privkey, our_dh, our_keyid,
+			go_encrypted, &edata);
+		if (err || haveauthmsg) {
+		    send_or_error_auth(ops, opdata, err, context, us);
+		    maybe_resend(&edata);
+		}
+	    }
+
+	    if (edata.ignore_message == -1) edata.ignore_message = 1;
+	    break;
+
+	case OTRL_MSGTYPE_DATA:
+	    switch(context->msgstate) {
+		gcry_error_t err;
+		OtrlTLV *tlvs, *tlv;
+		char *plaintext;
+		char *buf;
+		const char *err_msg;
+		unsigned char *extrakey;
+		unsigned char flags;
+		NextExpectedSMP nextMsg;
+
+		case OTRL_MSGSTATE_PLAINTEXT:
+		case OTRL_MSGSTATE_FINISHED:
+		    /* See if we're supposed to ignore this message in
+		     * the event it's unreadable. */
+		    err = otrl_proto_data_read_flags(message, &flags);
+		    if ((flags & OTRL_MSGFLAGS_IGNORE_UNREADABLE)) {
+			edata.ignore_message = 1;
+			break;
+		    }
+
+		    if(best_context && best_context != context &&
+			best_context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+
+			if (ops->handle_msg_event) {
+			    ops->handle_msg_event(opdata,
+				    OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE,
+				    m_context, NULL,
+				    gcry_error(GPG_ERR_NO_ERROR));
+			}
+		    } else if (ops->handle_msg_event) {
+			ops->handle_msg_event(opdata,
+				    OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE,
+				    context, NULL,
+				    gcry_error(GPG_ERR_NO_ERROR));
+		    }
+		    edata.ignore_message = 1;
+
+		    /* We don't actually want to send anything in this case,
+		       since this could just be a message intended for another
+		       v2 instance.  We still notify the local user though */
+		    break;
+
+		case OTRL_MSGSTATE_ENCRYPTED:
+		    extrakey = gcry_malloc_secure(OTRL_EXTRAKEY_BYTES);
+		    err = otrl_proto_accept_data(&plaintext, &tlvs, context,
+				    message, &flags, extrakey);
+		    if (err) {
+			int is_conflict =
+				(gpg_err_code(err) == GPG_ERR_CONFLICT);
+			if ((flags & OTRL_MSGFLAGS_IGNORE_UNREADABLE)) {
+			    edata.ignore_message = 1;
+			    break;
+			}
+			if (is_conflict) {
+			    if (ops->handle_msg_event) {
+				ops->handle_msg_event(opdata,
+					OTRL_MSGEVENT_RCVDMSG_UNREADABLE,
+					context, NULL,
+					gcry_error(GPG_ERR_NO_ERROR));
+			    }
+			} else {
+			    if (ops->handle_msg_event) {
+				ops->handle_msg_event(opdata,
+					OTRL_MSGEVENT_RCVDMSG_MALFORMED,
+					context, NULL,
+					gcry_error(GPG_ERR_NO_ERROR));
+			    }
+			}
+			if (ops->inject_message && ops->otr_error_message) {
+			    err_msg = ops->otr_error_message(opdata,
+					context,
+					is_conflict ?
+					    OTRL_ERRCODE_MSG_UNREADABLE :
+					    OTRL_ERRCODE_MSG_MALFORMED);
+			    if (err_msg) {
+				buf = malloc(strlen(OTR_ERROR_PREFIX) +
+						strlen(err_msg) + 1);
+				if (buf) {
+				    strcpy(buf, OTR_ERROR_PREFIX);
+				    strcat(buf, err_msg);
+				    ops->inject_message(opdata,
+					    accountname, protocol,
+					    sender, buf);
+				    free(buf);
+				}
+			    }
+			    if (ops->otr_error_message_free) {
+				ops->otr_error_message_free(opdata,
+					err_msg);
+			    }
+			}
+			edata.ignore_message = 1;
+			break;
+		    }
+
+		    /* If the other side told us he's disconnected his
+		     * private connection, make a note of that so we
+		     * don't try sending anything else to him. */
+		    if (otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED)) {
+			otrl_context_force_finished(context);
+		    }
+
+		    /* If the other side told us to use the current
+		     * extra symmetric key, let the application know. */
+		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SYMKEY);
+		    if (tlv && otrl_api_version >= 0x040000) {
+			if (ops->received_symkey && tlv->len >= 4) {
+			    unsigned char *bufp = tlv->data;
+			    unsigned int use =
+				(bufp[0] << 24) | (bufp[1] << 16) |
+				(bufp[2] << 8) | bufp[3];
+			    ops->received_symkey(opdata, context, use,
+				    bufp+4, tlv->len - 4, extrakey);
+			}
+		    }
+		    gcry_free(extrakey);
+		    extrakey = NULL;
+
+		    /* If TLVs contain SMP data, process it */
+		    nextMsg = context->smstate->nextExpected;
+
+		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
+		    if (tlv) {
+			if (nextMsg == OTRL_SMP_EXPECT1 && tlv->len > 0) {
+			    /* We can only do the verification half now.
+			     * We must wait for the secret to be entered
+			     * to continue. */
+			    char *question = (char *)tlv->data;
+			    char *qend = memchr(question, '\0', tlv->len - 1);
+			    size_t qlen = qend ? (qend - question + 1) :
+				    tlv->len;
+			    otrl_sm_step2a(context->smstate, tlv->data + qlen,
+				    tlv->len - qlen, 1);
+
+			    if (context->smstate->sm_prog_state !=
+				    OTRL_SMP_PROG_CHEATED) {
+				if (ops->handle_smp_event) {
+				    ops->handle_smp_event(opdata,
+					    OTRL_SMPEVENT_ASK_FOR_ANSWER,
+					    context, 25, question);
+				}
+			    } else {
+				if (ops->handle_smp_event) {
+				    ops->handle_smp_event(opdata,
+					    OTRL_SMPEVENT_CHEATED, context,
+					    0, NULL);
+				}
+				context->smstate->nextExpected =
+					OTRL_SMP_EXPECT1;
+				context->smstate->sm_prog_state =
+					OTRL_SMP_PROG_OK;
+			    }
+			} else {
+			    if (ops->handle_smp_event) {
+				ops->handle_smp_event(opdata,
+					OTRL_SMPEVENT_ERROR, context,
+					0, NULL);
+			    }
+			}
+		    }
+
+		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
+		    if (tlv) {
+			if (nextMsg == OTRL_SMP_EXPECT1) {
+			    /* We can only do the verification half now.
+			     * We must wait for the secret to be entered
+			     * to continue. */
+			    otrl_sm_step2a(context->smstate, tlv->data,
+				    tlv->len, 0);
+			    if (context->smstate->sm_prog_state !=
+				    OTRL_SMP_PROG_CHEATED) {
+				if (ops->handle_smp_event) {
+				    ops->handle_smp_event(opdata,
+					    OTRL_SMPEVENT_ASK_FOR_SECRET,
+					    context, 25, NULL);
+				}
+			    } else {
+				if (ops->handle_smp_event) {
+				    ops->handle_smp_event(opdata,
+					    OTRL_SMPEVENT_CHEATED,
+					    context, 0, NULL);
+				}
+				context->smstate->nextExpected =
+					OTRL_SMP_EXPECT1;
+				context->smstate->sm_prog_state =
+					OTRL_SMP_PROG_OK;
+			    }
+			} else {
+			    if (ops->handle_smp_event) {
+				ops->handle_smp_event(opdata,
+					OTRL_SMPEVENT_ERROR, context,
+					0, NULL);
+			    }
+			}
+		    }
+
+		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
+		    if (tlv) {
+			if (nextMsg == OTRL_SMP_EXPECT2) {
+			    unsigned char* nextmsg;
+			    int nextmsglen;
+			    OtrlTLV *sendtlv;
+			    char *sendsmp = NULL;
+			    otrl_sm_step3(context->smstate, tlv->data,
+				    tlv->len, &nextmsg, &nextmsglen);
+
+			    if (context->smstate->sm_prog_state !=
+				    OTRL_SMP_PROG_CHEATED) {
+				/* Send msg with next smp msg content */
+				sendtlv = otrl_tlv_new(OTRL_TLV_SMP3,
+					nextmsglen, nextmsg);
+				err = otrl_proto_create_data(&sendsmp,
+					context, "", sendtlv,
+					OTRL_MSGFLAGS_IGNORE_UNREADABLE,
+					NULL);
+				if (!err) {
+				err = fragment_and_send(ops,
+					opdata, context, sendsmp,
+					OTRL_FRAGMENT_SEND_ALL, NULL);
+				}
+				free(sendsmp);
+				otrl_tlv_free(sendtlv);
+
+				if (ops->handle_smp_event) {
+				    ops->handle_smp_event(opdata,
+					    OTRL_SMPEVENT_IN_PROGRESS,
+					    context, 60, NULL);
+				}
+				context->smstate->nextExpected =
+					OTRL_SMP_EXPECT4;
+			    } else {
+				if (ops->handle_smp_event) {
+				    ops->handle_smp_event(opdata,
+					    OTRL_SMPEVENT_CHEATED,
+					    context, 0, NULL);
+				}
+				context->smstate->nextExpected =
+					OTRL_SMP_EXPECT1;
+				context->smstate->sm_prog_state =
+					OTRL_SMP_PROG_OK;
+			    }
+			    free(nextmsg);
+			} else {
+			    if (ops->handle_smp_event) {
+				ops->handle_smp_event(opdata,
+					OTRL_SMPEVENT_ERROR, context,
+					0, NULL);
+			    }
+			}
+		    }
+
+		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
+		    if (tlv) {
+			if (nextMsg == OTRL_SMP_EXPECT3) {
+			    unsigned char* nextmsg;
+			    int nextmsglen;
+			    OtrlTLV *sendtlv;
+			    char *sendsmp = NULL;
+			    err = otrl_sm_step4(context->smstate, tlv->data,
+				    tlv->len, &nextmsg, &nextmsglen);
+			    /* Set trust level based on result */
+			    if (context->smstate->received_question == 0) {
+				set_smp_trust(ops, opdata, context,
+					(err == gcry_error(GPG_ERR_NO_ERROR)));
+			    }
+
+			    if (context->smstate->sm_prog_state !=
+				    OTRL_SMP_PROG_CHEATED) {
+				/* Send msg with next smp msg content */
+				sendtlv = otrl_tlv_new(OTRL_TLV_SMP4,
+					nextmsglen, nextmsg);
+				err = otrl_proto_create_data(&sendsmp,
+					context, "", sendtlv,
+					OTRL_MSGFLAGS_IGNORE_UNREADABLE,
+					NULL);
+				if (!err) {
+				err = fragment_and_send(ops,
+					opdata, context, sendsmp,
+					OTRL_FRAGMENT_SEND_ALL, NULL);
+				}
+				free(sendsmp);
+				otrl_tlv_free(sendtlv);
+
+				if (ops->handle_smp_event) {
+				    OtrlSMPEvent succorfail =
+					context->smstate->sm_prog_state ==
+						OTRL_SMP_PROG_SUCCEEDED ?
+					    OTRL_SMPEVENT_SUCCESS :
+					    OTRL_SMPEVENT_FAILURE;
+				    ops->handle_smp_event(opdata, succorfail,
+					    context, 100, NULL);
+				}
+				context->smstate->nextExpected =
+				    OTRL_SMP_EXPECT1;
+			    } else {
+				if (ops->handle_smp_event) {
+				    ops->handle_smp_event(opdata,
+					    OTRL_SMPEVENT_CHEATED,
+					    context, 0, NULL);
+				}
+				context->smstate->nextExpected =
+					OTRL_SMP_EXPECT1;
+				context->smstate->sm_prog_state =
+					OTRL_SMP_PROG_OK;
+			    }
+			    free(nextmsg);
+			} else {
+			    if (ops->handle_smp_event) {
+				ops->handle_smp_event(opdata,
+					OTRL_SMPEVENT_ERROR, context,
+					0, NULL);
+			    }
+			}
+		    }
+
+		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
+		    if (tlv) {
+			if (nextMsg == OTRL_SMP_EXPECT4) {
+			    err = otrl_sm_step5(context->smstate, tlv->data,
+				    tlv->len);
+			    /* Set trust level based on result */
+			    set_smp_trust(ops, opdata, context,
+				    (err == gcry_error(GPG_ERR_NO_ERROR)));
+
+			    if (context->smstate->sm_prog_state !=
+				    OTRL_SMP_PROG_CHEATED) {
+				if (ops->handle_smp_event) {
+				    OtrlSMPEvent succorfail =
+					context->smstate->sm_prog_state ==
+						OTRL_SMP_PROG_SUCCEEDED ?
+					    OTRL_SMPEVENT_SUCCESS :
+					    OTRL_SMPEVENT_FAILURE;
+				    ops->handle_smp_event(opdata, succorfail,
+					    context, 100, NULL);
+				}
+				context->smstate->nextExpected =
+					OTRL_SMP_EXPECT1;
+			    } else {
+				if (ops->handle_smp_event) {
+				    ops->handle_smp_event(opdata,
+					    OTRL_SMPEVENT_CHEATED,
+					    context, 0, NULL);
+				}
+				context->smstate->nextExpected =
+					OTRL_SMP_EXPECT1;
+				context->smstate->sm_prog_state =
+					OTRL_SMP_PROG_OK;
+			    }
+			} else {
+			    if (ops->handle_smp_event) {
+				ops->handle_smp_event(opdata,
+					OTRL_SMPEVENT_ERROR, context,
+					0, NULL);
+			    }
+			}
+		    }
+
+		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
+		    if (tlv) {
+			context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+			if (ops->handle_smp_event) {
+			    ops->handle_smp_event(opdata, OTRL_SMPEVENT_ABORT,
+				    context, 0, NULL);
+			}
+		    }
+
+		    if (plaintext[0] == '\0') {
+			/* If it's a heartbeat (an empty message), don't
+			 * display it to the user, but signal an event. */
+			if (ops->handle_msg_event) {
+			    ops->handle_msg_event(opdata,
+				    OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD,
+				    context, NULL,
+				    gcry_error(GPG_ERR_NO_ERROR));
+			}
+			edata.ignore_message = 1;
+		    } else if (edata.ignore_message != 1 &&
+			    context->context_priv->their_keyid > 0) {
+			/* If it's *not* a heartbeat, and we haven't
+			 * sent anything in a while, also send a
+			 * heartbeat. */
+			time_t now = time(NULL);
+			if (context->context_priv->lastsent <
+				(now - HEARTBEAT_INTERVAL)) {
+			    char *heartbeat;
+
+			    /* Create the heartbeat message */
+			    err = otrl_proto_create_data(&heartbeat,
+				    context, "", NULL,
+				    OTRL_MSGFLAGS_IGNORE_UNREADABLE,
+				    NULL);
+			    if (!err) {
+				/* Send it, and inject a debug message */
+				if (ops->inject_message) {
+				    ops->inject_message(opdata, accountname,
+					    protocol, sender, heartbeat);
+				}
+				free(heartbeat);
+
+				context->context_priv->lastsent = now;
+				otrl_context_update_recent_child(context, 1);
+
+				/* Signal an event for the heartbeat message */
+				if (ops->handle_msg_event) {
+				    ops->handle_msg_event(opdata,
+					    OTRL_MSGEVENT_LOG_HEARTBEAT_SENT,
+					    context, NULL,
+					    gcry_error(GPG_ERR_NO_ERROR));
+				}
+			    }
+			}
+		    }
+
+		    /* Return the TLVs even if ignore_message == 1 so
+		     * that we can attach TLVs to heartbeats. */
+		    if (tlvsp) {
+			*tlvsp = tlvs;
+		    } else {
+			otrl_tlv_free(tlvs);
+		    }
+
+		    if (edata.ignore_message != 1) {
+			char *converted_msg = NULL;
+
+			*newmessagep = plaintext;
+			edata.ignore_message = 0;
+
+			/* convert the plaintext message if necessary */
+			if (ops->convert_msg) {
+			    ops->convert_msg(opdata, context,
+				    OTRL_CONVERT_RECEIVING, &converted_msg,
+				    plaintext);
+
+			    if (converted_msg) {
+				free(plaintext);
+				plaintext = NULL;
+				*newmessagep = strdup(converted_msg);
+
+				if (ops->convert_free) {
+				    ops->convert_free(opdata, context,
+					    converted_msg);
+				}
+			    }
+			}
+		    } else {
+			free(plaintext);
+		    }
+		    break;
+	    }
+	    break;
+
+	case OTRL_MSGTYPE_ERROR:
+	    if ((policy & OTRL_POLICY_ERROR_START_AKE)) {
+		char *msgtosend = otrl_proto_default_query_msg(
+			context->accountname, policy);
+		if (msgtosend && ops->inject_message) {
+		    ops->inject_message(opdata, context->accountname,
+			    context->protocol, context->username,
+			    msgtosend);
+		}
+		free(msgtosend);
+	    }
+
+	    if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+		/* Mark the last message we sent as eligible for
+		 * retransmission */
+		context->context_priv->may_retransmit = 1;
+	    }
+
+	    /* In any event, display the error message, with the
+	     * display_otr_message callback, if possible */
+	    if (ops->handle_msg_event) {
+		/* Remove the OTR error prefix and pass the msg */
+		const char *just_err_msg = strstr(message, OTR_ERROR_PREFIX);
+		if (!just_err_msg) {
+		    just_err_msg = message;
+		} else {
+		    just_err_msg += (strlen(OTR_ERROR_PREFIX));
+		    if (*just_err_msg == ' ') {
+			/* Advance pointer to skip the space character */
+			just_err_msg++;
+		    }
+		    ops->handle_msg_event(opdata,
+			    OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR,
+			    context, just_err_msg,
+			    gcry_error(GPG_ERR_NO_ERROR));
+		    edata.ignore_message = 1;
+		}
+	    }
+	    break;
+
+	case OTRL_MSGTYPE_TAGGEDPLAINTEXT:
+	    /* Strip the tag from the message */
+	    bestversion = otrl_proto_whitespace_bestversion(message,
+		    &startwhite, &endwhite, policy);
+	    if (startwhite && endwhite) {
+		size_t restlen = strlen(endwhite);
+		char *strippedmsg = strdup(message);
+
+		if (strippedmsg) {
+		    memmove(strippedmsg + (startwhite - message),
+			    strippedmsg + (endwhite - message), restlen+1);
+		    *newmessagep = strippedmsg;
+		    edata.ignore_message = 0;
+		}
+	    }
+	    if (bestversion && context->msgstate != OTRL_MSGSTATE_ENCRYPTED
+		    && (policy & OTRL_POLICY_WHITESPACE_START_AKE)) {
+		switch(bestversion) {
+		    case 3:
+			err = otrl_auth_start_v23(&(context->auth), 3);
+			send_or_error_auth(ops, opdata, err, context, us);
+			break;
+		    case 2:
+			err = otrl_auth_start_v23(&(context->auth), 2);
+			send_or_error_auth(ops, opdata, err, context, us);
+			break;
+		    case 1:
+			/* Get our private key */
+			privkey = otrl_privkey_find(us, context->accountname,
+				context->protocol);
+			if (privkey == NULL) {
+			    /* We've got no private key! */
+			    if (ops->create_privkey) {
+				ops->create_privkey(opdata,
+					context->accountname,
+					context->protocol);
+				privkey = otrl_privkey_find(us,
+					context->accountname,
+					context->protocol);
+			    }
+			}
+			if (privkey) {
+			    err = otrl_auth_start_v1(&(context->auth), NULL, 0,
+				    privkey);
+			    send_or_error_auth(ops, opdata, err, context, us);
+			}
+			break;
+		    default:
+			/* Don't start the AKE */
+			break;
+		}
+	    }
+
+	    /* FALLTHROUGH */
+	case OTRL_MSGTYPE_NOTOTR:
+	    if (best_context->msgstate != OTRL_MSGSTATE_PLAINTEXT ||
+		    (policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) {
+		/* Not fine.  Let the user know. */
+		const char *plainmsg = (*newmessagep) ? *newmessagep : message;
+		if (ops->handle_msg_event) {
+		    ops->handle_msg_event(opdata,
+			    OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED,
+			    context, plainmsg, gcry_error(GPG_ERR_NO_ERROR));
+		    free(*newmessagep);
+		    *newmessagep = NULL;
+		    edata.ignore_message = 1;
+		}
+	    }
+	    break;
+
+	case OTRL_MSGTYPE_UNKNOWN:
+	    /* We received an OTR message we didn't recognize.  Ignore
+	     * it, and signal an event. */
+	    if (ops->handle_msg_event) {
+		ops->handle_msg_event(opdata,
+			OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED,
+			context, NULL, gcry_error(GPG_ERR_NO_ERROR));
+	    }
+	    if (edata.ignore_message == -1) edata.ignore_message = 1;
+	    break;
+    }
+
+end:
+    /* If we reassembled a fragmented message, we need to free the
+     * allocated memory now. */
+    free(unfragmessage);
+
+    if (edata.ignore_message == -1) edata.ignore_message = 0;
+    return edata.ignore_message;
+}
+
+/* Put a connection into the PLAINTEXT state, first sending the
+ * other side a notice that we're doing so if we're currently ENCRYPTED,
+ * and we think he's logged in. Affects only the specified context. */
+static void disconnect_context(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context)
+{
+    if (!context) return;
+
+    if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+	    context->context_priv->their_keyid > 0 &&
+	    ops->is_logged_in &&
+	    ops->is_logged_in(opdata, context->accountname, context->protocol,
+		    context->username) == 1) {
+	if (ops->inject_message) {
+	    char *encmsg = NULL;
+	    gcry_error_t err;
+	    OtrlTLV *tlv = otrl_tlv_new(OTRL_TLV_DISCONNECTED, 0, NULL);
+
+	    err = otrl_proto_create_data(&encmsg, context, "", tlv,
+		    OTRL_MSGFLAGS_IGNORE_UNREADABLE, NULL);
+	    if (!err) {
+		ops->inject_message(opdata, context->accountname,
+			context->protocol, context->username, encmsg);
+	    }
+	    free(encmsg);
+	    otrl_tlv_free(tlv);
+	}
+    }
+
+    otrl_context_force_plaintext(context);
+    if (ops->update_context_list) {
+	ops->update_context_list(opdata);
+    }
+}
+
+
+/* Put a connection into the PLAINTEXT state, first sending the
+ * other side a notice that we're doing so if we're currently ENCRYPTED,
+ * and we think he's logged in. Affects only the specified instance. */
+void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, const char *accountname, const char *protocol,
+	const char *username, otrl_instag_t instance)
+{
+    ConnContext *context = otrl_context_find(us, username, accountname,
+	    protocol, instance, 0, NULL, NULL, NULL);
+
+    if (!context) return;
+
+    disconnect_context(us, ops, opdata, context);
+}
+
+/* Put a connection into the PLAINTEXT state, first sending the
+ * other side a notice that we're doing so if we're currently ENCRYPTED,
+ * and we think he's logged in. Affects all matching instances. */
+void otrl_message_disconnect_all_instances(OtrlUserState us,
+	const OtrlMessageAppOps *ops, void *opdata, const char *accountname,
+	const char *protocol, const char *username)
+{
+    ConnContext * c_iter;
+    ConnContext *context;
+
+    if (!username || !accountname || !protocol) return;
+
+    context = otrl_context_find(us, username, accountname,
+	    protocol, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
+
+    if (!context) return;
+
+    for (c_iter = context; c_iter && c_iter->m_context == context->m_context;
+	c_iter = c_iter->next) {
+	disconnect_context(us, ops, opdata, c_iter);
+    }
+}
+
+/* Get the current extra symmetric key (of size OTRL_EXTRAKEY_BYTES
+ * bytes) and let the other side know what we're going to use it for.
+ * The key is stored in symkey, which must already be allocated
+ * and OTRL_EXTRAKEY_BYTES bytes long. */
+gcry_error_t otrl_message_symkey(OtrlUserState us,
+	const OtrlMessageAppOps *ops, void *opdata, ConnContext *context,
+	unsigned int use, const unsigned char *usedata, size_t usedatalen,
+	unsigned char *symkey)
+{
+    if (!context || (usedatalen > 0 && !usedata)) {
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+	    context->context_priv->their_keyid > 0) {
+	unsigned char *tlvdata = malloc(usedatalen+4);
+	char *encmsg = NULL;
+	gcry_error_t err;
+	OtrlTLV *tlv;
+
+	tlvdata[0] = (use >> 24) & 0xff;
+	tlvdata[1] = (use >> 16) & 0xff;
+	tlvdata[2] = (use >> 8) & 0xff;
+	tlvdata[3] = (use) & 0xff;
+	if (usedatalen > 0) {
+	    memmove(tlvdata+4, usedata, usedatalen);
+	}
+
+	tlv = otrl_tlv_new(OTRL_TLV_SYMKEY, usedatalen+4, tlvdata);
+	free(tlvdata);
+
+	err = otrl_proto_create_data(&encmsg, context, "", tlv,
+		OTRL_MSGFLAGS_IGNORE_UNREADABLE, symkey);
+	if (!err && ops->inject_message) {
+	    ops->inject_message(opdata, context->accountname,
+		    context->protocol, context->username, encmsg);
+	}
+	free(encmsg);
+	otrl_tlv_free(tlv);
+
+	return err;
+    }
+
+    /* We weren't in an encrypted session. */
+    return gcry_error(GPG_ERR_INV_VALUE);
+}
+
+/* If you do _not_ define a timer_control callback function, set a timer
+ * to go off every definterval =
+ * otrl_message_poll_get_default_interval(userstate) seconds, and call
+ * otrl_message_poll every time the timer goes off. */
+unsigned int otrl_message_poll_get_default_interval(OtrlUserState us)
+{
+    return POLL_DEFAULT_INTERVAL;
+}
+
+/* Call this function every so often, either as directed by the
+ * timer_control callback, or every definterval =
+ * otrl_message_poll_get_default_interval(userstate) seconds if you have
+ * no timer_control callback.  This function must be called from the
+ * main libotr thread.*/
+void otrl_message_poll(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata)
+{
+    /* Wipe private keys last sent before this time */
+    time_t expire_before = time(NULL) - MAX_AKE_WAIT_TIME;
+
+    ConnContext *contextp;
+
+    /* Is there a context still waiting for a DHKEY message, even after
+     * we wipe the stale ones? */
+    int still_waiting = 0;
+
+    if (us == NULL) return;
+
+    for (contextp = us->context_root; contextp; contextp = contextp->next) {
+	/* If this is a master context, and it's still waiting for a
+	 * v3 DHKEY message, see if it's waited long enough. */
+	if (contextp->m_context == contextp &&
+		contextp->auth.authstate == OTRL_AUTHSTATE_AWAITING_DHKEY &&
+		contextp->auth.protocol_version == 3 &&
+		contextp->auth.commit_sent_time > 0) {
+	    if (contextp->auth.commit_sent_time < expire_before) {
+		otrl_auth_clear(&contextp->auth);
+	    } else {
+		/* Not yet expired */
+		still_waiting = 1;
+	    }
+	}
+    }
+
+    /* If there's nothing more to wait for, stop the timer, if possible. */
+    if (still_waiting == 0 && ops && ops->timer_control) {
+	ops->timer_control(opdata, 0);
+	us->timer_running = 0;
+    }
+}
diff --git a/libotr/libotr-4.1.1/src/message.h b/libotr/libotr-4.1.1/src/message.h
new file mode 100644
index 0000000..bb82ffc
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/message.h
@@ -0,0 +1,440 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2014  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __MESSAGE_H__
+#define __MESSAGE_H__
+
+#define OTR_ERROR_PREFIX "?OTR Error: "
+
+typedef enum {
+    OTRL_ERRCODE_NONE,
+    OTRL_ERRCODE_ENCRYPTION_ERROR,
+    OTRL_ERRCODE_MSG_NOT_IN_PRIVATE,
+    OTRL_ERRCODE_MSG_UNREADABLE,
+    OTRL_ERRCODE_MSG_MALFORMED,
+} OtrlErrorCode;
+
+/* These define the events used to indicate status of SMP to the UI */
+typedef enum {
+    OTRL_SMPEVENT_NONE,
+    OTRL_SMPEVENT_ERROR,
+    OTRL_SMPEVENT_ABORT,
+    OTRL_SMPEVENT_CHEATED,
+    OTRL_SMPEVENT_ASK_FOR_ANSWER,
+    OTRL_SMPEVENT_ASK_FOR_SECRET,
+    OTRL_SMPEVENT_IN_PROGRESS,
+    OTRL_SMPEVENT_SUCCESS,
+    OTRL_SMPEVENT_FAILURE
+} OtrlSMPEvent;
+
+/* These define the events used to indicate the messages that need
+ * to be sent */
+typedef enum {
+    OTRL_MSGEVENT_NONE,
+    OTRL_MSGEVENT_ENCRYPTION_REQUIRED,
+    OTRL_MSGEVENT_ENCRYPTION_ERROR,
+    OTRL_MSGEVENT_CONNECTION_ENDED,
+    OTRL_MSGEVENT_SETUP_ERROR,
+    OTRL_MSGEVENT_MSG_REFLECTED,
+    OTRL_MSGEVENT_MSG_RESENT,
+    OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE,
+    OTRL_MSGEVENT_RCVDMSG_UNREADABLE,
+    OTRL_MSGEVENT_RCVDMSG_MALFORMED,
+    OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD,
+    OTRL_MSGEVENT_LOG_HEARTBEAT_SENT,
+    OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR,
+    OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED,
+    OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED,
+    OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE
+} OtrlMessageEvent;
+
+typedef enum {
+    OTRL_NOTIFY_ERROR,
+    OTRL_NOTIFY_WARNING,
+    OTRL_NOTIFY_INFO
+} OtrlNotifyLevel;
+
+typedef enum {
+    OTRL_CONVERT_SENDING,
+    OTRL_CONVERT_RECEIVING
+} OtrlConvertType;
+
+typedef struct s_OtrlMessageAppOps {
+    /* Return the OTR policy for the given context. */
+    OtrlPolicy (*policy)(void *opdata, ConnContext *context);
+
+    /* Create a private key for the given accountname/protocol if
+     * desired. */
+    void (*create_privkey)(void *opdata, const char *accountname,
+	    const char *protocol);
+
+    /* Report whether you think the given user is online.  Return 1 if
+     * you think he is, 0 if you think he isn't, -1 if you're not sure.
+     *
+     * If you return 1, messages such as heartbeats or other
+     * notifications may be sent to the user, which could result in "not
+     * logged in" errors if you're wrong. */
+    int (*is_logged_in)(void *opdata, const char *accountname,
+	    const char *protocol, const char *recipient);
+
+    /* Send the given IM to the given recipient from the given
+     * accountname/protocol. */
+    void (*inject_message)(void *opdata, const char *accountname,
+	    const char *protocol, const char *recipient, const char *message);
+
+    /* When the list of ConnContexts changes (including a change in
+     * state), this is called so the UI can be updated. */
+    void (*update_context_list)(void *opdata);
+
+    /* A new fingerprint for the given user has been received. */
+    void (*new_fingerprint)(void *opdata, OtrlUserState us,
+	    const char *accountname, const char *protocol,
+	    const char *username, unsigned char fingerprint[20]);
+
+    /* The list of known fingerprints has changed.  Write them to disk. */
+    void (*write_fingerprints)(void *opdata);
+
+    /* A ConnContext has entered a secure state. */
+    void (*gone_secure)(void *opdata, ConnContext *context);
+
+    /* A ConnContext has left a secure state. */
+    void (*gone_insecure)(void *opdata, ConnContext *context);
+
+    /* We have completed an authentication, using the D-H keys we
+     * already knew.  is_reply indicates whether we initiated the AKE. */
+    void (*still_secure)(void *opdata, ConnContext *context, int is_reply);
+
+    /* Find the maximum message size supported by this protocol. */
+    int (*max_message_size)(void *opdata, ConnContext *context);
+
+    /* Return a newly allocated string containing a human-friendly
+     * representation for the given account */
+    const char *(*account_name)(void *opdata, const char *account,
+	    const char *protocol);
+
+    /* Deallocate a string returned by account_name */
+    void (*account_name_free)(void *opdata, const char *account_name);
+
+    /* We received a request from the buddy to use the current "extra"
+     * symmetric key.  The key will be passed in symkey, of length
+     * OTRL_EXTRAKEY_BYTES.  The requested use, as well as use-specific
+     * data will be passed so that the applications can communicate other
+     * information (some id for the data transfer, for example). */
+    void (*received_symkey)(void *opdata, ConnContext *context,
+	    unsigned int use, const unsigned char *usedata,
+	    size_t usedatalen, const unsigned char *symkey);
+
+    /* Return a string according to the error event. This string will then
+     * be concatenated to an OTR header to produce an OTR protocol error
+     * message. The following are the possible error events:
+     * - OTRL_ERRCODE_ENCRYPTION_ERROR
+     * 		occured while encrypting a message
+     * - OTRL_ERRCODE_MSG_NOT_IN_PRIVATE
+     * 		sent encrypted message to somebody who is not in
+     * 		a mutual OTR session
+     * - OTRL_ERRCODE_MSG_UNREADABLE
+     *		sent an unreadable encrypted message
+     * - OTRL_ERRCODE_MSG_MALFORMED
+     * 		message sent is malformed */
+    const char *(*otr_error_message)(void *opdata, ConnContext *context,
+	OtrlErrorCode err_code);
+
+    /* Deallocate a string returned by otr_error_message */
+    void (*otr_error_message_free)(void *opdata, const char *err_msg);
+
+    /* Return a string that will be prefixed to any resent message. If this
+     * function is not provided by the application then the default prefix,
+     * "[resent]", will be used.
+     * */
+    const char *(*resent_msg_prefix)(void *opdata, ConnContext *context);
+
+    /* Deallocate a string returned by resent_msg_prefix */
+    void (*resent_msg_prefix_free)(void *opdata, const char *prefix);
+
+    /* Update the authentication UI with respect to SMP events
+     * These are the possible events:
+     * - OTRL_SMPEVENT_ASK_FOR_SECRET
+     *      prompt the user to enter a shared secret. The sender application
+     *      should call otrl_message_initiate_smp, passing NULL as the question.
+     *      When the receiver application resumes the SM protocol by calling
+     *      otrl_message_respond_smp with the secret answer.
+     * - OTRL_SMPEVENT_ASK_FOR_ANSWER
+     *      (same as OTRL_SMPEVENT_ASK_FOR_SECRET but sender calls
+     *      otrl_message_initiate_smp_q instead)
+     * - OTRL_SMPEVENT_CHEATED
+     *      abort the current auth and update the auth progress dialog
+     *      with progress_percent. otrl_message_abort_smp should be called to
+     *      stop the SM protocol.
+     * - OTRL_SMPEVENT_INPROGRESS 	and
+     *   OTRL_SMPEVENT_SUCCESS 		and
+     *   OTRL_SMPEVENT_FAILURE    	and
+     *   OTRL_SMPEVENT_ABORT
+     *      update the auth progress dialog with progress_percent
+     * - OTRL_SMPEVENT_ERROR
+     *      (same as OTRL_SMPEVENT_CHEATED)
+     * */
+    void (*handle_smp_event)(void *opdata, OtrlSMPEvent smp_event,
+	    ConnContext *context, unsigned short progress_percent,
+	    char *question);
+
+    /* Handle and send the appropriate message(s) to the sender/recipient
+     * depending on the message events. All the events only require an opdata,
+     * the event, and the context. The message and err will be NULL except for
+     * some events (see below). The possible events are:
+     * - OTRL_MSGEVENT_ENCRYPTION_REQUIRED
+     *      Our policy requires encryption but we are trying to send
+     *      an unencrypted message out.
+     * - OTRL_MSGEVENT_ENCRYPTION_ERROR
+     *      An error occured while encrypting a message and the message
+     *      was not sent.
+     * - OTRL_MSGEVENT_CONNECTION_ENDED
+     *      Message has not been sent because our buddy has ended the
+     *      private conversation. We should either close the connection,
+     *      or refresh it.
+     * - OTRL_MSGEVENT_SETUP_ERROR
+     *      A private conversation could not be set up. A gcry_error_t
+     *      will be passed.
+     * - OTRL_MSGEVENT_MSG_REFLECTED
+     *      Received our own OTR messages.
+     * - OTRL_MSGEVENT_MSG_RESENT
+     *      The previous message was resent.
+     * - OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE
+     *      Received an encrypted message but cannot read
+     *      it because no private connection is established yet.
+     * - OTRL_MSGEVENT_RCVDMSG_UNREADABLE
+     *      Cannot read the received message.
+     * - OTRL_MSGEVENT_RCVDMSG_MALFORMED
+     *      The message received contains malformed data.
+     * - OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD
+     *      Received a heartbeat.
+     * - OTRL_MSGEVENT_LOG_HEARTBEAT_SENT
+     *      Sent a heartbeat.
+     * - OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR
+     *      Received a general OTR error. The argument 'message' will
+     *      also be passed and it will contain the OTR error message.
+     * - OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED
+     *      Received an unencrypted message. The argument 'message' will
+     *      also be passed and it will contain the plaintext message.
+     * - OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED
+     *      Cannot recognize the type of OTR message received.
+     * - OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE
+     *      Received and discarded a message intended for another instance. */
+    void (*handle_msg_event)(void *opdata, OtrlMessageEvent msg_event,
+		ConnContext *context, const char *message,
+		gcry_error_t err);
+
+     /* Create a instance tag for the given accountname/protocol if
+      * desired. */
+    void (*create_instag)(void *opdata, const char *accountname,
+		const char *protocol);
+
+     /* Called immediately before a data message is encrypted, and after a data
+      * message is decrypted. The OtrlConvertType parameter has the value
+      * OTRL_CONVERT_SENDING or OTRL_CONVERT_RECEIVING to differentiate these
+      * cases. */
+    void (*convert_msg)(void *opdata, ConnContext *context,
+		OtrlConvertType convert_type, char ** dest, const char *src);
+
+     /* Deallocate a string returned by convert_msg. */
+    void (*convert_free)(void *opdata, ConnContext *context, char *dest);
+
+    /* When timer_control is called, turn off any existing periodic
+     * timer.
+     *
+     * Additionally, if interval > 0, set a new periodic timer
+     * to go off every interval seconds.  When that timer fires, you
+     * must call otrl_message_poll(userstate, uiops, uiopdata); from the
+     * main libotr thread.
+     *
+     * The timing does not have to be exact; this timer is used to
+     * provide forward secrecy by cleaning up stale private state that
+     * may otherwise stick around in memory.  Note that the
+     * timer_control callback may be invoked from otrl_message_poll
+     * itself, possibly to indicate that interval == 0 (that is, that
+     * there's no more periodic work to be done at this time).
+     *
+     * If you set this callback to NULL, then you must ensure that your
+     * application calls otrl_message_poll(userstate, uiops, uiopdata);
+     * from the main libotr thread every definterval seconds (where
+     * definterval can be obtained by calling
+     * definterval = otrl_message_poll_get_default_interval(userstate);
+     * right after creating the userstate).  The advantage of
+     * implementing the timer_control callback is that the timer can be
+     * turned on by libotr only when it's needed.
+     *
+     * It is not a problem (except for a minor performance hit) to call
+     * otrl_message_poll more often than requested, whether
+     * timer_control is implemented or not.
+     *
+     * If you fail to implement the timer_control callback, and also
+     * fail to periodically call otrl_message_poll, then you open your
+     * users to a possible forward secrecy violation: an attacker that
+     * compromises the user's computer may be able to decrypt a handful
+     * of long-past messages (the first messages of an OTR
+     * conversation).
+     */
+    void (*timer_control)(void *opdata, unsigned int interval);
+
+} OtrlMessageAppOps;
+
+/* Deallocate a message allocated by other otrl_message_* routines. */
+void otrl_message_free(char *message);
+
+/* Handle a message about to be sent to the network.  It is safe to pass
+ * all messages about to be sent to this routine.  add_appdata is a
+ * function that will be called in the event that a new ConnContext is
+ * created.  It will be passed the data that you supplied, as well as a
+ * pointer to the new ConnContext.  You can use this to add
+ * application-specific information to the ConnContext using the
+ * "context->app" field, for example.  If you don't need to do this, you
+ * can pass NULL for the last two arguments of otrl_message_sending.
+ *
+ * tlvs is a chain of OtrlTLVs to append to the private message.  It is
+ * usually correct to just pass NULL here.
+ *
+ * If non-NULL, ops->convert_msg will be called just before encrypting a
+ * message.
+ *
+ * "instag" specifies the instance tag of the buddy (protocol version 3 only).
+ * Meta-instances may also be specified (e.g., OTRL_INSTAG_MOST_SECURE).
+ * If "contextp" is not NULL, it will be set to the ConnContext used for
+ * sending the message.
+ *
+ * If no fragmentation or msg injection is wanted, use OTRL_FRAGMENT_SEND_SKIP
+ * as the OtrlFragmentPolicy. In this case, this function will assign *messagep
+ * with the encrypted msg. If the routine returns non-zero, then the library
+ * tried to encrypt the message, but for some reason failed. DO NOT send the
+ * message in the clear in that case. If *messagep gets set by the call to
+ * something non-NULL, then you should replace your message with the contents
+ * of *messagep, and send that instead.
+ *
+ * Other fragmentation policies are OTRL_FRAGMENT_SEND_ALL,
+ * OTRL_FRAGMENT_SEND_ALL_BUT_LAST, or OTRL_FRAGMENT_SEND_ALL_BUT_FIRST. In
+ * these cases, the appropriate fragments will be automatically sent. For the
+ * last two policies, the remaining fragment will be passed in *original_msg.
+ *
+ * Call otrl_message_free(*messagep) if you don't need *messagep or when you're
+ * done with it. */
+gcry_error_t otrl_message_sending(OtrlUserState us,
+	const OtrlMessageAppOps *ops,
+	void *opdata, const char *accountname, const char *protocol,
+	const char *recipient, otrl_instag_t instag, const char *original_msg,
+	OtrlTLV *tlvs, char **messagep, OtrlFragmentPolicy fragPolicy,
+	ConnContext **contextp,
+	void (*add_appdata)(void *data, ConnContext *context),
+	void *data);
+
+/* Handle a message just received from the network.  It is safe to pass
+ * all received messages to this routine.  add_appdata is a function
+ * that will be called in the event that a new ConnContext is created.
+ * It will be passed the data that you supplied, as well as
+ * a pointer to the new ConnContext.  You can use this to add
+ * application-specific information to the ConnContext using the
+ * "context->app" field, for example.  If you don't need to do this, you
+ * can pass NULL for the last two arguments of otrl_message_receiving.
+ *
+ * If non-NULL, ops->convert_msg will be called after a data message is
+ * decrypted.
+ *
+ * If "contextp" is not NULL, it will be set to the ConnContext used for
+ * receiving the message.
+ *
+ * If otrl_message_receiving returns 1, then the message you received
+ * was an internal protocol message, and no message should be delivered
+ * to the user.
+ *
+ * If it returns 0, then check if *messagep was set to non-NULL.  If
+ * so, replace the received message with the contents of *messagep, and
+ * deliver that to the user instead.  You must call
+ * otrl_message_free(*messagep) when you're done with it.  If tlvsp is
+ * non-NULL, *tlvsp will be set to a chain of any TLVs that were
+ * transmitted along with this message.  You must call
+ * otrl_tlv_free(*tlvsp) when you're done with those.
+ *
+ * If otrl_message_receiving returns 0 and *messagep is NULL, then this
+ * was an ordinary, non-OTR message, which should just be delivered to
+ * the user without modification. */
+int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, const char *accountname, const char *protocol,
+	const char *sender, const char *message, char **newmessagep,
+	OtrlTLV **tlvsp, ConnContext **contextp,
+	void (*add_appdata)(void *data, ConnContext *context),
+	void *data);
+
+/* Put a connection into the PLAINTEXT state, first sending the
+ * other side a notice that we're doing so if we're currently ENCRYPTED,
+ * and we think he's logged in. Affects only the specified instance. */
+void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, const char *accountname, const char *protocol,
+	const char *username, otrl_instag_t instance);
+
+/* Put a connection into the PLAINTEXT state, first sending the
+ * other side a notice that we're doing so if we're currently ENCRYPTED,
+ * and we think he's logged in. Affects all matching instances. */
+void otrl_message_disconnect_all_instances(OtrlUserState us,
+	const OtrlMessageAppOps *ops, void *opdata, const char *accountname,
+	const char *protocol, const char *username);
+
+/* Initiate the Socialist Millionaires' Protocol */
+void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context, const unsigned char *secret,
+	size_t secretlen);
+
+/* Initiate the Socialist Millionaires' Protocol and send a prompt
+ * question to the buddy */
+void otrl_message_initiate_smp_q(OtrlUserState us,
+	const OtrlMessageAppOps *ops, void *opdata, ConnContext *context,
+	const char *question, const unsigned char *secret, size_t secretlen);
+
+/* Respond to a buddy initiating the Socialist Millionaires' Protocol */
+void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context, const unsigned char *secret,
+	size_t secretlen);
+
+/* Abort the SMP.  Called when an unexpected SMP message breaks the
+ * normal flow. */
+void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata, ConnContext *context);
+
+/* Get the current extra symmetric key (of size OTRL_EXTRAKEY_BYTES
+ * bytes) and let the other side know what we're going to use it for.
+ * The key is stored in symkey, which must already be allocated
+ * and OTRL_EXTRAKEY_BYTES bytes long. */
+gcry_error_t otrl_message_symkey(OtrlUserState us,
+	const OtrlMessageAppOps *ops, void *opdata, ConnContext *context,
+	unsigned int use, const unsigned char *usedata, size_t usedatalen,
+	unsigned char *symkey);
+
+/* If you do _not_ define a timer_control callback function, set a timer
+ * to go off every definterval =
+ * otrl_message_poll_get_default_interval(userstate) seconds, and call
+ * otrl_message_poll every time the timer goes off. */
+unsigned int otrl_message_poll_get_default_interval(OtrlUserState us);
+
+/* Call this function every so often, either as directed by the
+ * timer_control callback, or every definterval =
+ * otrl_message_poll_get_default_interval(userstate) seconds if you have
+ * no timer_control callback.  This function must be called from the
+ * main libotr thread.*/
+void otrl_message_poll(OtrlUserState us, const OtrlMessageAppOps *ops,
+	void *opdata);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/privkey-t.h b/libotr/libotr-4.1.1/src/privkey-t.h
new file mode 100644
index 0000000..7dd120e
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/privkey-t.h
@@ -0,0 +1,50 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __PRIVKEY_T_H__
+#define __PRIVKEY_T_H__
+
+#include <gcrypt.h>
+
+typedef struct s_OtrlPrivKey {
+    struct s_OtrlPrivKey *next;
+    struct s_OtrlPrivKey **tous;
+
+    char *accountname;
+    char *protocol;
+    unsigned short pubkey_type;
+    gcry_sexp_t privkey;
+    unsigned char *pubkey_data;
+    size_t pubkey_datalen;
+} OtrlPrivKey;
+
+#define OTRL_PUBKEY_TYPE_DSA 0x0000
+
+/* The list of privkeys currently being constructed, possibly in a
+ * background thread */
+typedef struct s_OtrlPendingPrivKey {
+    struct s_OtrlPendingPrivKey *next;
+    struct s_OtrlPendingPrivKey **tous;
+
+    char *accountname;
+    char *protocol;
+} OtrlPendingPrivKey;
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/privkey.c b/libotr/libotr-4.1.1/src/privkey.c
new file mode 100644
index 0000000..6e4bbe4
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/privkey.c
@@ -0,0 +1,938 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Rob Smits, Chris Alexander,
+ *  			      Willy Lew, Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "privkey.h"
+#include "serial.h"
+
+/* Convert a 20-byte hash value to a 45-byte human-readable value */
+void otrl_privkey_hash_to_human(
+	char human[OTRL_PRIVKEY_FPRINT_HUMAN_LEN],
+	const unsigned char hash[20])
+{
+    int word, byte;
+    char *p = human;
+
+    for(word=0; word<5; ++word) {
+	for(byte=0; byte<4; ++byte) {
+	    sprintf(p, "%02X", hash[word*4+byte]);
+	    p += 2;
+	}
+	*(p++) = ' ';
+    }
+    /* Change that last ' ' to a '\0' */
+    --p;
+    *p = '\0';
+}
+
+/* Calculate a human-readable hash of our DSA public key.  Return it in
+ * the passed fingerprint buffer.  Return NULL on error, or a pointer to
+ * the given buffer on success. */
+char *otrl_privkey_fingerprint(OtrlUserState us,
+	char fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN],
+	const char *accountname, const char *protocol)
+{
+    unsigned char hash[20];
+    OtrlPrivKey *p = otrl_privkey_find(us, accountname, protocol);
+
+    if (p) {
+	/* Calculate the hash */
+	gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data,
+		p->pubkey_datalen);
+
+	/* Now convert it to a human-readable format */
+	otrl_privkey_hash_to_human(fingerprint, hash);
+    } else {
+	return NULL;
+    }
+
+    return fingerprint;
+}
+
+/* Calculate a raw hash of our DSA public key.  Return it in the passed
+ * fingerprint buffer.  Return NULL on error, or a pointer to the given
+ * buffer on success. */
+unsigned char *otrl_privkey_fingerprint_raw(OtrlUserState us,
+	unsigned char hash[20], const char *accountname, const char *protocol)
+{
+    OtrlPrivKey *p = otrl_privkey_find(us, accountname, protocol);
+
+    if (p) {
+	/* Calculate the hash */
+	gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data,
+		p->pubkey_datalen);
+    } else {
+	return NULL;
+    }
+
+    return hash;
+}
+
+/* Create a public key block from a private key */
+static gcry_error_t make_pubkey(unsigned char **pubbufp, size_t *publenp,
+	gcry_sexp_t privkey)
+{
+    gcry_mpi_t p,q,g,y;
+    gcry_sexp_t dsas,ps,qs,gs,ys;
+    size_t np,nq,ng,ny;
+    enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+    unsigned char *bufp;
+    size_t lenp;
+
+    *pubbufp = NULL;
+    *publenp = 0;
+
+    /* Extract the public parameters */
+    dsas = gcry_sexp_find_token(privkey, "dsa", 0);
+    if (dsas == NULL) {
+	return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+    }
+    ps = gcry_sexp_find_token(dsas, "p", 0);
+    qs = gcry_sexp_find_token(dsas, "q", 0);
+    gs = gcry_sexp_find_token(dsas, "g", 0);
+    ys = gcry_sexp_find_token(dsas, "y", 0);
+    gcry_sexp_release(dsas);
+    if (!ps || !qs || !gs || !ys) {
+	gcry_sexp_release(ps);
+	gcry_sexp_release(qs);
+	gcry_sexp_release(gs);
+	gcry_sexp_release(ys);
+	return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+    }
+    p = gcry_sexp_nth_mpi(ps, 1, GCRYMPI_FMT_USG);
+    gcry_sexp_release(ps);
+    q = gcry_sexp_nth_mpi(qs, 1, GCRYMPI_FMT_USG);
+    gcry_sexp_release(qs);
+    g = gcry_sexp_nth_mpi(gs, 1, GCRYMPI_FMT_USG);
+    gcry_sexp_release(gs);
+    y = gcry_sexp_nth_mpi(ys, 1, GCRYMPI_FMT_USG);
+    gcry_sexp_release(ys);
+    if (!p || !q || !g || !y) {
+	gcry_mpi_release(p);
+	gcry_mpi_release(q);
+	gcry_mpi_release(g);
+	gcry_mpi_release(y);
+	return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+    }
+
+    *publenp = 0;
+    gcry_mpi_print(format, NULL, 0, &np, p);
+    *publenp += np + 4;
+    gcry_mpi_print(format, NULL, 0, &nq, q);
+    *publenp += nq + 4;
+    gcry_mpi_print(format, NULL, 0, &ng, g);
+    *publenp += ng + 4;
+    gcry_mpi_print(format, NULL, 0, &ny, y);
+    *publenp += ny + 4;
+
+    *pubbufp = malloc(*publenp);
+    if (*pubbufp == NULL) {
+	gcry_mpi_release(p);
+	gcry_mpi_release(q);
+	gcry_mpi_release(g);
+	gcry_mpi_release(y);
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    bufp = *pubbufp;
+    lenp = *publenp;
+
+    write_mpi(p,np,"P");
+    write_mpi(q,nq,"Q");
+    write_mpi(g,ng,"G");
+    write_mpi(y,ny,"Y");
+
+    gcry_mpi_release(p);
+    gcry_mpi_release(q);
+    gcry_mpi_release(g);
+    gcry_mpi_release(y);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Read a sets of private DSA keys from a file on disk into the given
+ * OtrlUserState. */
+gcry_error_t otrl_privkey_read(OtrlUserState us, const char *filename)
+{
+    FILE *privf;
+    gcry_error_t err;
+
+    /* Open the privkey file.  We use rb mode so that on WIN32, fread()
+     * reads the same number of bytes that fstat() indicates are in the
+     * file. */
+    privf = fopen(filename, "rb");
+    if (!privf) {
+	err = gcry_error_from_errno(errno);
+	return err;
+    }
+
+    err = otrl_privkey_read_FILEp(us, privf);
+
+    fclose(privf);
+    return err;
+}
+
+/* Read a sets of private DSA keys from a FILE* into the given
+ * OtrlUserState.  The FILE* must be open for reading. */
+gcry_error_t otrl_privkey_read_FILEp(OtrlUserState us, FILE *privf)
+{
+    int privfd;
+    struct stat st;
+    char *buf;
+    const char *token;
+    size_t tokenlen;
+    gcry_error_t err;
+    gcry_sexp_t allkeys;
+    int i;
+
+    if (!privf) return gcry_error(GPG_ERR_NO_ERROR);
+
+    /* Release any old ideas we had about our keys */
+    otrl_privkey_forget_all(us);
+
+    /* Load the data into a buffer */
+    privfd = fileno(privf);
+    if (fstat(privfd, &st)) {
+	err = gcry_error_from_errno(errno);
+	return err;
+    }
+    buf = malloc(st.st_size);
+    if (!buf && st.st_size > 0) {
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    if (fread(buf, st.st_size, 1, privf) != 1) {
+	err = gcry_error_from_errno(errno);
+	free(buf);
+	return err;
+    }
+
+    err = gcry_sexp_new(&allkeys, buf, st.st_size, 0);
+    free(buf);
+    if (err) {
+	return err;
+    }
+
+    token = gcry_sexp_nth_data(allkeys, 0, &tokenlen);
+    if (tokenlen != 8 || strncmp(token, "privkeys", 8)) {
+	gcry_sexp_release(allkeys);
+	return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+    }
+
+    /* Get each account */
+    for(i=1; i<gcry_sexp_length(allkeys); ++i) {
+	gcry_sexp_t names, protos, privs;
+	char *name, *proto;
+	gcry_sexp_t accounts;
+	OtrlPrivKey *p;
+
+	/* Get the ith "account" S-exp */
+	accounts = gcry_sexp_nth(allkeys, i);
+
+	/* It's really an "account" S-exp? */
+	token = gcry_sexp_nth_data(accounts, 0, &tokenlen);
+	if (tokenlen != 7 || strncmp(token, "account", 7)) {
+	    gcry_sexp_release(accounts);
+	    gcry_sexp_release(allkeys);
+	    return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+	}
+	/* Extract the name, protocol, and privkey S-exps */
+	names = gcry_sexp_find_token(accounts, "name", 0);
+	protos = gcry_sexp_find_token(accounts, "protocol", 0);
+	privs = gcry_sexp_find_token(accounts, "private-key", 0);
+	gcry_sexp_release(accounts);
+	if (!names || !protos || !privs) {
+	    gcry_sexp_release(names);
+	    gcry_sexp_release(protos);
+	    gcry_sexp_release(privs);
+	    gcry_sexp_release(allkeys);
+	    return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+	}
+	/* Extract the actual name and protocol */
+	token = gcry_sexp_nth_data(names, 1, &tokenlen);
+	if (!token) {
+	    gcry_sexp_release(names);
+	    gcry_sexp_release(protos);
+	    gcry_sexp_release(privs);
+	    gcry_sexp_release(allkeys);
+	    return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+	}
+	name = malloc(tokenlen + 1);
+	if (!name) {
+	    gcry_sexp_release(names);
+	    gcry_sexp_release(protos);
+	    gcry_sexp_release(privs);
+	    gcry_sexp_release(allkeys);
+	    return gcry_error(GPG_ERR_ENOMEM);
+	}
+	memmove(name, token, tokenlen);
+	name[tokenlen] = '\0';
+	gcry_sexp_release(names);
+
+	token = gcry_sexp_nth_data(protos, 1, &tokenlen);
+	if (!token) {
+	    free(name);
+	    gcry_sexp_release(protos);
+	    gcry_sexp_release(privs);
+	    gcry_sexp_release(allkeys);
+	    return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+	}
+	proto = malloc(tokenlen + 1);
+	if (!proto) {
+	    free(name);
+	    gcry_sexp_release(protos);
+	    gcry_sexp_release(privs);
+	    gcry_sexp_release(allkeys);
+	    return gcry_error(GPG_ERR_ENOMEM);
+	}
+	memmove(proto, token, tokenlen);
+	proto[tokenlen] = '\0';
+	gcry_sexp_release(protos);
+
+	/* Make a new OtrlPrivKey entry */
+	p = malloc(sizeof(*p));
+	if (!p) {
+	    free(name);
+	    free(proto);
+	    gcry_sexp_release(privs);
+	    gcry_sexp_release(allkeys);
+	    return gcry_error(GPG_ERR_ENOMEM);
+	}
+
+	/* Fill it in and link it up */
+	p->accountname = name;
+	p->protocol = proto;
+	p->pubkey_type = OTRL_PUBKEY_TYPE_DSA;
+	p->privkey = privs;
+	p->next = us->privkey_root;
+	if (p->next) {
+	    p->next->tous = &(p->next);
+	}
+	p->tous = &(us->privkey_root);
+	us->privkey_root = p;
+	err = make_pubkey(&(p->pubkey_data), &(p->pubkey_datalen), p->privkey);
+	if (err) {
+	    gcry_sexp_release(allkeys);
+	    otrl_privkey_forget(p);
+	    return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
+	}
+    }
+    gcry_sexp_release(allkeys);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+static OtrlPendingPrivKey *pending_find(OtrlUserState us,
+	const char *accountname, const char *protocol)
+{
+    OtrlPendingPrivKey *search = us->pending_root;
+
+    while (search) {
+	if (!strcmp(search->accountname, accountname) &&
+		!strcmp(search->protocol, protocol)) {
+	    /* Found it */
+	    return search;
+	}
+	search = search->next;
+    }
+    return NULL;
+}
+
+/* Insert an account/protocol pair into the pending privkey list of the
+ * given OtrlUserState and return a pointer to the new
+ * OtrlPendingPrivKey, or return NULL if it's already there. */
+static OtrlPendingPrivKey *pending_insert(OtrlUserState us,
+	const char *accountname, const char *protocol)
+{
+    /* See if it's already there */
+    OtrlPendingPrivKey *search = pending_find(us, accountname, protocol);
+
+    if (search) {
+	/* It is */
+	return NULL;
+    }
+
+    /* We'll insert it at the beginning of the list */
+    search = malloc(sizeof(*search));
+    if (!search) return NULL;
+
+    search->accountname = strdup(accountname);
+    search->protocol = strdup(protocol);
+
+    search->next = us->pending_root;
+    us->pending_root = search;
+    if (search->next) {
+	search->next->tous = &(search->next);
+    }
+    search->tous = &(us->pending_root);
+    return search;
+}
+
+static void pending_forget(OtrlPendingPrivKey *ppk)
+{
+    if (ppk) {
+	free(ppk->accountname);
+	free(ppk->protocol);
+
+	/* Re-link the list */
+	*(ppk->tous) = ppk->next;
+	if (ppk->next) {
+	    ppk->next->tous = ppk->tous;
+	}
+
+	free(ppk);
+    }
+}
+
+/* Free the memory associated with the pending privkey list */
+void otrl_privkey_pending_forget_all(OtrlUserState us)
+{
+    while(us->pending_root) {
+	pending_forget(us->pending_root);
+    }
+}
+
+static gcry_error_t sexp_write(FILE *privf, gcry_sexp_t sexp)
+{
+    size_t buflen;
+    char *buf;
+
+    buflen = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+    buf = malloc(buflen);
+    if (buf == NULL && buflen > 0) {
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, buf, buflen);
+
+    fprintf(privf, "%s", buf);
+    free(buf);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+static gcry_error_t account_write(FILE *privf, const char *accountname,
+	const char *protocol, gcry_sexp_t privkey)
+{
+    gcry_error_t err;
+    gcry_sexp_t names, protos;
+
+    fprintf(privf, " (account\n");
+
+    err = gcry_sexp_build(&names, NULL, "(name %s)", accountname);
+    if (!err) {
+	err = sexp_write(privf, names);
+	gcry_sexp_release(names);
+    }
+    if (!err) err = gcry_sexp_build(&protos, NULL, "(protocol %s)", protocol);
+    if (!err) {
+	err = sexp_write(privf, protos);
+	gcry_sexp_release(protos);
+    }
+    if (!err) err = sexp_write(privf, privkey);
+
+    fprintf(privf, " )\n");
+
+    return err;
+}
+
+struct s_pending_privkey_calc {
+    char *accountname;
+    char *protocol;
+    gcry_sexp_t privkey;
+};
+
+/* Begin a private key generation that will potentially take place in
+ * a background thread.  This routine must be called from the main
+ * thread.  It will set *newkeyp, which you can pass to
+ * otrl_privkey_generate_calculate in a background thread.  If it
+ * returns gcry_error(GPG_ERR_EEXIST), then a privkey creation for
+ * this accountname/protocol is already in progress, and *newkeyp will
+ * be set to NULL. */
+gcry_error_t otrl_privkey_generate_start(OtrlUserState us,
+	const char *accountname, const char *protocol, void **newkeyp)
+{
+    OtrlPendingPrivKey *found = pending_find(us, accountname, protocol);
+    struct s_pending_privkey_calc *ppc;
+
+    if (found) {
+	if (newkeyp) *newkeyp = NULL;
+	return gcry_error(GPG_ERR_EEXIST);
+    }
+
+    /* We're not already creating this key.  Mark it as in progress. */
+    pending_insert(us, accountname, protocol);
+
+    /* Allocate the working structure */
+    ppc = malloc(sizeof(*ppc));
+    ppc->accountname = strdup(accountname);
+    ppc->protocol = strdup(protocol);
+    ppc->privkey = NULL;
+
+    *newkeyp = ppc;
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Do the private key generation calculation.  You may call this from a
+ * background thread.  When it completes, call
+ * otrl_privkey_generate_finish from the _main_ thread. */
+gcry_error_t otrl_privkey_generate_calculate(void *newkey)
+{
+    struct s_pending_privkey_calc *ppc =
+	    (struct s_pending_privkey_calc *)newkey;
+    gcry_error_t err;
+    gcry_sexp_t key, parms;
+    static const char *parmstr = "(genkey (dsa (nbits 4:1024)))";
+
+    /* Create a DSA key */
+    err = gcry_sexp_new(&parms, parmstr, strlen(parmstr), 0);
+    if (err) {
+	return err;
+    }
+    err = gcry_pk_genkey(&key, parms);
+    gcry_sexp_release(parms);
+    if (err) {
+	return err;
+    }
+
+    /* Extract the privkey */
+    ppc->privkey = gcry_sexp_find_token(key, "private-key", 0);
+    gcry_sexp_release(key);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+static FILE* privkey_fopen(const char *filename, gcry_error_t *errp)
+{
+    FILE *privf;
+#ifndef WIN32
+    mode_t oldmask;
+#endif
+
+#ifndef WIN32
+    oldmask = umask(077);
+#endif
+    privf = fopen(filename, "w+b");
+    if (!privf && errp) {
+	*errp = gcry_error_from_errno(errno);
+    }
+#ifndef WIN32
+    umask(oldmask);
+#endif
+    return privf;
+}
+
+/* Call this from the main thread only, in the event that the background
+ * thread generating the key is cancelled.  The newkey is deallocated,
+ * and must not be used further. */
+void otrl_privkey_generate_cancelled(OtrlUserState us, void *newkey)
+{
+    struct s_pending_privkey_calc *ppc =
+	    (struct s_pending_privkey_calc *)newkey;
+
+    if (us) {
+	pending_forget(pending_find(us, ppc->accountname, ppc->protocol));
+    }
+
+    /* Deallocate ppc */
+    free(ppc->accountname);
+    free(ppc->protocol);
+    gcry_sexp_release(ppc->privkey);
+    free(ppc);
+}
+
+/* Call this from the main thread only.  It will write the newly created
+ * private key into the given file and store it in the OtrlUserState. */
+gcry_error_t otrl_privkey_generate_finish(OtrlUserState us,
+	void *newkey, const char *filename)
+{
+    gcry_error_t err;
+    FILE *privf = privkey_fopen(filename, &err);
+    if (!privf) {
+	return err;
+    }
+
+    err = otrl_privkey_generate_finish_FILEp(us, newkey, privf);
+
+    fclose(privf);
+    return err;
+}
+
+/* Call this from the main thread only.  It will write the newly created
+ * private key into the given FILE* (which must be open for reading and
+ * writing) and store it in the OtrlUserState. */
+gcry_error_t otrl_privkey_generate_finish_FILEp(OtrlUserState us,
+	void *newkey, FILE *privf)
+{
+    struct s_pending_privkey_calc *ppc =
+	    (struct s_pending_privkey_calc *)newkey;
+    gcry_error_t ret = gcry_error(GPG_ERR_INV_VALUE);
+
+    if (ppc && us && privf) {
+	OtrlPrivKey *p;
+
+	/* Output the other keys we know */
+	fprintf(privf, "(privkeys\n");
+
+	for (p=us->privkey_root; p; p=p->next) {
+	    /* Skip this one if our new key replaces it */
+	    if (!strcmp(p->accountname, ppc->accountname) &&
+		    !strcmp(p->protocol, ppc->protocol)) {
+		continue;
+	    }
+
+	    account_write(privf, p->accountname, p->protocol, p->privkey);
+	}
+	account_write(privf, ppc->accountname, ppc->protocol, ppc->privkey);
+	fprintf(privf, ")\n");
+
+	fseek(privf, 0, SEEK_SET);
+
+	ret = otrl_privkey_read_FILEp(us, privf);
+    }
+
+    otrl_privkey_generate_cancelled(us, newkey);
+
+    return ret;
+}
+
+/* Generate a private DSA key for a given account, storing it into a
+ * file on disk, and loading it into the given OtrlUserState.  Overwrite any
+ * previously generated keys for that account in that OtrlUserState. */
+gcry_error_t otrl_privkey_generate(OtrlUserState us, const char *filename,
+	const char *accountname, const char *protocol)
+{
+    gcry_error_t err;
+    FILE *privf = privkey_fopen(filename, &err);
+    if (!privf) {
+	return err;
+    }
+
+    err = otrl_privkey_generate_FILEp(us, privf, accountname, protocol);
+
+    fclose(privf);
+    return err;
+}
+
+/* Generate a private DSA key for a given account, storing it into a
+ * FILE*, and loading it into the given OtrlUserState.  Overwrite any
+ * previously generated keys for that account in that OtrlUserState.
+ * The FILE* must be open for reading and writing. */
+gcry_error_t otrl_privkey_generate_FILEp(OtrlUserState us, FILE *privf,
+	const char *accountname, const char *protocol)
+{
+    void *newkey = NULL;
+    gcry_error_t err;
+
+    err = otrl_privkey_generate_start(us, accountname, protocol, &newkey);
+    if (newkey) {
+	otrl_privkey_generate_calculate(newkey);
+	err = otrl_privkey_generate_finish_FILEp(us, newkey, privf);
+    }
+
+    return err;
+}
+
+/* Convert a hex character to a value */
+static unsigned int ctoh(char c)
+{
+    if (c >= '0' && c <= '9') return c-'0';
+    if (c >= 'a' && c <= 'f') return c-'a'+10;
+    if (c >= 'A' && c <= 'F') return c-'A'+10;
+    return 0;  /* Unknown hex char */
+}
+
+/* Read the fingerprint store from a file on disk into the given
+ * OtrlUserState.  Use add_app_data to add application data to each
+ * ConnContext so created. */
+gcry_error_t otrl_privkey_read_fingerprints(OtrlUserState us,
+	const char *filename,
+	void (*add_app_data)(void *data, ConnContext *context),
+	void  *data)
+{
+    gcry_error_t err;
+    FILE *storef;
+
+    storef = fopen(filename, "rb");
+    if (!storef) {
+	err = gcry_error_from_errno(errno);
+	return err;
+    }
+
+    err = otrl_privkey_read_fingerprints_FILEp(us, storef, add_app_data, data);
+
+    fclose(storef);
+    return err;
+}
+
+/* Read the fingerprint store from a FILE* into the given
+ * OtrlUserState.  Use add_app_data to add application data to each
+ * ConnContext so created.  The FILE* must be open for reading. */
+gcry_error_t otrl_privkey_read_fingerprints_FILEp(OtrlUserState us,
+	FILE *storef,
+	void (*add_app_data)(void *data, ConnContext *context),
+	void  *data)
+{
+    ConnContext *context;
+    char storeline[1000];
+    unsigned char fingerprint[20];
+    size_t maxsize = sizeof(storeline);
+
+    if (!storef) return gcry_error(GPG_ERR_NO_ERROR);
+
+    while(fgets(storeline, maxsize, storef)) {
+	char *username;
+	char *accountname;
+	char *protocol;
+	char *hex;
+	char *trust;
+	char *tab;
+	char *eol;
+	Fingerprint *fng;
+	int i, j;
+	/* Parse the line, which should be of the form:
+	 *    username\taccountname\tprotocol\t40_hex_nybbles\n          */
+	username = storeline;
+	tab = strchr(username, '\t');
+	if (!tab) continue;
+	*tab = '\0';
+
+	accountname = tab + 1;
+	tab = strchr(accountname, '\t');
+	if (!tab) continue;
+	*tab = '\0';
+
+	protocol = tab + 1;
+	tab = strchr(protocol, '\t');
+	if (!tab) continue;
+	*tab = '\0';
+
+	hex = tab + 1;
+	tab = strchr(hex, '\t');
+	if (!tab) {
+	    eol = strchr(hex, '\r');
+	    if (!eol) eol = strchr(hex, '\n');
+	    if (!eol) continue;
+	    *eol = '\0';
+	    trust = NULL;
+	} else {
+	    *tab = '\0';
+	    trust = tab + 1;
+	    eol = strchr(trust, '\r');
+	    if (!eol) eol = strchr(trust, '\n');
+	    if (!eol) continue;
+	    *eol = '\0';
+	}
+
+	if (strlen(hex) != 40) continue;
+	for(j=0, i=0; i<40; i+=2) {
+	    fingerprint[j++] = (ctoh(hex[i]) << 4) + (ctoh(hex[i+1]));
+	}
+	/* Get the context for this user, adding if not yet present */
+	context = otrl_context_find(us, username, accountname, protocol,
+		OTRL_INSTAG_MASTER, 1, NULL, add_app_data, data);
+	/* Add the fingerprint if not already there */
+	fng = otrl_context_find_fingerprint(context, fingerprint, 1, NULL);
+	otrl_context_set_trust(fng, trust);
+    }
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Write the fingerprint store from a given OtrlUserState to a file on disk. */
+gcry_error_t otrl_privkey_write_fingerprints(OtrlUserState us,
+	const char *filename)
+{
+    gcry_error_t err;
+    FILE *storef;
+
+    storef = fopen(filename, "wb");
+    if (!storef) {
+	err = gcry_error_from_errno(errno);
+	return err;
+    }
+
+    err = otrl_privkey_write_fingerprints_FILEp(us, storef);
+
+    fclose(storef);
+    return err;
+}
+
+/* Write the fingerprint store from a given OtrlUserState to a FILE*.
+ * The FILE* must be open for writing. */
+gcry_error_t otrl_privkey_write_fingerprints_FILEp(OtrlUserState us,
+	FILE *storef)
+{
+    ConnContext *context;
+    Fingerprint *fprint;
+
+    if (!storef) return gcry_error(GPG_ERR_NO_ERROR);
+
+    for(context = us->context_root; context; context = context->next) {
+	/* Fingerprints are only stored in the master contexts */
+	if (context->their_instance != OTRL_INSTAG_MASTER) continue;
+
+	/* Don't bother with the first (fingerprintless) entry. */
+	for (fprint = context->fingerprint_root.next; fprint;
+		fprint = fprint->next) {
+	    int i;
+	    fprintf(storef, "%s\t%s\t%s\t", context->username,
+		    context->accountname, context->protocol);
+	    for(i=0;i<20;++i) {
+		fprintf(storef, "%02x", fprint->fingerprint[i]);
+	    }
+	    fprintf(storef, "\t%s\n", fprint->trust ? fprint->trust : "");
+	}
+    }
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Fetch the private key from the given OtrlUserState associated with
+ * the given account */
+OtrlPrivKey *otrl_privkey_find(OtrlUserState us, const char *accountname,
+	const char *protocol)
+{
+    OtrlPrivKey *p;
+    if (!accountname || !protocol) return NULL;
+
+    for(p=us->privkey_root; p; p=p->next) {
+	if (!strcmp(p->accountname, accountname) &&
+		!strcmp(p->protocol, protocol)) {
+	    return p;
+	}
+    }
+    return NULL;
+}
+
+/* Forget a private key */
+void otrl_privkey_forget(OtrlPrivKey *privkey)
+{
+    free(privkey->accountname);
+    free(privkey->protocol);
+    gcry_sexp_release(privkey->privkey);
+    free(privkey->pubkey_data);
+
+    /* Re-link the list */
+    *(privkey->tous) = privkey->next;
+    if (privkey->next) {
+	privkey->next->tous = privkey->tous;
+    }
+
+    /* Free the privkey struct */
+    free(privkey);
+}
+
+/* Forget all private keys in a given OtrlUserState. */
+void otrl_privkey_forget_all(OtrlUserState us)
+{
+    while (us->privkey_root) {
+	otrl_privkey_forget(us->privkey_root);
+    }
+}
+
+/* Sign data using a private key.  The data must be small enough to be
+ * signed (i.e. already hashed, if necessary).  The signature will be
+ * returned in *sigp, which the caller must free().  Its length will be
+ * returned in *siglenp. */
+gcry_error_t otrl_privkey_sign(unsigned char **sigp, size_t *siglenp,
+	OtrlPrivKey *privkey, const unsigned char *data, size_t len)
+{
+    gcry_mpi_t r,s, datampi;
+    gcry_sexp_t dsas, rs, ss, sigs, datas;
+    size_t nr, ns;
+    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+
+    if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA)
+	return gcry_error(GPG_ERR_INV_VALUE);
+
+    *sigp = malloc(40);
+    if (*sigp == NULL) return gcry_error(GPG_ERR_ENOMEM);
+    *siglenp = 40;
+
+    if (len) {
+	gcry_mpi_scan(&datampi, GCRYMPI_FMT_USG, data, len, NULL);
+    } else {
+	datampi = gcry_mpi_set_ui(NULL, 0);
+    }
+    gcry_sexp_build(&datas, NULL, "(%m)", datampi);
+    gcry_mpi_release(datampi);
+    gcry_pk_sign(&sigs, datas, privkey->privkey);
+    gcry_sexp_release(datas);
+    dsas = gcry_sexp_find_token(sigs, "dsa", 0);
+    gcry_sexp_release(sigs);
+    rs = gcry_sexp_find_token(dsas, "r", 0);
+    ss = gcry_sexp_find_token(dsas, "s", 0);
+    gcry_sexp_release(dsas);
+    r = gcry_sexp_nth_mpi(rs, 1, GCRYMPI_FMT_USG);
+    gcry_sexp_release(rs);
+    s = gcry_sexp_nth_mpi(ss, 1, GCRYMPI_FMT_USG);
+    gcry_sexp_release(ss);
+    gcry_mpi_print(format, NULL, 0, &nr, r);
+    gcry_mpi_print(format, NULL, 0, &ns, s);
+    memset(*sigp, 0, 40);
+    gcry_mpi_print(format, (*sigp)+(20-nr), nr, NULL, r);
+    gcry_mpi_print(format, (*sigp)+20+(20-ns), ns, NULL, s);
+    gcry_mpi_release(r);
+    gcry_mpi_release(s);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Verify a signature on data using a public key.  The data must be
+ * small enough to be signed (i.e. already hashed, if necessary). */
+gcry_error_t otrl_privkey_verify(const unsigned char *sigbuf, size_t siglen,
+	unsigned short pubkey_type, gcry_sexp_t pubs,
+	const unsigned char *data, size_t len)
+{
+    gcry_error_t err;
+    gcry_mpi_t datampi,r,s;
+    gcry_sexp_t datas, sigs;
+
+    if (pubkey_type != OTRL_PUBKEY_TYPE_DSA || siglen != 40)
+	return gcry_error(GPG_ERR_INV_VALUE);
+
+    if (len) {
+	gcry_mpi_scan(&datampi, GCRYMPI_FMT_USG, data, len, NULL);
+    } else {
+	datampi = gcry_mpi_set_ui(NULL, 0);
+    }
+    gcry_sexp_build(&datas, NULL, "(%m)", datampi);
+    gcry_mpi_release(datampi);
+    gcry_mpi_scan(&r, GCRYMPI_FMT_USG, sigbuf, 20, NULL);
+    gcry_mpi_scan(&s, GCRYMPI_FMT_USG, sigbuf+20, 20, NULL);
+    gcry_sexp_build(&sigs, NULL, "(sig-val (dsa (r %m)(s %m)))", r, s);
+    gcry_mpi_release(r);
+    gcry_mpi_release(s);
+
+    err = gcry_pk_verify(sigs, datas, pubs);
+    gcry_sexp_release(datas);
+    gcry_sexp_release(sigs);
+
+    return err;
+}
+
diff --git a/libotr/libotr-4.1.1/src/privkey.h b/libotr/libotr-4.1.1/src/privkey.h
new file mode 100644
index 0000000..3b2c173
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/privkey.h
@@ -0,0 +1,154 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __PRIVKEY_H__
+#define __PRIVKEY_H__
+
+#include <stdio.h>
+#include "privkey-t.h"
+#include "userstate.h"
+
+/* The length of a string representing a human-readable version of a
+ * fingerprint (including the trailing NUL) */
+#define OTRL_PRIVKEY_FPRINT_HUMAN_LEN 45
+
+/* Convert a 20-byte hash value to a 45-byte human-readable value */
+void otrl_privkey_hash_to_human(
+	char human[OTRL_PRIVKEY_FPRINT_HUMAN_LEN],
+	const unsigned char hash[20]);
+
+/* Calculate a human-readable hash of our DSA public key.  Return it in
+ * the passed fingerprint buffer.  Return NULL on error, or a pointer to
+ * the given buffer on success. */
+char *otrl_privkey_fingerprint(OtrlUserState us,
+	char fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN],
+	const char *accountname, const char *protocol);
+
+/* Calculate a raw hash of our DSA public key.  Return it in the passed
+ * fingerprint buffer.  Return NULL on error, or a pointer to the given
+ * buffer on success. */
+unsigned char *otrl_privkey_fingerprint_raw(OtrlUserState us,
+	unsigned char hash[20], const char *accountname, const char *protocol);
+
+/* Read a sets of private DSA keys from a file on disk into the given
+ * OtrlUserState. */
+gcry_error_t otrl_privkey_read(OtrlUserState us, const char *filename);
+
+/* Read a sets of private DSA keys from a FILE* into the given
+ * OtrlUserState.  The FILE* must be open for reading. */
+gcry_error_t otrl_privkey_read_FILEp(OtrlUserState us, FILE *privf);
+
+/* Free the memory associated with the pending privkey list */
+void otrl_privkey_pending_forget_all(OtrlUserState us);
+
+/* Begin a private key generation that will potentially take place in
+ * a background thread.  This routine must be called from the main
+ * thread.  It will set *newkeyp, which you can pass to
+ * otrl_privkey_generate_calculate in a background thread.  If it
+ * returns gcry_error(GPG_ERR_EEXIST), then a privkey creation for
+ * this accountname/protocol is already in progress, and *newkeyp will
+ * be set to NULL. */
+gcry_error_t otrl_privkey_generate_start(OtrlUserState us,
+	const char *accountname, const char *protocol, void **newkeyp);
+
+/* Do the private key generation calculation.  You may call this from a
+ * background thread.  When it completes, call
+ * otrl_privkey_generate_finish from the _main_ thread. */
+gcry_error_t otrl_privkey_generate_calculate(void *newkey);
+
+/* Call this from the main thread only.  It will write the newly created
+ * private key into the given file and store it in the OtrlUserState. */
+gcry_error_t otrl_privkey_generate_finish(OtrlUserState us,
+	void *newkey, const char *filename);
+
+/* Call this from the main thread only.  It will write the newly created
+ * private key into the given FILE* (which must be open for reading and
+ * writing) and store it in the OtrlUserState. */
+gcry_error_t otrl_privkey_generate_finish_FILEp(OtrlUserState us,
+	void *newkey, FILE *privf);
+
+/* Call this from the main thread only, in the event that the background
+ * thread generating the key is cancelled.  The newkey is deallocated,
+ * and must not be used further. */
+void otrl_privkey_generate_cancelled(OtrlUserState us, void *newkey);
+
+/* Generate a private DSA key for a given account, storing it into a
+ * file on disk, and loading it into the given OtrlUserState.  Overwrite any
+ * previously generated keys for that account in that OtrlUserState. */
+gcry_error_t otrl_privkey_generate(OtrlUserState us, const char *filename,
+	const char *accountname, const char *protocol);
+
+/* Generate a private DSA key for a given account, storing it into a
+ * FILE*, and loading it into the given OtrlUserState.  Overwrite any
+ * previously generated keys for that account in that OtrlUserState.
+ * The FILE* must be open for reading and writing. */
+gcry_error_t otrl_privkey_generate_FILEp(OtrlUserState us, FILE *privf,
+	const char *accountname, const char *protocol);
+
+/* Read the fingerprint store from a file on disk into the given
+ * OtrlUserState.  Use add_app_data to add application data to each
+ * ConnContext so created. */
+gcry_error_t otrl_privkey_read_fingerprints(OtrlUserState us,
+	const char *filename,
+	void (*add_app_data)(void *data, ConnContext *context),
+	void  *data);
+
+/* Read the fingerprint store from a FILE* into the given
+ * OtrlUserState.  Use add_app_data to add application data to each
+ * ConnContext so created.  The FILE* must be open for reading. */
+gcry_error_t otrl_privkey_read_fingerprints_FILEp(OtrlUserState us,
+	FILE *storef,
+	void (*add_app_data)(void *data, ConnContext *context),
+	void  *data);
+
+/* Write the fingerprint store from a given OtrlUserState to a file on disk. */
+gcry_error_t otrl_privkey_write_fingerprints(OtrlUserState us,
+	const char *filename);
+
+/* Write the fingerprint store from a given OtrlUserState to a FILE*.
+ * The FILE* must be open for writing. */
+gcry_error_t otrl_privkey_write_fingerprints_FILEp(OtrlUserState us,
+	FILE *storef);
+
+/* Fetch the private key from the given OtrlUserState associated with
+ * the given account */
+OtrlPrivKey *otrl_privkey_find(OtrlUserState us, const char *accountname,
+	const char *protocol);
+
+/* Forget a private key */
+void otrl_privkey_forget(OtrlPrivKey *privkey);
+
+/* Forget all private keys in a given OtrlUserState. */
+void otrl_privkey_forget_all(OtrlUserState us);
+
+/* Sign data using a private key.  The data must be small enough to be
+ * signed (i.e. already hashed, if necessary).  The signature will be
+ * returned in *sigp, which the caller must free().  Its length will be
+ * returned in *siglenp. */
+gcry_error_t otrl_privkey_sign(unsigned char **sigp, size_t *siglenp,
+	OtrlPrivKey *privkey, const unsigned char *data, size_t len);
+
+/* Verify a signature on data using a public key.  The data must be
+ * small enough to be signed (i.e. already hashed, if necessary). */
+gcry_error_t otrl_privkey_verify(const unsigned char *sigbuf, size_t siglen,
+	unsigned short pubkey_type, gcry_sexp_t pubs,
+	const unsigned char *data, size_t len);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/proto.c b/libotr/libotr-4.1.1/src/proto.c
new file mode 100644
index 0000000..8d82dc1
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/proto.c
@@ -0,0 +1,1081 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2016  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* OTR Protocol implementation.  This file should be independent of
+ * gaim, so that it can be used to make other clients. */
+
+/* system headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "b64.h"
+#include "privkey.h"
+#include "proto.h"
+#include "mem.h"
+#include "version.h"
+#include "tlv.h"
+#include "serial.h"
+
+#if OTRL_DEBUGGING
+extern const char *OTRL_DEBUGGING_DEBUGSTR;
+#endif
+
+/* For now, we need to know the API version the client is using so that
+ * we don't use any UI callbacks it hasn't set. */
+unsigned int otrl_api_version = 0;
+
+/* Initialize the OTR library.  Pass the version of the API you are
+ * using. */
+gcry_error_t otrl_init(unsigned int ver_major, unsigned int ver_minor,
+	unsigned int ver_sub)
+{
+    unsigned int api_version;
+
+    /* The major versions have to match, and you can't be using a newer
+     * minor version than we expect. */
+    if (ver_major != OTRL_VERSION_MAJOR || ver_minor > OTRL_VERSION_MINOR) {
+	fprintf(stderr, "Expected libotr API version %u.%u.%u incompatible "
+		"with actual version %u.%u.%u.  Aborting.\n",
+		ver_major, ver_minor, ver_sub,
+		OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, OTRL_VERSION_SUB);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Set the API version.  If we get called multiple times for some
+     * reason, take the smallest value. */
+    api_version = (ver_major << 16) | (ver_minor << 8) | (ver_sub);
+    if (otrl_api_version == 0 || otrl_api_version > api_version) {
+	otrl_api_version = api_version;
+    }
+
+    /* Initialize the memory module */
+    otrl_mem_init();
+
+    /* Initialize the DH module */
+    otrl_dh_init();
+
+    /* Initialize the SM module */
+    otrl_sm_init();
+
+#if OTRL_DEBUGGING
+    /* Inform the user that debugging is available */
+    fprintf(stderr, "\nlibotr debugging is available.  Type %s in a message\n"
+	    "  to see debug info.\n\n", OTRL_DEBUGGING_DEBUGSTR);
+#endif
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Return a pointer to a static string containing the version number of
+ * the OTR library. */
+const char *otrl_version(void)
+{
+    return OTRL_VERSION;
+}
+
+/* Store some MAC keys to be revealed later */
+static gcry_error_t reveal_macs(ConnContext *context,
+	DH_sesskeys *sess1, DH_sesskeys *sess2)
+{
+    unsigned int numnew = sess1->rcvmacused + sess1->sendmacused +
+	sess2->rcvmacused + sess2->sendmacused;
+    unsigned int newnumsaved;
+    unsigned char *newmacs;
+
+    /* Is there anything to do? */
+    if (numnew == 0) return gcry_error(GPG_ERR_NO_ERROR);
+
+    newnumsaved = context->context_priv->numsavedkeys + numnew;
+    newmacs = realloc(context->context_priv->saved_mac_keys,
+	    newnumsaved * 20);
+    if (!newmacs) {
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    if (sess1->rcvmacused) {
+	memmove(newmacs + context->context_priv->numsavedkeys * 20,
+		sess1->rcvmackey, 20);
+	context->context_priv->numsavedkeys++;
+    }
+    if (sess1->sendmacused) {
+	memmove(newmacs + context->context_priv->numsavedkeys * 20,
+		sess1->sendmackey, 20);
+	context->context_priv->numsavedkeys++;
+    }
+    if (sess2->rcvmacused) {
+	memmove(newmacs + context->context_priv->numsavedkeys * 20,
+		sess2->rcvmackey, 20);
+	context->context_priv->numsavedkeys++;
+    }
+    if (sess2->sendmacused) {
+	memmove(newmacs + context->context_priv->numsavedkeys * 20,
+		sess2->sendmackey, 20);
+	context->context_priv->numsavedkeys++;
+    }
+    context->context_priv->saved_mac_keys = newmacs;
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Make a new DH key for us, and rotate old old ones.  Be sure to keep
+ * the sesskeys array in sync. */
+static gcry_error_t rotate_dh_keys(ConnContext *context)
+{
+    gcry_error_t err;
+
+    /* Rotate the keypair */
+    otrl_dh_keypair_free(&(context->context_priv->our_old_dh_key));
+    memmove(&(context->context_priv->our_old_dh_key),
+	    &(context->context_priv->our_dh_key),
+	    sizeof(DH_keypair));
+
+    /* Rotate the session keys */
+    err = reveal_macs(context, &(context->context_priv->sesskeys[1][0]),
+	    &(context->context_priv->sesskeys[1][1]));
+    if (err) return err;
+    otrl_dh_session_free(&(context->context_priv->sesskeys[1][0]));
+    otrl_dh_session_free(&(context->context_priv->sesskeys[1][1]));
+    memmove(&(context->context_priv->sesskeys[1][0]),
+	    &(context->context_priv->sesskeys[0][0]),
+	    sizeof(DH_sesskeys));
+    memmove(&(context->context_priv->sesskeys[1][1]),
+	    &(context->context_priv->sesskeys[0][1]),
+	    sizeof(DH_sesskeys));
+
+    /* Create a new DH key */
+    otrl_dh_gen_keypair(DH1536_GROUP_ID, &(context->context_priv->our_dh_key));
+    context->context_priv->our_keyid++;
+
+    /* Make the session keys */
+    if (context->context_priv->their_y) {
+	err = otrl_dh_session(&(context->context_priv->sesskeys[0][0]),
+		&(context->context_priv->our_dh_key),
+		context->context_priv->their_y);
+	if (err) return err;
+    } else {
+	otrl_dh_session_blank(&(context->context_priv->sesskeys[0][0]));
+    }
+    if (context->context_priv->their_old_y) {
+	err = otrl_dh_session(&(context->context_priv->sesskeys[0][1]),
+		&(context->context_priv->our_dh_key),
+		context->context_priv->their_old_y);
+	if (err) return err;
+    } else {
+	otrl_dh_session_blank(&(context->context_priv->sesskeys[0][1]));
+    }
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Rotate in a new DH public key for our correspondent.  Be sure to keep
+ * the sesskeys array in sync. */
+static gcry_error_t rotate_y_keys(ConnContext *context, gcry_mpi_t new_y)
+{
+    gcry_error_t err;
+
+    /* Rotate the public key */
+    gcry_mpi_release(context->context_priv->their_old_y);
+    context->context_priv->their_old_y = context->context_priv->their_y;
+
+    /* Rotate the session keys */
+    err = reveal_macs(context, &(context->context_priv->sesskeys[0][1]),
+	    &(context->context_priv->sesskeys[1][1]));
+    if (err) return err;
+    otrl_dh_session_free(&(context->context_priv->sesskeys[0][1]));
+    otrl_dh_session_free(&(context->context_priv->sesskeys[1][1]));
+    memmove(&(context->context_priv->sesskeys[0][1]),
+	    &(context->context_priv->sesskeys[0][0]),
+	    sizeof(DH_sesskeys));
+    memmove(&(context->context_priv->sesskeys[1][1]),
+	    &(context->context_priv->sesskeys[1][0]),
+	    sizeof(DH_sesskeys));
+
+    /* Copy in the new public key */
+    context->context_priv->their_y = gcry_mpi_copy(new_y);
+    context->context_priv->their_keyid++;
+
+    /* Make the session keys */
+    err = otrl_dh_session(&(context->context_priv->sesskeys[0][0]),
+	    &(context->context_priv->our_dh_key),
+	    context->context_priv->their_y);
+    if (err) return err;
+    err = otrl_dh_session(&(context->context_priv->sesskeys[1][0]),
+	    &(context->context_priv->our_old_dh_key),
+	    context->context_priv->their_y);
+    if (err) return err;
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Return a pointer to a newly-allocated OTR query message, customized
+ * with our name.  The caller should free() the result when he's done
+ * with it. */
+char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy)
+{
+    char *msg;
+    int v1_supported, v2_supported, v3_supported;
+    char *version_tag;
+    char *bufp;
+    /* Don't use g_strdup_printf here, because someone (not us) is going
+     * to free() the *message pointer, not g_free() it.  We can't
+     * require that they g_free() it, because this pointer will probably
+     * get passed to the main IM application for processing (and
+     * free()ing). */
+    const char *format = "?OTR%s\n<b>%s</b> has requested an "
+	    "<a href=\"https://otr.cypherpunks.ca/\">Off-the-Record "
+	    "private conversation</a>.  However, you do not have a plugin "
+	    "to support that.\nSee <a href=\"https://otr.cypherpunks.ca/\">"
+	    "https://otr.cypherpunks.ca/</a> for more information.";
+
+    /* Figure out the version tag */
+    v1_supported = (policy & OTRL_POLICY_ALLOW_V1);
+    v2_supported = (policy & OTRL_POLICY_ALLOW_V2);
+    v3_supported = (policy & OTRL_POLICY_ALLOW_V3);
+    version_tag = malloc(8);
+    bufp = version_tag;
+    if (v1_supported) {
+	*bufp = '?';
+	bufp++;
+    }
+    if (v2_supported || v3_supported) {
+	*bufp = 'v';
+	bufp++;
+	if (v2_supported) {
+	    *bufp = '2';
+	    bufp++;
+	}
+	if (v3_supported) {
+	    *bufp = '3';
+	    bufp++;
+	}
+	*bufp = '?';
+	bufp++;
+    }
+    *bufp = '\0';
+
+    /* Remove two "%s", add '\0' */
+    msg = malloc(strlen(format) + strlen(version_tag) + strlen(ourname) - 3);
+    if (!msg) {
+	free(version_tag);
+	return NULL;
+    }
+    sprintf(msg, format, version_tag, ourname);
+    free(version_tag);
+    return msg;
+}
+
+/* Return the best version of OTR support by both sides, given an OTR
+ * Query Message and the local policy. */
+unsigned int otrl_proto_query_bestversion(const char *otrquerymsg,
+	OtrlPolicy policy)
+{
+    char *otrtag;
+    unsigned int query_versions = 0;
+
+
+    otrtag = strstr(otrquerymsg, "?OTR");
+    if (!otrtag) {
+	return 0;
+    }
+    otrtag += 4;
+
+    if (*otrtag == '?') {
+	query_versions = (1<<0);
+	++otrtag;
+    }
+    if (*otrtag == 'v') {
+	for(++otrtag; *otrtag && *otrtag != '?'; ++otrtag) {
+	    switch(*otrtag) {
+		case '2':
+		    query_versions |= (1<<1);
+		    break;
+		case '3':
+		    query_versions |= (1<<2);
+		    break;
+	    }
+	}
+    }
+
+    if ((policy & OTRL_POLICY_ALLOW_V3) && (query_versions & (1<<2))) {
+	return 3;
+    }
+    if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) {
+	return 2;
+    }
+    if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) {
+	return 1;
+    }
+    return 0;
+}
+
+/* Locate any whitespace tag in this message, and return the best
+ * version of OTR support on both sides.  Set *starttagp and *endtagp to
+ * the start and end of the located tag, so that it can be snipped out. */
+unsigned int otrl_proto_whitespace_bestversion(const char *msg,
+	const char **starttagp, const char **endtagp, OtrlPolicy policy)
+{
+    const char *starttag, *endtag;
+    unsigned int query_versions = 0;
+
+    *starttagp = NULL;
+    *endtagp = NULL;
+
+    starttag = strstr(msg, OTRL_MESSAGE_TAG_BASE);
+    if (!starttag) return 0;
+
+    endtag = starttag + strlen(OTRL_MESSAGE_TAG_BASE);
+
+    /* Look for groups of 8 spaces and/or tabs */
+    while(1) {
+	int i;
+	int allwhite = 1;
+	for(i=0;i<8;++i) {
+	    if (endtag[i] != ' ' && endtag[i] != '\t') {
+		allwhite = 0;
+		break;
+	    }
+	}
+	if (allwhite) {
+	    if (!strncmp(endtag, OTRL_MESSAGE_TAG_V1, 8)) {
+		query_versions |= (1<<0);
+	    }
+	    if (!strncmp(endtag, OTRL_MESSAGE_TAG_V2, 8)) {
+		query_versions |= (1<<1);
+	    }
+	    if (!strncmp(endtag, OTRL_MESSAGE_TAG_V3, 8)) {
+		query_versions |= (1<<2);
+	    }
+	    endtag += 8;
+	} else {
+	    break;
+	}
+    }
+
+    *starttagp = starttag;
+    *endtagp = endtag;
+
+    if ((policy & OTRL_POLICY_ALLOW_V3) && (query_versions & (1<<2))) {
+	return 3;
+    }
+    if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) {
+	return 2;
+    }
+    if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) {
+	return 1;
+    }
+    return 0;
+}
+
+/* Find the message type. */
+OtrlMessageType otrl_proto_message_type(const char *message)
+{
+    char *otrtag;
+
+    otrtag = strstr(message, "?OTR");
+
+    if (!otrtag) {
+	if (strstr(message, OTRL_MESSAGE_TAG_BASE)) {
+	    return OTRL_MSGTYPE_TAGGEDPLAINTEXT;
+	} else {
+	    return OTRL_MSGTYPE_NOTOTR;
+	}
+    }
+
+    if (!strncmp(otrtag, "?OTR:AAM", 8) || !strncmp(otrtag, "?OTR:AAI", 8)) {
+	switch(*(otrtag + 8)) {
+	    case 'C': return OTRL_MSGTYPE_DH_COMMIT;
+	    case 'K': return OTRL_MSGTYPE_DH_KEY;
+	    case 'R': return OTRL_MSGTYPE_REVEALSIG;
+	    case 'S': return OTRL_MSGTYPE_SIGNATURE;
+	    case 'D': return OTRL_MSGTYPE_DATA;
+	}
+    } else {
+	if (!strncmp(otrtag, "?OTR?", 5)) return OTRL_MSGTYPE_QUERY;
+	if (!strncmp(otrtag, "?OTRv", 5)) return OTRL_MSGTYPE_QUERY;
+	if (!strncmp(otrtag, "?OTR:AAEK", 9)) return OTRL_MSGTYPE_V1_KEYEXCH;
+	if (!strncmp(otrtag, "?OTR:AAED", 9)) return OTRL_MSGTYPE_DATA;
+	if (!strncmp(otrtag, "?OTR Error:", 11)) return OTRL_MSGTYPE_ERROR;
+    }
+    return OTRL_MSGTYPE_UNKNOWN;
+}
+
+/* Find the message version. */
+int otrl_proto_message_version(const char *message)
+{
+    char *otrtag;
+
+    otrtag = strstr(message, "?OTR");
+
+    if (!otrtag) {
+	return 0;
+    }
+
+    if (!strncmp(otrtag, "?OTR:AAM", 8))
+	return 3;
+    if (!strncmp(otrtag, "?OTR:AAI", 8))
+	return 2;
+    if (!strncmp(otrtag, "?OTR:AAE", 8))
+	return 1;
+
+    return 0;
+}
+
+/* Find the instance tags in this message */
+gcry_error_t otrl_proto_instance(const char *otrmsg,
+	unsigned int *instance_from, unsigned int *instance_to)
+{
+    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
+
+    const char *otrtag = otrmsg;
+    unsigned char *bufp = NULL;
+    unsigned char *bufp_head = NULL;
+    size_t lenp;
+
+    if (!otrtag || strncmp(otrtag, "?OTR:AAM", 8)) {
+	goto invval;
+    }
+
+    if (strlen(otrtag) < 21 ) goto invval;
+
+    /* Decode and extract instance tag */
+    bufp = malloc(OTRL_B64_MAX_DECODED_SIZE(12));
+    bufp_head = bufp;
+    lenp = otrl_base64_decode(bufp, otrtag+9, 12);
+    read_int(*instance_from);
+    read_int(*instance_to);
+    free(bufp_head);
+    return gcry_error(GPG_ERR_NO_ERROR);
+invval:
+    free(bufp_head);
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    return err;
+}
+
+/* Create an OTR Data message.  Pass the plaintext as msg, and an
+ * optional chain of TLVs.  A newly-allocated string will be returned in
+ * *encmessagep. Put the current extra symmetric key into extrakey
+ * (if non-NULL). */
+gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
+	const char *msg, const OtrlTLV *tlvs, unsigned char flags,
+	unsigned char *extrakey)
+{
+    size_t justmsglen = strlen(msg);
+    size_t msglen = justmsglen + 1 + otrl_tlv_seriallen(tlvs);
+    size_t buflen;
+    size_t pubkeylen;
+    unsigned char *buf = NULL;
+    unsigned char *bufp;
+    size_t lenp;
+    DH_sesskeys *sess = &(context->context_priv->sesskeys[1][0]);
+    gcry_error_t err;
+    size_t reveallen = 20 * context->context_priv->numsavedkeys;
+    char *base64buf = NULL;
+    unsigned char *msgbuf = NULL;
+    enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+    char *msgdup;
+    int version = context->protocol_version;
+
+    *encmessagep = NULL;
+
+    /* Make sure we're actually supposed to be able to encrypt */
+    if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED ||
+	    context->context_priv->their_keyid == 0) {
+	return gcry_error(GPG_ERR_CONFLICT);
+    }
+
+    /* We need to copy the incoming msg, since it might be an alias for
+     * context->lastmessage, which we'll be freeing soon. */
+    msgdup = gcry_malloc_secure(justmsglen + 1);
+    if (msgdup == NULL) {
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    strcpy(msgdup, msg);
+
+    /* Header, msg flags, send keyid, recv keyid, counter, msg len, msg
+     * len of revealed mac keys, revealed mac keys, MAC */
+    buflen = OTRL_HEADER_LEN + (version == 3 ? 8 : 0)
+	+ (version == 2 || version == 3 ? 1 : 0) + 4 + 4
+	+ 8 + 4 + msglen + 4 + reveallen + 20;
+    gcry_mpi_print(format, NULL, 0, &pubkeylen,
+	    context->context_priv->our_dh_key.pub);
+    buflen += pubkeylen + 4;
+    buf = malloc(buflen);
+    msgbuf = gcry_malloc_secure(msglen);
+    if (buf == NULL || msgbuf == NULL) {
+	free(buf);
+	gcry_free(msgbuf);
+	gcry_free(msgdup);
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    memmove(msgbuf, msgdup, justmsglen);
+    msgbuf[justmsglen] = '\0';
+    otrl_tlv_serialize(msgbuf + justmsglen + 1, tlvs);
+    bufp = buf;
+    lenp = buflen;
+    if (version == 1) {
+	memmove(bufp, "\x00\x01\x03", 3);  /* header */
+    } else if (version == 2) {
+	memmove(bufp, "\x00\x02\x03", 3);  /* header */
+    } else {
+	memmove(bufp, "\x00\x03\x03", 3);  /* header */
+    }
+
+    debug_data("Header", bufp, 3);
+    bufp += 3; lenp -= 3;
+
+    if (version == 3) {
+	/* v3 instance tags */
+	write_int(context->our_instance);
+	debug_int("Sender instag", bufp-4);
+	write_int(context->their_instance);
+	debug_int("Recipient instag", bufp-4);
+    }
+
+    if (version == 2 || version == 3) {
+	bufp[0] = flags;
+	bufp += 1; lenp -= 1;
+    }
+
+    write_int(context->context_priv->our_keyid-1); /* sender keyid */
+    debug_int("Sender keyid", bufp-4);
+    write_int(context->context_priv->their_keyid); /* recipient keyid */
+    debug_int("Recipient keyid", bufp-4);
+
+    write_mpi(context->context_priv->our_dh_key.pub, pubkeylen, "Y");  /* Y */
+
+    otrl_dh_incctr(sess->sendctr);
+    memmove(bufp, sess->sendctr, 8);      /* Counter (top 8 bytes only) */
+    debug_data("Counter", bufp, 8);
+    bufp += 8; lenp -= 8;
+
+    write_int(msglen);                        /* length of encrypted data */
+    debug_int("Msg len", bufp-4);
+
+    err = gcry_cipher_reset(sess->sendenc);
+    if (err) goto err;
+    err = gcry_cipher_setctr(sess->sendenc, sess->sendctr, 16);
+    if (err) goto err;
+    err = gcry_cipher_encrypt(sess->sendenc, bufp, msglen, msgbuf, msglen);
+    if (err) goto err;                              /* encrypted data */
+    debug_data("Enc data", bufp, msglen);
+    bufp += msglen;
+    lenp -= msglen;
+
+    gcry_md_reset(sess->sendmac);
+    gcry_md_write(sess->sendmac, buf, bufp-buf);
+    memmove(bufp, gcry_md_read(sess->sendmac, GCRY_MD_SHA1), 20);
+    debug_data("MAC", bufp, 20);
+    bufp += 20;                                         /* MAC */
+    lenp -= 20;
+
+    write_int(reveallen);                     /* length of revealed MAC keys */
+    debug_int("Revealed MAC length", bufp-4);
+
+    if (reveallen > 0) {
+	memmove(bufp, context->context_priv->saved_mac_keys, reveallen);
+	debug_data("Revealed MAC data", bufp, reveallen);
+	bufp += reveallen; lenp -= reveallen;
+	free(context->context_priv->saved_mac_keys);
+	context->context_priv->saved_mac_keys = NULL;
+	context->context_priv->numsavedkeys = 0;
+    }
+
+    assert(lenp == 0);
+
+    /* Make the base64-encoding. */
+    base64buf = otrl_base64_otr_encode(buf, buflen);
+    if (base64buf == NULL) {
+	err = gcry_error(GPG_ERR_ENOMEM);
+	goto err;
+    }
+
+    free(buf);
+    gcry_free(msgbuf);
+    *encmessagep = base64buf;
+    gcry_free(context->context_priv->lastmessage);
+    context->context_priv->lastmessage = NULL;
+    context->context_priv->may_retransmit = 0;
+    if (msglen > 0) {
+	context->context_priv->lastmessage = gcry_malloc_secure(justmsglen + 1);
+	if (context->context_priv->lastmessage) {
+	    strcpy(context->context_priv->lastmessage, msgdup);
+	}
+    }
+    gcry_free(msgdup);
+
+    /* Save a copy of the current extra key */
+    if (extrakey) {
+	memmove(extrakey, sess->extrakey, OTRL_EXTRAKEY_BYTES);
+    }
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+err:
+    free(buf);
+    gcry_free(msgbuf);
+    gcry_free(msgdup);
+    *encmessagep = NULL;
+    return err;
+}
+
+/* Extract the flags from an otherwise unreadable Data Message. */
+gcry_error_t otrl_proto_data_read_flags(const char *datamsg,
+	unsigned char *flagsp)
+{
+    char *otrtag, *endtag;
+    unsigned char *rawmsg = NULL;
+    unsigned char *bufp;
+    size_t msglen, rawlen, lenp;
+    unsigned char version;
+
+    if (flagsp) *flagsp = 0;
+    otrtag = strstr(datamsg, "?OTR:");
+    if (!otrtag) {
+	goto invval;
+    }
+    endtag = strchr(otrtag, '.');
+    if (endtag) {
+	msglen = endtag-otrtag;
+    } else {
+	msglen = strlen(otrtag);
+    }
+
+    /* Skip over the "?OTR:" */
+    otrtag += 5;
+    msglen -= 5;
+
+    /* Base64-decode the message */
+    rawlen = OTRL_B64_MAX_DECODED_SIZE(msglen);   /* maximum possible */
+    rawmsg = malloc(rawlen);
+    if (!rawmsg && rawlen > 0) {
+	return gcry_error(GPG_ERR_ENOMEM);
+    }
+    rawlen = otrl_base64_decode(rawmsg, otrtag, msglen);  /* actual size */
+
+    bufp = rawmsg;
+    lenp = rawlen;
+
+    require_len(3);
+    version = bufp[1];
+    skip_header('\x03');
+
+    if (version == 3) {
+	require_len(8);
+	bufp += 8; lenp -= 8;
+    }
+
+    if (version == 2 || version == 3) {
+	require_len(1);
+	if (flagsp) *flagsp = bufp[0];
+	bufp += 1; lenp -= 1;
+    }
+
+    free(rawmsg);
+    return gcry_error(GPG_ERR_NO_ERROR);
+
+invval:
+    free(rawmsg);
+    return gcry_error(GPG_ERR_INV_VALUE);
+}
+
+/* Accept an OTR Data Message in datamsg.  Decrypt it and put the
+ * plaintext into *plaintextp, and any TLVs into tlvsp.  Put any
+ * received flags into *flagsp (if non-NULL).  Put the current extra
+ * symmetric key into extrakey (if non-NULL). */
+gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
+	ConnContext *context, const char *datamsg, unsigned char *flagsp,
+	unsigned char *extrakey)
+{
+    char *otrtag, *endtag;
+    gcry_error_t err;
+    unsigned char *rawmsg = NULL;
+    size_t msglen, rawlen, lenp;
+    unsigned char *macstart, *macend;
+    unsigned char *bufp;
+    unsigned int sender_keyid, recipient_keyid;
+    gcry_mpi_t sender_next_y = NULL;
+    unsigned char ctr[8];
+    size_t datalen, reveallen;
+    unsigned char *data = NULL;
+    unsigned char *nul = NULL;
+    unsigned char givenmac[20];
+    DH_sesskeys *sess;
+    unsigned char version;
+
+    *plaintextp = NULL;
+    *tlvsp = NULL;
+    if (flagsp) *flagsp = 0;
+    otrtag = strstr(datamsg, "?OTR:");
+    if (!otrtag) {
+	goto invval;
+    }
+    endtag = strchr(otrtag, '.');
+    if (endtag) {
+	msglen = endtag-otrtag;
+    } else {
+	msglen = strlen(otrtag);
+    }
+
+    /* Skip over the "?OTR:" */
+    otrtag += 5;
+    msglen -= 5;
+
+    /* Base64-decode the message */
+    rawlen = OTRL_B64_MAX_DECODED_SIZE(msglen);   /* maximum possible */
+    rawmsg = malloc(rawlen);
+    if (!rawmsg && rawlen > 0) {
+	err = gcry_error(GPG_ERR_ENOMEM);
+	goto err;
+    }
+    rawlen = otrl_base64_decode(rawmsg, otrtag, msglen);  /* actual size */
+
+    bufp = rawmsg;
+    lenp = rawlen;
+
+    macstart = bufp;
+    require_len(3);
+    version = bufp[1];
+
+    skip_header('\x03');
+
+    if (version == 3) {
+	require_len(8);
+	bufp += 8; lenp -= 8;
+    }
+
+    if (version == 2 || version == 3) {
+	require_len(1);
+	if (flagsp) *flagsp = bufp[0];
+	bufp += 1; lenp -= 1;
+    }
+
+    read_int(sender_keyid);
+    read_int(recipient_keyid);
+    read_mpi(sender_next_y);
+    require_len(8);
+    memmove(ctr, bufp, 8);
+    bufp += 8; lenp -= 8;
+    read_int(datalen);
+    require_len(datalen);
+    data = malloc(datalen+1);
+    if (!data) {
+	err = gcry_error(GPG_ERR_ENOMEM);
+	goto err;
+    }
+    memmove(data, bufp, datalen);
+    data[datalen] = '\0';
+    bufp += datalen; lenp -= datalen;
+    macend = bufp;
+    require_len(20);
+    memmove(givenmac, bufp, 20);
+    bufp += 20; lenp -= 20;
+    read_int(reveallen);
+    require_len(reveallen);
+    /* Just skip over the revealed MAC keys, which we don't need.  They
+     * were published for deniability of transcripts. */
+    bufp += reveallen; lenp -= reveallen;
+
+    /* That should be everything */
+    if (lenp != 0) goto invval;
+
+    /* We don't take any action on this message (especially rotating
+     * keys) until we've verified the MAC on this message.  To that end,
+     * we need to know which keys this message is claiming to use. */
+    if (context->context_priv->their_keyid == 0 ||
+	    (sender_keyid != context->context_priv->their_keyid &&
+		sender_keyid != context->context_priv->their_keyid - 1) ||
+	    (recipient_keyid != context->context_priv->our_keyid &&
+	     recipient_keyid != context->context_priv->our_keyid - 1) ||
+	    sender_keyid == 0 || recipient_keyid == 0) {
+	goto conflict;
+    }
+
+    if (sender_keyid == context->context_priv->their_keyid - 1 &&
+	    context->context_priv->their_old_y == NULL) {
+	goto conflict;
+    }
+
+    /* These are the session keys this message is claiming to use. */
+    sess = &(context->context_priv->sesskeys
+	    [context->context_priv->our_keyid - recipient_keyid]
+	    [context->context_priv->their_keyid - sender_keyid]);
+
+    gcry_md_reset(sess->rcvmac);
+    gcry_md_write(sess->rcvmac, macstart, macend-macstart);
+    if (otrl_mem_differ(givenmac, gcry_md_read(sess->rcvmac, GCRY_MD_SHA1),
+	    20)) {
+	/* The MACs didn't match! */
+	goto conflict;
+    }
+    sess->rcvmacused = 1;
+
+    /* Check to see that the counter is increasing; i.e. that this isn't
+     * a replay. */
+    if (otrl_dh_cmpctr(ctr, sess->rcvctr) <= 0) {
+	goto conflict;
+    }
+
+    /* Decrypt the message */
+    memmove(sess->rcvctr, ctr, 8);
+    err = gcry_cipher_reset(sess->rcvenc);
+    if (err) goto err;
+    err = gcry_cipher_setctr(sess->rcvenc, sess->rcvctr, 16);
+    if (err) goto err;
+    err = gcry_cipher_decrypt(sess->rcvenc, data, datalen, NULL, 0);
+    if (err) goto err;
+
+    /* Save a copy of the current extra key */
+    if (extrakey) {
+	memmove(extrakey, sess->extrakey, OTRL_EXTRAKEY_BYTES);
+    }
+
+    /* See if either set of keys needs rotating */
+
+    if (recipient_keyid == context->context_priv->our_keyid) {
+	/* They're using our most recent key, so generate a new one */
+	err = rotate_dh_keys(context);
+	if (err) goto err;
+    }
+
+    if (sender_keyid == context->context_priv->their_keyid) {
+	/* They've sent us a new public key */
+	err = rotate_y_keys(context, sender_next_y);
+	if (err) goto err;
+    }
+
+    gcry_mpi_release(sender_next_y);
+    *plaintextp = (char *)data;
+
+    /* See if there are TLVs */
+    nul = data;
+    while (nul < data+datalen && *nul) ++nul;
+    /* If we stopped before the end, skip the NUL we stopped at */
+    if (nul < data+datalen) ++nul;
+    *tlvsp = otrl_tlv_parse(nul, (data+datalen)-nul);
+
+    free(rawmsg);
+    return gcry_error(GPG_ERR_NO_ERROR);
+
+invval:
+    err = gcry_error(GPG_ERR_INV_VALUE);
+    goto err;
+conflict:
+    err = gcry_error(GPG_ERR_CONFLICT);
+    goto err;
+err:
+    gcry_mpi_release(sender_next_y);
+    free(data);
+    free(rawmsg);
+    return err;
+}
+
+/* Accumulate a potential fragment into the current context. */
+OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep,
+	ConnContext *context, const char *msg)
+{
+    OtrlFragmentResult res = OTRL_FRAGMENT_INCOMPLETE;
+    const char *tag;
+    unsigned short n = 0, k = 0;
+    int start = 0, end = 0;
+
+    tag = strstr(msg, "?OTR|");
+    if (tag) {
+	sscanf(tag, "?OTR|%*x|%*x,%hu,%hu,%n%*[^,],%n", &k, &n, &start, &end);
+    } else if ((tag = strstr(msg, "?OTR,")) != NULL) {
+	sscanf(tag, "?OTR,%hu,%hu,%n%*[^,],%n", &k, &n, &start, &end);
+    } else {
+	/* Unfragmented message, so discard any fragment we may have */
+	free(context->context_priv->fragment);
+	context->context_priv->fragment = NULL;
+	context->context_priv->fragment_len = 0;
+	context->context_priv->fragment_n = 0;
+	context->context_priv->fragment_k = 0;
+	res = OTRL_FRAGMENT_UNFRAGMENTED;
+	return res;
+    }
+
+    if (k > 0 && n > 0 && k <= n && start > 0 && end > 0 && start < end) {
+	if (k == 1) {
+	    size_t fraglen = end - start - 1;
+	    size_t newsize = fraglen + 1;
+	    free(context->context_priv->fragment);
+	    context->context_priv->fragment = NULL;
+	    if (newsize >= 1) {  /* Check for overflow */
+		context->context_priv->fragment = malloc(newsize);
+	    }
+	    if (context->context_priv->fragment) {
+		memmove(context->context_priv->fragment, tag + start, fraglen);
+		context->context_priv->fragment_len = fraglen;
+		context->context_priv->fragment[
+			context->context_priv->fragment_len] = '\0';
+		context->context_priv->fragment_n = n;
+		context->context_priv->fragment_k = k;
+	    } else {
+		context->context_priv->fragment_len = 0;
+		context->context_priv->fragment_n = 0;
+		context->context_priv->fragment_k = 0;
+	    }
+	} else if (n == context->context_priv->fragment_n &&
+		k == context->context_priv->fragment_k + 1) {
+	    size_t fraglen = end - start - 1;
+	    char *newfrag = NULL;
+	    size_t newsize = context->context_priv->fragment_len + fraglen + 1;
+	    /* Check for overflow */
+	    if (newsize > context->context_priv->fragment_len) {
+		newfrag = realloc(context->context_priv->fragment, newsize);
+	    }
+	    if (newfrag) {
+		context->context_priv->fragment = newfrag;
+		memmove(context->context_priv->fragment +
+			context->context_priv->fragment_len,
+			tag + start, fraglen);
+		context->context_priv->fragment_len += fraglen;
+		context->context_priv->fragment[
+			context->context_priv->fragment_len] = '\0';
+		context->context_priv->fragment_k = k;
+	    } else {
+		free(context->context_priv->fragment);
+		context->context_priv->fragment = NULL;
+		context->context_priv->fragment_len = 0;
+		context->context_priv->fragment_n = 0;
+		context->context_priv->fragment_k = 0;
+	    }
+	} else {
+	    free(context->context_priv->fragment);
+	    context->context_priv->fragment = NULL;
+	    context->context_priv->fragment_len = 0;
+	    context->context_priv->fragment_n = 0;
+	    context->context_priv->fragment_k = 0;
+	}
+    }
+
+    if (context->context_priv->fragment_n > 0 &&
+	    context->context_priv->fragment_n ==
+	    context->context_priv->fragment_k) {
+	/* We've got a complete message */
+	*unfragmessagep = context->context_priv->fragment;
+	context->context_priv->fragment = NULL;
+	context->context_priv->fragment_len = 0;
+	context->context_priv->fragment_n = 0;
+	context->context_priv->fragment_k = 0;
+	res = OTRL_FRAGMENT_COMPLETE;
+    }
+
+    return res;
+}
+
+/* Create a fragmented message. */
+gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count,
+	char ***fragments, ConnContext *context, const char *message)
+{
+    char *fragdata;
+    size_t fragdatalen = 0;
+    int curfrag = 0;
+    size_t index = 0;
+    size_t msglen = strlen(message);
+    /* Should vary by number of msgs */
+    int headerlen = context->protocol_version == 3 ? 37 : 19;
+
+    char **fragmentarray;
+
+    if (fragment_count < 1 || fragment_count > 65535) {
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    fragmentarray = malloc(fragment_count * sizeof(char*));
+    if(!fragmentarray) return gcry_error(GPG_ERR_ENOMEM);
+
+    /*
+     * Find the next message fragment and store it in the array.
+     */
+    for(curfrag = 1; curfrag <= fragment_count; curfrag++) {
+	int i;
+	char *fragmentmsg;
+
+	if (msglen - index < (size_t)(mms - headerlen)) {
+	    fragdatalen = msglen - index;
+	} else {
+	    fragdatalen = mms - headerlen;
+	}
+
+	fragdata = malloc(fragdatalen + 1);
+	if(!fragdata) {
+		for (i=0; i<curfrag-1; free(fragmentarray[i++])) {}
+		free(fragmentarray);
+		return gcry_error(GPG_ERR_ENOMEM);
+	}
+	strncpy(fragdata, message, fragdatalen);
+	fragdata[fragdatalen] = 0;
+
+	fragmentmsg = malloc(fragdatalen+headerlen+1);
+	if(!fragmentmsg) {
+	    for (i=0; i<curfrag-1; free(fragmentarray[i++])) {}
+	    free(fragmentarray);
+	    free(fragdata);
+	    return gcry_error(GPG_ERR_ENOMEM);
+	}
+
+	/*
+	 * Create the actual fragment and store it in the array
+	 */
+	if (context->auth.protocol_version != 3) {
+	    snprintf(fragmentmsg, fragdatalen + headerlen,
+		    "?OTR,%05hu,%05hu,%s,", (unsigned short)curfrag,
+			    (unsigned short)fragment_count, fragdata);
+	} else {
+	    /* V3 messages require instance tags in the header */
+	    snprintf(fragmentmsg, fragdatalen + headerlen,
+		    "?OTR|%08x|%08x,%05hu,%05hu,%s,",
+		    context->our_instance, context->their_instance,
+		    (unsigned short)curfrag, (unsigned short)fragment_count,
+		    fragdata);
+	}
+	fragmentmsg[fragdatalen + headerlen] = 0;
+
+	fragmentarray[curfrag-1] = fragmentmsg;
+
+	free(fragdata);
+	index += fragdatalen;
+	message += fragdatalen;
+    }
+
+    *fragments = fragmentarray;
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Free a string array containing fragment messages. */
+void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen)
+{
+    int i;
+    char **fragmentarray = *fragments;
+    if(fragmentarray) {
+	for(i = 0; i < arraylen; i++)
+	{
+	    if(fragmentarray[i]) {
+		free(fragmentarray[i]);
+	    }
+	}
+	free(fragmentarray);
+    }
+}
+
diff --git a/libotr/libotr-4.1.1/src/proto.h b/libotr/libotr-4.1.1/src/proto.h
new file mode 100644
index 0000000..28be83f
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/proto.h
@@ -0,0 +1,174 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Rob Smits, Chris Alexander,
+ *  			      Willy Lew, Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __PROTO_H__
+#define __PROTO_H__
+
+#include "context.h"
+#include "version.h"
+#include "tlv.h"
+
+/* If we ever see this sequence in a plaintext message, we'll assume the
+ * other side speaks OTR, and try to establish a connection. */
+#define OTRL_MESSAGE_TAG_BASE " \t  \t\t\t\t \t \t \t  "
+/* The following must each be of length 8 */
+#define OTRL_MESSAGE_TAG_V1 " \t \t  \t "
+#define OTRL_MESSAGE_TAG_V2 "  \t\t  \t "
+#define OTRL_MESSAGE_TAG_V3 "  \t\t  \t\t"
+
+/* The possible flags contained in a Data Message */
+#define OTRL_MSGFLAGS_IGNORE_UNREADABLE		0x01
+
+typedef unsigned int OtrlPolicy;
+
+#define OTRL_POLICY_ALLOW_V1			0x01
+#define OTRL_POLICY_ALLOW_V2			0x02
+#define OTRL_POLICY_ALLOW_V3			0x04
+#define OTRL_POLICY_REQUIRE_ENCRYPTION		0x08
+#define OTRL_POLICY_SEND_WHITESPACE_TAG		0x10
+#define OTRL_POLICY_WHITESPACE_START_AKE	0x20
+#define OTRL_POLICY_ERROR_START_AKE		0x40
+
+#define OTRL_POLICY_VERSION_MASK (OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2 |\
+	OTRL_POLICY_ALLOW_V3)
+
+/* Length of OTR message headers */
+#define OTRL_HEADER_LEN		3
+#define OTRL_B64_HEADER_LEN	4
+
+/* Analogous to v1 policies */
+#define OTRL_POLICY_NEVER			0x00
+#define OTRL_POLICY_OPPORTUNISTIC \
+	    ( OTRL_POLICY_ALLOW_V2 | \
+	    OTRL_POLICY_ALLOW_V3 | \
+	    OTRL_POLICY_SEND_WHITESPACE_TAG | \
+	    OTRL_POLICY_WHITESPACE_START_AKE | \
+	    OTRL_POLICY_ERROR_START_AKE )
+#define OTRL_POLICY_MANUAL \
+	    ( OTRL_POLICY_ALLOW_V2 | \
+	    OTRL_POLICY_ALLOW_V3)
+#define OTRL_POLICY_ALWAYS \
+	    ( OTRL_POLICY_ALLOW_V2 | \
+	    OTRL_POLICY_ALLOW_V3 | \
+	    OTRL_POLICY_REQUIRE_ENCRYPTION | \
+	    OTRL_POLICY_WHITESPACE_START_AKE | \
+	    OTRL_POLICY_ERROR_START_AKE )
+#define OTRL_POLICY_DEFAULT OTRL_POLICY_OPPORTUNISTIC
+
+typedef enum {
+    OTRL_MSGTYPE_NOTOTR,
+    OTRL_MSGTYPE_TAGGEDPLAINTEXT,
+    OTRL_MSGTYPE_QUERY,
+    OTRL_MSGTYPE_DH_COMMIT,
+    OTRL_MSGTYPE_DH_KEY,
+    OTRL_MSGTYPE_REVEALSIG,
+    OTRL_MSGTYPE_SIGNATURE,
+    OTRL_MSGTYPE_V1_KEYEXCH,
+    OTRL_MSGTYPE_DATA,
+    OTRL_MSGTYPE_ERROR,
+    OTRL_MSGTYPE_UNKNOWN
+} OtrlMessageType;
+
+typedef enum {
+    OTRL_FRAGMENT_UNFRAGMENTED,
+    OTRL_FRAGMENT_INCOMPLETE,
+    OTRL_FRAGMENT_COMPLETE
+} OtrlFragmentResult;
+
+typedef enum {
+    OTRL_FRAGMENT_SEND_SKIP, /* Return new message back to caller,
+			      * but don't inject. */
+    OTRL_FRAGMENT_SEND_ALL,
+    OTRL_FRAGMENT_SEND_ALL_BUT_FIRST,
+    OTRL_FRAGMENT_SEND_ALL_BUT_LAST
+} OtrlFragmentPolicy;
+
+/* Initialize the OTR library.  Pass the version of the API you are
+ * using. */
+gcry_error_t otrl_init(unsigned int ver_major, unsigned int ver_minor,
+	unsigned int ver_sub);
+
+/* Shortcut */
+#define OTRL_INIT do { \
+	if (otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, \
+		OTRL_VERSION_SUB)) { \
+	    exit(1); \
+	} \
+    } while(0)
+
+/* Return a pointer to a static string containing the version number of
+ * the OTR library. */
+const char *otrl_version(void);
+
+/* Return a pointer to a newly-allocated OTR query message, customized
+ * with our name.  The caller should free() the result when he's done
+ * with it. */
+char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy);
+
+/* Return the best version of OTR support by both sides, given an OTR
+ * Query Message and the local policy. */
+unsigned int otrl_proto_query_bestversion(const char *querymsg,
+	OtrlPolicy policy);
+
+/* Locate any whitespace tag in this message, and return the best
+ * version of OTR support on both sides.  Set *starttagp and *endtagp to
+ * the start and end of the located tag, so that it can be snipped out. */
+unsigned int otrl_proto_whitespace_bestversion(const char *msg,
+	const char **starttagp, const char **endtagp, OtrlPolicy policy);
+
+/* Find the message type. */
+OtrlMessageType otrl_proto_message_type(const char *message);
+
+/* Find the message version. */
+int otrl_proto_message_version(const char *message);
+
+/* Find the instance tags in this message. */
+gcry_error_t otrl_proto_instance(const char *otrmsg,
+	unsigned int *instance_from, unsigned int *instance_to);
+
+/* Create an OTR Data message.  Pass the plaintext as msg, and an
+ * optional chain of TLVs.  A newly-allocated string will be returned in
+ * *encmessagep. Put the current extra symmetric key into extrakey
+ * (if non-NULL). */
+gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
+	const char *msg, const OtrlTLV *tlvs, unsigned char flags,
+	unsigned char *extrakey);
+
+/* Extract the flags from an otherwise unreadable Data Message. */
+gcry_error_t otrl_proto_data_read_flags(const char *datamsg,
+	unsigned char *flagsp);
+
+/* Accept an OTR Data Message in datamsg.  Decrypt it and put the
+ * plaintext into *plaintextp, and any TLVs into tlvsp.  Put any
+ * received flags into *flagsp (if non-NULL).  Put the current extra
+ * symmetric key into extrakey (if non-NULL). */
+gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
+	ConnContext *context, const char *datamsg, unsigned char *flagsp,
+	unsigned char *extrakey);
+
+/* Accumulate a potential fragment into the current context. */
+OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep,
+	ConnContext *context, const char *msg);
+
+gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count,
+	char ***fragments, ConnContext *context, const char *message);
+
+void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen);
+#endif
diff --git a/libotr/libotr-4.1.1/src/serial.h b/libotr/libotr-4.1.1/src/serial.h
new file mode 100644
index 0000000..cd2442b
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/serial.h
@@ -0,0 +1,107 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Rob Smits, Chris Alexander,
+ *  			      Willy Lew, Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SERIAL_H__
+#define __SERIAL_H__
+
+#undef DEBUG
+
+#ifdef DEBUG
+
+#include <stdio.h>
+
+#define debug_data(t,b,l) do { const unsigned char *data = (b); size_t i; \
+	fprintf(stderr, "%s: ", (t)); \
+	for(i=0;i<(l);++i) { \
+	    fprintf(stderr, "%02x", data[i]); \
+	} \
+	fprintf(stderr, "\n"); \
+    } while(0)
+
+#define debug_int(t,b) do { const unsigned char *data = (b); \
+	unsigned int v = \
+	    (((unsigned int)data[0]) << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \
+	fprintf(stderr, "%s: %u (0x%x)\n", (t), v, v); \
+    } while(0)
+
+#else
+#define debug_data(t,b,l)
+#define debug_int(t,b)
+#endif
+
+#define write_int(x) do { \
+	bufp[0] = ((x) >> 24) & 0xff; \
+	bufp[1] = ((x) >> 16) & 0xff; \
+	bufp[2] = ((x) >> 8) & 0xff; \
+	bufp[3] = (x) & 0xff; \
+	bufp += 4; lenp -= 4; \
+    } while(0)
+
+#define write_mpi(x,nx,dx) do { \
+	write_int(nx); \
+	gcry_mpi_print(format, bufp, lenp, NULL, (x)); \
+	debug_data((dx), bufp, (nx)); \
+	bufp += (nx); lenp -= (nx); \
+    } while(0)
+
+#define require_len(l) do { \
+	if (lenp < (l)) goto invval; \
+    } while(0)
+
+#define read_int(x) do { \
+	require_len(4); \
+	(x) = (((unsigned int)bufp[0]) << 24) | (bufp[1] << 16) | (bufp[2] << 8) | bufp[3]; \
+	bufp += 4; lenp -= 4; \
+    } while(0)
+
+#define read_mpi(x) do { \
+	size_t mpilen; \
+	read_int(mpilen); \
+	if (mpilen) { \
+	    require_len(mpilen); \
+	    gcry_mpi_scan(&(x), GCRYMPI_FMT_USG, bufp, mpilen, NULL); \
+	} else { \
+	    (x) = gcry_mpi_set_ui(NULL, 0); \
+	} \
+	bufp += mpilen; lenp -= mpilen; \
+    } while(0)
+
+/* Write version and msg type into bufp*/
+#define write_header(version, msgtype) do { \
+	bufp[0] = 0x00; \
+        bufp[1] = version & 0xff; \
+        bufp[2] = msgtype; \
+        debug_data("Header", bufp, 3); \
+        bufp += 3; lenp -= 3; \
+    } while(0)
+
+/* Verify msg header is v1, v2 or v3 and has type x,
+*  increment bufp past msg header */
+#define skip_header(x) do { \
+        require_len(3); \
+        if ((bufp[0] != 0x00) || (bufp[2] != x)) \
+	    goto invval; \
+        if ((bufp[1] == 0x01) || (bufp[1] == 0x02) || \
+                (bufp[1] == 0x03)) { \
+	    bufp += 3; lenp -= 3; \
+	} else goto invval; \
+    } while(0)
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/sm.c b/libotr/libotr-4.1.1/src/sm.c
new file mode 100644
index 0000000..4fb679e
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/sm.c
@@ -0,0 +1,998 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2014  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "sm.h"
+#include "serial.h"
+
+#if OTRL_DEBUGGING
+
+/* Dump the contents of an SMState to the FILE *f. */
+void otrl_sm_dump(FILE *f, const OtrlSMState *sm)
+{
+    fprintf(f, "  SM state:\n");
+    fprintf(f, "    Next expected: %d (%s)\n", sm->nextExpected,
+	sm->nextExpected == OTRL_SMP_EXPECT1 ? "EXPECT1" :
+	sm->nextExpected == OTRL_SMP_EXPECT2 ? "EXPECT2" :
+	sm->nextExpected == OTRL_SMP_EXPECT3 ? "EXPECT3" :
+	sm->nextExpected == OTRL_SMP_EXPECT4 ? "EXPECT4" :
+	sm->nextExpected == OTRL_SMP_EXPECT5 ? "EXPECT5" :
+	"INVALID");
+    fprintf(f, "    Received_Q: %d\n", sm->received_question);
+    fprintf(f, "    Progress state: %d (%s)\n", sm->sm_prog_state,
+	sm->sm_prog_state == OTRL_SMP_PROG_OK ? "OK" :
+	sm->sm_prog_state == OTRL_SMP_PROG_CHEATED ? "CHEATED" :
+	sm->sm_prog_state == OTRL_SMP_PROG_FAILED ? "FAILED" :
+	sm->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED ? "SUCCEEDED" :
+	"INVALID");
+}
+
+#endif
+
+static const int SM_MSG1_LEN = 6;
+static const int SM_MSG2_LEN = 11;
+static const int SM_MSG3_LEN = 8;
+static const int SM_MSG4_LEN = 3;
+
+/* The modulus p */
+static const char* SM_MODULUS_S = "0x"
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
+/* The order of the group q = (p-1)/2 */
+static const char* SM_ORDER_S = "0x"
+    "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68"
+    "948127044533E63A0105DF531D89CD9128A5043CC71A026E"
+    "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122"
+    "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6"
+    "F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9E"
+    "E1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AF"
+    "C1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36"
+    "B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF";
+static const char *SM_GENERATOR_S = "0x02";
+static const int SM_MOD_LEN_BITS = 1536;
+static const int SM_MOD_LEN_BYTES = 192;
+
+static gcry_mpi_t SM_MODULUS = NULL;
+static gcry_mpi_t SM_GENERATOR = NULL;
+static gcry_mpi_t SM_ORDER = NULL;
+static gcry_mpi_t SM_MODULUS_MINUS_2 = NULL;
+
+/*
+ * Call this once, at plugin load time.  It sets up the modulus and
+ * generator MPIs.
+ */
+void otrl_sm_init(void)
+{
+    gcry_check_version(NULL);
+    gcry_mpi_scan(&SM_MODULUS, GCRYMPI_FMT_HEX,
+	(const unsigned char *)SM_MODULUS_S, 0, NULL);
+    gcry_mpi_scan(&SM_ORDER, GCRYMPI_FMT_HEX,
+	(const unsigned char *)SM_ORDER_S, 0, NULL);
+    gcry_mpi_scan(&SM_GENERATOR, GCRYMPI_FMT_HEX,
+	(const unsigned char *)SM_GENERATOR_S, 0, NULL);
+    SM_MODULUS_MINUS_2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_sub_ui(SM_MODULUS_MINUS_2, SM_MODULUS, 2);
+}
+
+/*
+ * Initialize the fields of a SM state.
+ */
+void otrl_sm_state_new(OtrlSMState *smst)
+{
+    smst->secret = NULL;
+    smst->x2 = NULL;
+    smst->x3 = NULL;
+    smst->g1 = NULL;
+    smst->g2 = NULL;
+    smst->g3 = NULL;
+    smst->g3o = NULL;
+    smst->p = NULL;
+    smst->q = NULL;
+    smst->pab = NULL;
+    smst->qab = NULL;
+    smst->nextExpected = OTRL_SMP_EXPECT1;
+    smst->received_question = 0;
+    smst->sm_prog_state = OTRL_SMP_PROG_OK;
+}
+
+/*
+ * Initialize the fields of a SM state.  Called the first time that
+ * a user begins an SMP session.
+ */
+void otrl_sm_state_init(OtrlSMState *smst)
+{
+    otrl_sm_state_free(smst);
+    smst->secret = gcry_mpi_snew(SM_MOD_LEN_BITS);
+    smst->x2 = NULL;
+    smst->x3 = NULL;
+    smst->g1 = gcry_mpi_copy(SM_GENERATOR);
+    smst->g2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    smst->g3 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    smst->g3o = gcry_mpi_new(SM_MOD_LEN_BITS);
+    smst->p = gcry_mpi_new(SM_MOD_LEN_BITS);
+    smst->q = gcry_mpi_new(SM_MOD_LEN_BITS);
+    smst->pab = gcry_mpi_new(SM_MOD_LEN_BITS);
+    smst->qab = gcry_mpi_new(SM_MOD_LEN_BITS);
+    smst->received_question = 0;
+    smst->sm_prog_state = OTRL_SMP_PROG_OK;
+}
+
+/*
+ * Initialize the fields of a SM message1.
+ * [0] = g2a, [1] = c2, [2] = d2, [3] = g3a, [4] = c3, [5] = d3
+ */
+void otrl_sm_msg1_init(gcry_mpi_t **msg1)
+{
+    gcry_mpi_t *msg = malloc(SM_MSG1_LEN * sizeof(gcry_mpi_t));
+    msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[1] = NULL;
+    msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[4] = NULL;
+    msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+    *msg1 = msg;
+}
+
+/*
+ * Initialize the fields of a SM message2.
+ * [0] = g2b, [1] = c2, [2] = d2, [3] = g3b, [4] = c3, [5] = d3
+ * [6] = pb, [7] = qb, [8] = cp, [9] = d5, [10] = d6
+ */
+void otrl_sm_msg2_init(gcry_mpi_t **msg2)
+{
+    gcry_mpi_t *msg = malloc(SM_MSG2_LEN * sizeof(gcry_mpi_t));
+    msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[1] = NULL;
+    msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[4] = NULL;
+    msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[6] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[7] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[8] = NULL;
+    msg[9] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[10] = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+    *msg2 = msg;
+}
+
+/*
+ * Initialize the fields of a SM message3.
+ * [0] = pa, [1] = qa, [2] = cp, [3] = d5, [4] = d6, [5] = ra,
+ * [6] = cr, [7] = d7
+ */
+void otrl_sm_msg3_init(gcry_mpi_t **msg3)
+{
+    gcry_mpi_t *msg = malloc(SM_MSG3_LEN * sizeof(gcry_mpi_t));
+    msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[1] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[2] = NULL;
+    msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[4] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[6] = NULL;
+    msg[7] = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+    *msg3 = msg;
+}
+
+/*
+ * Initialize the fields of a SM message4.
+ * [0] = rb, [1] = cr, [2] = d7
+ */
+void otrl_sm_msg4_init(gcry_mpi_t **msg4)
+{
+    gcry_mpi_t *msg = malloc(SM_MSG4_LEN * sizeof(gcry_mpi_t));
+    msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS);
+    msg[1] = NULL;
+    msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+    *msg4 = msg;
+}
+
+/*
+ * Deallocate the contents of a OtrlSMState (but not the OtrlSMState
+ * itself)
+ */
+void otrl_sm_state_free(OtrlSMState *smst)
+{
+    gcry_mpi_release(smst->secret);
+    gcry_mpi_release(smst->x2);
+    gcry_mpi_release(smst->x3);
+    gcry_mpi_release(smst->g1);
+    gcry_mpi_release(smst->g2);
+    gcry_mpi_release(smst->g3);
+    gcry_mpi_release(smst->g3o);
+    gcry_mpi_release(smst->p);
+    gcry_mpi_release(smst->q);
+    gcry_mpi_release(smst->pab);
+    gcry_mpi_release(smst->qab);
+    otrl_sm_state_new(smst);
+}
+
+/*
+ * Deallocate the contents of a message
+ */
+void otrl_sm_msg_free(gcry_mpi_t **message, int msglen)
+{
+    gcry_mpi_t *msg = *message;
+    int i;
+    for (i=0; i<msglen; i++) {
+	gcry_mpi_release(msg[i]);
+    }
+    free(msg);
+    *message = NULL;
+}
+
+static gcry_mpi_t randomExponent(void)
+{
+    unsigned char *secbuf = NULL;
+    gcry_mpi_t randexpon = NULL;
+
+    /* Generate a random exponent */
+    secbuf = gcry_random_bytes_secure(SM_MOD_LEN_BYTES, GCRY_STRONG_RANDOM);
+    gcry_mpi_scan(&randexpon, GCRYMPI_FMT_USG, secbuf, SM_MOD_LEN_BYTES, NULL);
+    gcry_free(secbuf);
+
+    return randexpon;
+}
+
+/*
+ * Hash one or two mpis.  To hash only one mpi, b may be set to NULL.
+ */
+static gcry_error_t otrl_sm_hash(gcry_mpi_t* hash, int version,
+	const gcry_mpi_t a, const gcry_mpi_t b)
+{
+    unsigned char* input;
+    unsigned char output[SM_DIGEST_SIZE];
+    size_t sizea;
+    size_t sizeb;
+    size_t totalsize;
+    unsigned char* dataa;
+    unsigned char* datab;
+
+    gcry_mpi_aprint(GCRYMPI_FMT_USG, &dataa, &sizea, a);
+    totalsize = 1 + 4 + sizea;
+    if (b) {
+	gcry_mpi_aprint(GCRYMPI_FMT_USG, &datab, &sizeb, b);
+	totalsize += 4 + sizeb;
+    } else {
+	sizeb = 0;
+    }
+
+    input = malloc(totalsize);
+    input[0] = (unsigned char)version;
+    input[1] = (unsigned char)((sizea >> 24) & 0xFF);
+    input[2] = (unsigned char)((sizea >> 16) & 0xFF);
+    input[3] = (unsigned char)((sizea >> 8) & 0xFF);
+    input[4] = (unsigned char)(sizea & 0xFF);
+    memmove(input + 5, dataa, sizea);
+    if (b) {
+	input[5 + sizea] = (unsigned char)((sizeb >> 24) & 0xFF);
+	input[6 + sizea] = (unsigned char)((sizeb >> 16) & 0xFF);
+	input[7 + sizea] = (unsigned char)((sizeb >> 8) & 0xFF);
+	input[8 + sizea] = (unsigned char)(sizeb & 0xFF);
+	memmove(input + 9 + sizea, datab, sizeb);
+    }
+
+    gcry_md_hash_buffer(SM_HASH_ALGORITHM, output, input, totalsize);
+    gcry_mpi_scan(hash, GCRYMPI_FMT_USG, output, SM_DIGEST_SIZE, NULL);
+    free(input);
+    input = NULL;
+
+    /* free memory */
+    gcry_free(dataa);
+    if (b) gcry_free(datab);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* This method should be passed a pointer to an uninitialized buffer,
+ * and a list of mpis with a list length.  When returns, the buffer will
+ * point to newly-allocated memory (using malloc) containing a
+ * reversible serialization. */
+static gcry_error_t serialize_mpi_array(unsigned char **buffer, int *buflen,
+	unsigned int count, gcry_mpi_t *mpis)
+{
+    size_t totalsize = 0, lenp, nextsize;
+    unsigned int i, j;
+    size_t *list_sizes = malloc(count * sizeof(size_t));
+    unsigned char **tempbuffer = malloc(count * sizeof(unsigned char *));
+    unsigned char *bufp;
+
+    for (i=0; i<count; i++) {
+	gcry_mpi_aprint(GCRYMPI_FMT_USG, &(tempbuffer[i]), &(list_sizes[i]),
+		mpis[i]);
+	totalsize += list_sizes[i];
+    }
+
+    *buflen = (count+1)*4 + totalsize;
+    *buffer = malloc(*buflen * sizeof(char));
+
+    bufp = *buffer;
+    lenp = totalsize;
+
+    write_int(count);
+    for(i=0; i<count; i++)
+    {
+	nextsize = list_sizes[i];
+	write_int(nextsize);
+
+	for(j=0; j<nextsize; j++)
+	    bufp[j] = tempbuffer[i][j];
+
+	bufp += nextsize;
+	lenp -= nextsize;
+	gcry_free(tempbuffer[i]);
+    }
+    free(tempbuffer);
+    free(list_sizes);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Takes a buffer containing serialized and concatenated mpis
+ * and converts it to an array of gcry_mpi_t structs.
+ * The buffer is assumed to consist of a 4-byte int containing the
+ * number of mpis in the array, followed by {size, data} pairs for
+ * each mpi.  If malformed, method returns GCRY_ERROR_INV_VALUE */
+static gcry_error_t unserialize_mpi_array(gcry_mpi_t **mpis,
+	unsigned int expcount, const unsigned char *buffer, const int buflen)
+{
+    unsigned int i;
+    size_t lenp = buflen;
+    unsigned int thecount = 0;
+    const unsigned char* bufp = buffer;
+    *mpis = NULL;
+
+    read_int(thecount);
+    if (thecount != expcount) goto invval;
+
+    *mpis = malloc(thecount * sizeof(gcry_mpi_t));
+
+    for (i=0; i<thecount; i++) {
+	(*mpis)[i] = NULL;
+    }
+
+    for (i=0; i<thecount; i++) {
+	read_mpi((*mpis)[i]);
+    }
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+
+invval:
+    if (*mpis) {
+	for (i=0; i<thecount; i++) {
+	    gcry_mpi_release((*mpis)[i]);
+	}
+	free(*mpis);
+	*mpis = NULL;
+    }
+    return gcry_error(GPG_ERR_INV_VALUE);
+}
+
+/* Check that an MPI is in the right range to be a (non-unit) group
+ * element */
+static int check_group_elem(gcry_mpi_t g)
+{
+    if (gcry_mpi_cmp_ui(g, 2) < 0 ||
+	    gcry_mpi_cmp(g, SM_MODULUS_MINUS_2) > 0) {
+	return 1;
+    }
+    return 0;
+}
+
+/* Check that an MPI is in the right range to be a (non-zero) exponent */
+static int check_expon(gcry_mpi_t x)
+{
+    if (gcry_mpi_cmp_ui(x, 1) < 0 ||
+	    gcry_mpi_cmp(x, SM_ORDER) >= 0) {
+	return 1;
+    }
+    return 0;
+}
+
+/*
+ * Proof of knowledge of a discrete logarithm
+ */
+static gcry_error_t otrl_sm_proof_know_log(gcry_mpi_t *c, gcry_mpi_t *d,
+	const gcry_mpi_t g, const gcry_mpi_t x, int version)
+{
+    gcry_mpi_t r = randomExponent();
+    gcry_mpi_t temp = gcry_mpi_snew(SM_MOD_LEN_BITS);
+    gcry_mpi_powm(temp, g, r, SM_MODULUS);
+    otrl_sm_hash(c, version, temp, NULL);
+    gcry_mpi_mulm(temp, x, *c, SM_ORDER);
+    gcry_mpi_subm(*d, r, temp, SM_ORDER);
+    gcry_mpi_release(temp);
+    gcry_mpi_release(r);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/*
+ * Verify a proof of knowledge of a discrete logarithm.
+ * Checks that c = h(g^d x^c)
+ */
+static int otrl_sm_check_know_log(const gcry_mpi_t c, const gcry_mpi_t d,
+	const gcry_mpi_t g, const gcry_mpi_t x, int version)
+{
+    int comp;
+
+    gcry_mpi_t gd = gcry_mpi_new(SM_MOD_LEN_BITS);  /* g^d */
+    gcry_mpi_t xc = gcry_mpi_new(SM_MOD_LEN_BITS);  /* x^c */
+    gcry_mpi_t gdxc = gcry_mpi_new(SM_MOD_LEN_BITS);   /* (g^d x^c) */
+    gcry_mpi_t hgdxc = NULL;   /* h(g^d x^c) */
+
+    gcry_mpi_powm(gd, g, d, SM_MODULUS);
+    gcry_mpi_powm(xc, x, c, SM_MODULUS);
+    gcry_mpi_mulm(gdxc, gd, xc, SM_MODULUS);
+    otrl_sm_hash(&hgdxc, version, gdxc, NULL);
+
+    comp = gcry_mpi_cmp(hgdxc, c);
+    gcry_mpi_release(gd);
+    gcry_mpi_release(xc);
+    gcry_mpi_release(gdxc);
+    gcry_mpi_release(hgdxc);
+
+    return comp;
+}
+
+/*
+ * Proof of knowledge of coordinates with first components being equal
+ */
+static gcry_error_t otrl_sm_proof_equal_coords(gcry_mpi_t *c, gcry_mpi_t *d1,
+	gcry_mpi_t *d2, const OtrlSMState *state, const gcry_mpi_t r,
+	int version)
+{
+    gcry_mpi_t r1 = randomExponent();
+    gcry_mpi_t r2 = randomExponent();
+    gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+    /* Compute the value of c, as c = h(g3^r1, g1^r1 g2^r2) */
+    gcry_mpi_powm(temp1, state->g1, r1, SM_MODULUS);
+    gcry_mpi_powm(temp2, state->g2, r2, SM_MODULUS);
+    gcry_mpi_mulm(temp2, temp1, temp2, SM_MODULUS);
+    gcry_mpi_powm(temp1, state->g3, r1, SM_MODULUS);
+    otrl_sm_hash(c, version, temp1, temp2);
+
+    /* Compute the d values, as d1 = r1 - r c, d2 = r2 - secret c */
+    gcry_mpi_mulm(temp1, r, *c, SM_ORDER);
+    gcry_mpi_subm(*d1, r1, temp1, SM_ORDER);
+
+    gcry_mpi_mulm(temp1, state->secret, *c, SM_ORDER);
+    gcry_mpi_subm(*d2, r2, temp1, SM_ORDER);
+
+    /* All clear */
+    gcry_mpi_release(r1);
+    gcry_mpi_release(r2);
+    gcry_mpi_release(temp1);
+    gcry_mpi_release(temp2);
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/*
+ * Verify a proof of knowledge of coordinates with first components being equal
+ */
+static gcry_error_t otrl_sm_check_equal_coords(const gcry_mpi_t c,
+	const gcry_mpi_t d1, const gcry_mpi_t d2, const gcry_mpi_t p,
+	const gcry_mpi_t q, const OtrlSMState *state, int version)
+{
+    int comp;
+
+    gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_t temp3 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_t cprime = NULL;
+
+    /* To verify, we test that hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c) = c
+     * If indeed c = hash(g3^r1, g1^r1 g2^r2), d1 = r1 - r*c,
+     * d2 = r2 - secret*c.  And if indeed p = g3^r, q = g1^r * g2^secret
+     * Then we should have that:
+     *   hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c)
+     * = hash(g3^(r1 - r*c + r*c), g1^(r1 - r*c + q*c) *
+     *      g2^(r2 - secret*c + secret*c))
+     * = hash(g3^r1, g1^r1 g2^r2)
+     * = c
+     */
+    gcry_mpi_powm(temp2, state->g3, d1, SM_MODULUS);
+    gcry_mpi_powm(temp3, p, c, SM_MODULUS);
+    gcry_mpi_mulm(temp1, temp2, temp3, SM_MODULUS);
+
+    gcry_mpi_powm(temp2, state->g1, d1, SM_MODULUS);
+    gcry_mpi_powm(temp3, state->g2, d2, SM_MODULUS);
+    gcry_mpi_mulm(temp2, temp2, temp3, SM_MODULUS);
+    gcry_mpi_powm(temp3, q, c, SM_MODULUS);
+    gcry_mpi_mulm(temp2, temp3, temp2, SM_MODULUS);
+
+    otrl_sm_hash(&cprime, version, temp1, temp2);
+
+    comp = gcry_mpi_cmp(c, cprime);
+    gcry_mpi_release(temp1);
+    gcry_mpi_release(temp2);
+    gcry_mpi_release(temp3);
+    gcry_mpi_release(cprime);
+
+    return comp;
+}
+
+/*
+ * Proof of knowledge of logs with exponents being equal
+ */
+static gcry_error_t otrl_sm_proof_equal_logs(gcry_mpi_t *c, gcry_mpi_t *d,
+	OtrlSMState *state, int version)
+{
+    gcry_mpi_t r = randomExponent();
+    gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+    /* Compute the value of c, as c = h(g1^r, (Qa/Qb)^r) */
+    gcry_mpi_powm(temp1, state->g1, r, SM_MODULUS);
+    gcry_mpi_powm(temp2, state->qab, r, SM_MODULUS);
+    otrl_sm_hash(c, version, temp1, temp2);
+
+    /* Compute the d values, as d = r - x3 c */
+    gcry_mpi_mulm(temp1, state->x3, *c, SM_ORDER);
+    gcry_mpi_subm(*d, r, temp1, SM_ORDER);
+
+    /* All clear */
+    gcry_mpi_release(r);
+    gcry_mpi_release(temp1);
+    gcry_mpi_release(temp2);
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/*
+ * Verify a proof of knowledge of logs with exponents being equal
+ */
+static gcry_error_t otrl_sm_check_equal_logs(const gcry_mpi_t c,
+	const gcry_mpi_t d, const gcry_mpi_t r, const OtrlSMState *state,
+	int version)
+{
+    int comp;
+
+    gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_t temp3 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_t cprime = NULL;
+
+    /* Here, we recall the exponents used to create g3.
+     * If we have previously seen g3o = g1^x where x is unknown
+     * during the DH exchange to produce g3, then we may proceed with:
+     *
+     * To verify, we test that hash(g1^d * g3o^c, qab^d * r^c) = c
+     * If indeed c = hash(g1^r1, qab^r1), d = r1- x * c
+     * And if indeed r = qab^x
+     * Then we should have that:
+     *   hash(g1^d * g3o^c, qab^d r^c)
+     * = hash(g1^(r1 - x*c + x*c), qab^(r1 - x*c + x*c))
+     * = hash(g1^r1, qab^r1)
+     * = c
+     */
+    gcry_mpi_powm(temp2, state->g1, d, SM_MODULUS);
+    gcry_mpi_powm(temp3, state->g3o, c, SM_MODULUS);
+    gcry_mpi_mulm(temp1, temp2, temp3, SM_MODULUS);
+
+    gcry_mpi_powm(temp3, state->qab, d, SM_MODULUS);
+    gcry_mpi_powm(temp2, r, c, SM_MODULUS);
+    gcry_mpi_mulm(temp2, temp3, temp2, SM_MODULUS);
+
+    otrl_sm_hash(&cprime, version, temp1, temp2);
+
+    comp = gcry_mpi_cmp(c, cprime);
+    gcry_mpi_release(temp1);
+    gcry_mpi_release(temp2);
+    gcry_mpi_release(temp3);
+    gcry_mpi_release(cprime);
+
+    return comp;
+}
+
+/* Create first message in SMP exchange.  Input is Alice's secret value
+ * which this protocol aims to compare to Bob's.  Output is a serialized
+ * mpi array whose elements correspond to the following:
+ * [0] = g2a, Alice's half of DH exchange to determine g2
+ * [1] = c2, [2] = d2, Alice's ZK proof of knowledge of g2a exponent
+ * [3] = g3a, Alice's half of DH exchange to determine g3
+ * [4] = c3, [5] = d3, Alice's ZK proof of knowledge of g3a exponent */
+gcry_error_t otrl_sm_step1(OtrlSMAliceState *astate,
+	const unsigned char* secret, int secretlen,
+	unsigned char** output, int* outputlen)
+{
+    /* Initialize the sm state or update the secret */
+    gcry_mpi_t secret_mpi = NULL;
+    gcry_mpi_t *msg1;
+
+    *output = NULL;
+    *outputlen = 0;
+
+    gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, secret, secretlen, NULL);
+
+    if (! astate->g1) {
+	otrl_sm_state_init(astate);
+    }
+    gcry_mpi_set(astate->secret, secret_mpi);
+    gcry_mpi_release(secret_mpi);
+    astate->received_question = 0;
+
+    otrl_sm_msg1_init(&msg1);
+
+    astate->x2 = randomExponent();
+    astate->x3 = randomExponent();
+
+    gcry_mpi_powm(msg1[0], astate->g1, astate->x2, SM_MODULUS);
+    otrl_sm_proof_know_log(&(msg1[1]), &(msg1[2]), astate->g1, astate->x2, 1);
+
+    gcry_mpi_powm(msg1[3], astate->g1, astate->x3, SM_MODULUS);
+    otrl_sm_proof_know_log(&(msg1[4]), &(msg1[5]), astate->g1, astate->x3, 2);
+
+    serialize_mpi_array(output, outputlen, SM_MSG1_LEN, msg1);
+    otrl_sm_msg_free(&msg1, SM_MSG1_LEN);
+    astate->sm_prog_state = OTRL_SMP_PROG_OK;
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Receive the first message in SMP exchange, which was generated by
+ * otrl_sm_step1.  Input is saved until the user inputs their secret
+ * information.  No output. */
+gcry_error_t otrl_sm_step2a(OtrlSMBobState *bstate, const unsigned char* input,
+	const int inputlen, int received_question)
+{
+    gcry_mpi_t *msg1;
+    gcry_error_t err;
+
+    /* Initialize the sm state if needed */
+    if (! bstate->g1) {
+	otrl_sm_state_init(bstate);
+    }
+    bstate->received_question = received_question;
+    bstate->sm_prog_state = OTRL_SMP_PROG_CHEATED;
+
+    /* Read from input to find the mpis */
+    err = unserialize_mpi_array(&msg1, SM_MSG1_LEN, input, inputlen);
+
+    if (err != gcry_error(GPG_ERR_NO_ERROR)) return err;
+
+    if (check_group_elem(msg1[0]) || check_expon(msg1[2]) ||
+	    check_group_elem(msg1[3]) || check_expon(msg1[5])) {
+	otrl_sm_msg_free(&msg1, SM_MSG1_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Store Alice's g3a value for later in the protocol */
+    gcry_mpi_set(bstate->g3o, msg1[3]);
+
+    /* Verify Alice's proofs */
+    if (otrl_sm_check_know_log(msg1[1], msg1[2], bstate->g1, msg1[0], 1) ||
+	otrl_sm_check_know_log(msg1[4], msg1[5], bstate->g1, msg1[3], 2)) {
+	otrl_sm_msg_free(&msg1, SM_MSG1_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Create Bob's half of the generators g2 and g3 */
+    bstate->x2 = randomExponent();
+    bstate->x3 = randomExponent();
+
+    /* Combine the two halves from Bob and Alice and determine g2 and g3 */
+    gcry_mpi_powm(bstate->g2, msg1[0], bstate->x2, SM_MODULUS);
+    gcry_mpi_powm(bstate->g3, msg1[3], bstate->x3, SM_MODULUS);
+
+    bstate->sm_prog_state = OTRL_SMP_PROG_OK;
+
+    otrl_sm_msg_free(&msg1, SM_MSG1_LEN);
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Create second message in SMP exchange.  Input is Bob's secret value.
+ * Information from earlier steps in the exchange is taken from Bob's
+ * state.  Output is a serialized mpi array whose elements correspond
+ * to the following:
+ * [0] = g2b, Bob's half of DH exchange to determine g2
+ * [1] = c2, [2] = d2, Bob's ZK proof of knowledge of g2b exponent
+ * [3] = g3b, Bob's half of DH exchange to determine g3
+ * [4] = c3, [5] = d3, Bob's ZK proof of knowledge of g3b exponent
+ * [6] = pb, [7] = qb, Bob's halves of the (Pa/Pb) and (Qa/Qb) values
+ * [8] = cp, [9] = d5, [10] = d6, Bob's ZK proof that pb, qb formed correctly */
+gcry_error_t otrl_sm_step2b(OtrlSMBobState *bstate, const unsigned char* secret,
+	int secretlen, unsigned char **output, int* outputlen)
+{
+    /* Convert the given secret to the proper form and store it */
+    gcry_mpi_t r, qb1, qb2;
+    gcry_mpi_t *msg2;
+    gcry_mpi_t secret_mpi = NULL;
+
+    *output = NULL;
+    *outputlen = 0;
+
+    gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, secret, secretlen, NULL);
+    gcry_mpi_set(bstate->secret, secret_mpi);
+    gcry_mpi_release(secret_mpi);
+
+    otrl_sm_msg2_init(&msg2);
+
+    gcry_mpi_powm(msg2[0], bstate->g1, bstate->x2, SM_MODULUS);
+    otrl_sm_proof_know_log(&(msg2[1]), &(msg2[2]), bstate->g1, bstate->x2, 3);
+
+    gcry_mpi_powm(msg2[3], bstate->g1, bstate->x3, SM_MODULUS);
+    otrl_sm_proof_know_log(&(msg2[4]), &(msg2[5]), bstate->g1, bstate->x3, 4);
+
+    /* Calculate P and Q values for Bob */
+    r = randomExponent();
+    qb1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    qb2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_powm(bstate->p, bstate->g3, r, SM_MODULUS);
+    gcry_mpi_set(msg2[6], bstate->p);
+    gcry_mpi_powm(qb1, bstate->g1, r, SM_MODULUS);
+    gcry_mpi_powm(qb2, bstate->g2, bstate->secret, SM_MODULUS);
+    gcry_mpi_mulm(bstate->q, qb1, qb2, SM_MODULUS);
+    gcry_mpi_set(msg2[7], bstate->q);
+
+    otrl_sm_proof_equal_coords(&(msg2[8]), &(msg2[9]),
+	    &(msg2[10]), bstate, r, 5);
+
+    /* Convert to serialized form */
+    serialize_mpi_array(output, outputlen, SM_MSG2_LEN, msg2);
+
+    /* Free up memory for unserialized and intermediate values */
+    gcry_mpi_release(r);
+    gcry_mpi_release(qb1);
+    gcry_mpi_release(qb2);
+    otrl_sm_msg_free(&msg2, SM_MSG2_LEN);
+
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Create third message in SMP exchange.  Input is a message generated
+ * by otrl_sm_step2b. Output is a serialized mpi array whose elements
+ * correspond to the following:
+ * [0] = pa, [1] = qa, Alice's halves of the (Pa/Pb) and (Qa/Qb) values
+ * [2] = cp, [3] = d5, [4] = d6, Alice's ZK proof that pa, qa formed correctly
+ * [5] = ra, calculated as (Qa/Qb)^x3 where x3 is the exponent used in g3a
+ * [6] = cr, [7] = d7, Alice's ZK proof that ra is formed correctly */
+gcry_error_t otrl_sm_step3(OtrlSMAliceState *astate, const unsigned char* input,
+	const int inputlen, unsigned char **output, int* outputlen)
+{
+    /* Read from input to find the mpis */
+    gcry_mpi_t r, qa1, qa2, inv;
+    gcry_mpi_t *msg2;
+    gcry_mpi_t *msg3;
+    gcry_error_t err;
+
+    *output = NULL;
+    *outputlen = 0;
+    astate->sm_prog_state = OTRL_SMP_PROG_CHEATED;
+
+    err = unserialize_mpi_array(&msg2, SM_MSG2_LEN, input, inputlen);
+    if (err != gcry_error(GPG_ERR_NO_ERROR)) return err;
+
+    if (check_group_elem(msg2[0]) || check_group_elem(msg2[3]) ||
+	    check_group_elem(msg2[6]) || check_group_elem(msg2[7]) ||
+	    check_expon(msg2[2]) || check_expon(msg2[5]) ||
+	    check_expon(msg2[9]) || check_expon(msg2[10])) {
+	otrl_sm_msg_free(&msg2, SM_MSG2_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    otrl_sm_msg3_init(&msg3);
+
+    /* Store Bob's g3a value for later in the protocol */
+    gcry_mpi_set(astate->g3o, msg2[3]);
+
+    /* Verify Bob's knowledge of discrete log proofs */
+    if (otrl_sm_check_know_log(msg2[1], msg2[2], astate->g1, msg2[0], 3) ||
+	    otrl_sm_check_know_log(msg2[4], msg2[5], astate->g1, msg2[3], 4)) {
+	otrl_sm_msg_free(&msg2, SM_MSG2_LEN);
+	otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Combine the two halves from Bob and Alice and determine g2 and g3 */
+    gcry_mpi_powm(astate->g2, msg2[0], astate->x2, SM_MODULUS);
+    gcry_mpi_powm(astate->g3, msg2[3], astate->x3, SM_MODULUS);
+
+    /* Verify Bob's coordinate equality proof */
+    if (otrl_sm_check_equal_coords(msg2[8], msg2[9], msg2[10], msg2[6], msg2[7],
+	    astate, 5)) {
+	otrl_sm_msg_free(&msg2, SM_MSG2_LEN);
+	otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Calculate P and Q values for Alice */
+    r = randomExponent();
+    qa1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    qa2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_powm(astate->p, astate->g3, r, SM_MODULUS);
+    gcry_mpi_set(msg3[0], astate->p);
+    gcry_mpi_powm(qa1, astate->g1, r, SM_MODULUS);
+    gcry_mpi_powm(qa2, astate->g2, astate->secret, SM_MODULUS);
+    gcry_mpi_mulm(astate->q, qa1, qa2, SM_MODULUS);
+    gcry_mpi_set(msg3[1], astate->q);
+
+    otrl_sm_proof_equal_coords(&(msg3[2]), &(msg3[3]), &(msg3[4]), astate,
+	    r, 6);
+
+    /* Calculate Ra and proof */
+    inv = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_invm(inv, msg2[6], SM_MODULUS);
+    gcry_mpi_mulm(astate->pab, astate->p, inv, SM_MODULUS);
+    gcry_mpi_invm(inv, msg2[7], SM_MODULUS);
+    gcry_mpi_mulm(astate->qab, astate->q, inv, SM_MODULUS);
+    gcry_mpi_powm(msg3[5], astate->qab, astate->x3, SM_MODULUS);
+    otrl_sm_proof_equal_logs(&(msg3[6]), &(msg3[7]), astate, 7);
+
+    serialize_mpi_array(output, outputlen, SM_MSG3_LEN, msg3);
+    otrl_sm_msg_free(&msg2, SM_MSG2_LEN);
+    otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+
+    gcry_mpi_release(r);
+    gcry_mpi_release(qa1);
+    gcry_mpi_release(qa2);
+    gcry_mpi_release(inv);
+
+    astate->sm_prog_state = OTRL_SMP_PROG_OK;
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Create final message in SMP exchange.  Input is a message generated
+ * by otrl_sm_step3. Output is a serialized mpi array whose elements
+ * correspond to the following:
+ * [0] = rb, calculated as (Qa/Qb)^x3 where x3 is the exponent used in g3b
+ * [1] = cr, [2] = d7, Bob's ZK proof that rb is formed correctly
+ * This method also checks if Alice and Bob's secrets were the same.  If
+ * so, it returns NO_ERROR.  If the secrets differ, an INV_VALUE error is
+ * returned instead. */
+gcry_error_t otrl_sm_step4(OtrlSMBobState *bstate, const unsigned char* input,
+	const int inputlen, unsigned char **output, int* outputlen)
+{
+    /* Read from input to find the mpis */
+    int comp;
+    gcry_mpi_t inv, rab;
+    gcry_mpi_t *msg3;
+    gcry_mpi_t *msg4;
+    gcry_error_t err;
+    err = unserialize_mpi_array(&msg3, SM_MSG3_LEN, input, inputlen);
+
+    *output = NULL;
+    *outputlen = 0;
+    bstate->sm_prog_state = OTRL_SMP_PROG_CHEATED;
+
+    if (err != gcry_error(GPG_ERR_NO_ERROR)) return err;
+
+    otrl_sm_msg4_init(&msg4);
+
+    if (check_group_elem(msg3[0]) || check_group_elem(msg3[1]) ||
+	    check_group_elem(msg3[5]) || check_expon(msg3[3]) ||
+	    check_expon(msg3[4]) || check_expon(msg3[7]))  {
+	otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+	otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Verify Alice's coordinate equality proof */
+    if (otrl_sm_check_equal_coords(msg3[2], msg3[3], msg3[4], msg3[0], msg3[1],
+	    bstate, 6)) {
+	otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+	otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Find Pa/Pb and Qa/Qb */
+    inv = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_invm(inv, bstate->p, SM_MODULUS);
+    gcry_mpi_mulm(bstate->pab, msg3[0], inv, SM_MODULUS);
+    gcry_mpi_invm(inv, bstate->q, SM_MODULUS);
+    gcry_mpi_mulm(bstate->qab, msg3[1], inv, SM_MODULUS);
+
+    /* Verify Alice's log equality proof */
+    if (otrl_sm_check_equal_logs(msg3[6], msg3[7], msg3[5], bstate, 7)) {
+	otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+	otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+	gcry_mpi_release(inv);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Calculate Rb and proof */
+    gcry_mpi_powm(msg4[0], bstate->qab, bstate->x3, SM_MODULUS);
+    otrl_sm_proof_equal_logs(&(msg4[1]), &(msg4[2]), bstate, 8);
+
+    serialize_mpi_array(output, outputlen, SM_MSG4_LEN, msg4);
+
+    /* Calculate Rab and verify that secrets match */
+    rab = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_powm(rab, msg3[5], bstate->x3, SM_MODULUS);
+    comp = gcry_mpi_cmp(rab, bstate->pab);
+
+    /* Clean up everything allocated in this step */
+    otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+    otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+    gcry_mpi_release(rab);
+    gcry_mpi_release(inv);
+
+    bstate->sm_prog_state = comp ? OTRL_SMP_PROG_FAILED :
+	OTRL_SMP_PROG_SUCCEEDED;
+
+    if (comp)
+	return gcry_error(GPG_ERR_INV_VALUE);
+    else
+	return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Receives the final SMP message, which was generated in otrl_sm_step.
+ * This method checks if Alice and Bob's secrets were the same.  If
+ * so, it returns NO_ERROR.  If the secrets differ, an INV_VALUE error is
+ * returned instead. */
+gcry_error_t otrl_sm_step5(OtrlSMAliceState *astate, const unsigned char* input,
+	const int inputlen)
+{
+    /* Read from input to find the mpis */
+    int comp;
+    gcry_mpi_t rab;
+    gcry_mpi_t *msg4;
+    gcry_error_t err;
+    err = unserialize_mpi_array(&msg4, SM_MSG4_LEN, input, inputlen);
+    astate->sm_prog_state = OTRL_SMP_PROG_CHEATED;
+
+    if (err != gcry_error(GPG_ERR_NO_ERROR)) return err;
+
+    if (check_group_elem(msg4[0]) || check_expon(msg4[2])) {
+	otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Verify Bob's log equality proof */
+    if (otrl_sm_check_equal_logs(msg4[1], msg4[2], msg4[0], astate, 8)) {
+	otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+	return gcry_error(GPG_ERR_INV_VALUE);
+    }
+
+    /* Calculate Rab and verify that secrets match */
+    rab = gcry_mpi_new(SM_MOD_LEN_BITS);
+    gcry_mpi_powm(rab, msg4[0], astate->x3, SM_MODULUS);
+
+    comp = gcry_mpi_cmp(rab, astate->pab);
+    gcry_mpi_release(rab);
+    otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+
+    astate->sm_prog_state = comp ? OTRL_SMP_PROG_FAILED :
+	OTRL_SMP_PROG_SUCCEEDED;
+
+    if (comp)
+	return gcry_error(GPG_ERR_INV_VALUE);
+    else
+	return gcry_error(GPG_ERR_NO_ERROR);
+}
diff --git a/libotr/libotr-4.1.1/src/sm.h b/libotr/libotr-4.1.1/src/sm.h
new file mode 100644
index 0000000..53703ff
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/sm.h
@@ -0,0 +1,84 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SM_H__
+#define __SM_H__
+
+#include <gcrypt.h>
+
+#define SM_HASH_ALGORITHM GCRY_MD_SHA256
+#define SM_DIGEST_SIZE 32
+
+typedef enum {
+    OTRL_SMP_EXPECT1,
+    OTRL_SMP_EXPECT2,
+    OTRL_SMP_EXPECT3,
+    OTRL_SMP_EXPECT4,
+    OTRL_SMP_EXPECT5
+} NextExpectedSMP;
+
+typedef enum {
+    OTRL_SMP_PROG_OK = 0,            /* All is going fine so far */
+    OTRL_SMP_PROG_CHEATED = -2,      /* Some verification failed */
+    OTRL_SMP_PROG_FAILED = -1,       /* The secrets didn't match */
+    OTRL_SMP_PROG_SUCCEEDED = 1      /* The SMP completed successfully */
+} OtrlSMProgState;
+
+typedef struct {
+    gcry_mpi_t secret, x2, x3, g1, g2, g3, g3o, p, q, pab, qab;
+    NextExpectedSMP nextExpected;
+    int received_question;  /* 1 if we received a question in an SMP1Q TLV */
+    OtrlSMProgState sm_prog_state;
+} OtrlSMState;
+
+typedef OtrlSMState OtrlSMAliceState;
+typedef OtrlSMState OtrlSMBobState;
+
+/*
+ * Call this once, at plugin load time.  It sets up the modulus and
+ * generator MPIs.
+ */
+void otrl_sm_init(void);
+
+/*
+ * Initialize the fields of a SM state.
+ */
+void otrl_sm_state_new(OtrlSMState *smst);
+
+/*
+ * Initialize the fields of a SM state.  Called the first time that
+ * a user begins an SMP session.
+ */
+void otrl_sm_state_init(OtrlSMState *smst);
+
+/*
+ * Deallocate the contents of a OtrlSMState (but not the OtrlSMState
+ * itself)
+ */
+void otrl_sm_state_free(OtrlSMState *smst);
+
+gcry_error_t otrl_sm_step1(OtrlSMAliceState *astate, const unsigned char* secret, int secretlen, unsigned char** output, int* outputlen);
+gcry_error_t otrl_sm_step2a(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, int received_question);
+gcry_error_t otrl_sm_step2b(OtrlSMBobState *bstate, const unsigned char* secret, int secretlen, unsigned char **output, int* outputlen);
+gcry_error_t otrl_sm_step3(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen);
+gcry_error_t otrl_sm_step4(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen);
+gcry_error_t otrl_sm_step5(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/tlv.c b/libotr/libotr-4.1.1/src/tlv.c
new file mode 100644
index 0000000..fa76c3d
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/tlv.c
@@ -0,0 +1,109 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "tlv.h"
+
+/* Make a single TLV, copying the supplied data */
+OtrlTLV *otrl_tlv_new(unsigned short type, unsigned short len,
+	const unsigned char *data)
+{
+    OtrlTLV *tlv = malloc(sizeof(OtrlTLV));
+    assert(tlv != NULL);
+    tlv->type = type;
+    tlv->len = len;
+    tlv->data = malloc(len + 1);
+    assert(tlv->data != NULL);
+    memmove(tlv->data, data, len);
+    tlv->data[tlv->len] = '\0';
+    tlv->next = NULL;
+    return tlv;
+}
+
+/* Construct a chain of TLVs from the given data */
+OtrlTLV *otrl_tlv_parse(const unsigned char *serialized, size_t seriallen)
+{
+    OtrlTLV *tlv = NULL;
+    OtrlTLV **tlvp = &tlv;
+    while (seriallen >= 4) {
+	unsigned short type = (serialized[0] << 8) + serialized[1];
+	unsigned short len = (serialized[2] << 8) + serialized[3];
+	serialized += 4; seriallen -=4;
+	if (seriallen < len) break;
+	*tlvp = otrl_tlv_new(type, len, serialized);
+	serialized += len;
+	seriallen -= len;
+	tlvp = &((*tlvp)->next);
+    }
+    return tlv;
+}
+
+/* Deallocate a chain of TLVs */
+void otrl_tlv_free(OtrlTLV *tlv)
+{
+    while (tlv) {
+	OtrlTLV *next = tlv->next;
+	free(tlv->data);
+	free(tlv);
+	tlv = next;
+    }
+}
+
+/* Find the serialized length of a chain of TLVs */
+size_t otrl_tlv_seriallen(const OtrlTLV *tlv)
+{
+    size_t totlen = 0;
+    while (tlv) {
+	totlen += tlv->len + 4;
+	tlv = tlv->next;
+    }
+    return totlen;
+}
+
+/* Serialize a chain of TLVs.  The supplied buffer must already be large
+ * enough. */
+void otrl_tlv_serialize(unsigned char *buf, const OtrlTLV *tlv)
+{
+    while (tlv) {
+	buf[0] = (tlv->type >> 8) & 0xff;
+	buf[1] = tlv->type & 0xff;
+	buf[2] = (tlv->len >> 8) & 0xff;
+	buf[3] = tlv->len & 0xff;
+	buf += 4;
+	memmove(buf, tlv->data, tlv->len);
+	buf += tlv->len;
+	tlv = tlv->next;
+    }
+}
+
+/* Return the first TLV with the given type in the chain, or NULL if one
+ * isn't found.  (The tlvs argument isn't const because the return type
+ * needs to be non-const.) */
+OtrlTLV *otrl_tlv_find(OtrlTLV *tlvs, unsigned short type)
+{
+    while (tlvs) {
+	if (tlvs->type == type) return tlvs;
+	tlvs = tlvs->next;
+    }
+    return NULL;
+}
diff --git a/libotr/libotr-4.1.1/src/tlv.h b/libotr/libotr-4.1.1/src/tlv.h
new file mode 100644
index 0000000..0bfeeb2
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/tlv.h
@@ -0,0 +1,78 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TLV_H__
+#define __TLV_H__
+
+typedef struct s_OtrlTLV {
+    unsigned short type;
+    unsigned short len;
+    unsigned char *data;
+    struct s_OtrlTLV *next;
+} OtrlTLV;
+
+/* TLV types */
+
+/* This is just padding for the encrypted message, and should be ignored. */
+#define OTRL_TLV_PADDING         0x0000
+
+/* The sender has thrown away his OTR session keys with you */
+#define OTRL_TLV_DISCONNECTED    0x0001
+
+/* The message contains a step in the Socialist Millionaires' Protocol. */
+#define OTRL_TLV_SMP1            0x0002
+#define OTRL_TLV_SMP2            0x0003
+#define OTRL_TLV_SMP3            0x0004
+#define OTRL_TLV_SMP4            0x0005
+#define OTRL_TLV_SMP_ABORT       0x0006
+/* Like OTRL_TLV_SMP1, but there's a question for the buddy at the
+ * beginning */
+#define OTRL_TLV_SMP1Q           0x0007
+/* Tell the application the current "extra" symmetric key */
+/* XXX: Document this in the protocol spec:
+ * The body of the TLV will begin with a 4-byte indication of what this
+ * symmetric key will be used for (file transfer, voice encryption,
+ * etc.).  After that, the contents are use-specific (which file, etc.).
+ * There are no currently defined uses. */
+#define OTRL_TLV_SYMKEY          0x0008
+
+/* Make a single TLV, copying the supplied data */
+OtrlTLV *otrl_tlv_new(unsigned short type, unsigned short len,
+	const unsigned char *data);
+
+/* Construct a chain of TLVs from the given data */
+OtrlTLV *otrl_tlv_parse(const unsigned char *serialized, size_t seriallen);
+
+/* Deallocate a chain of TLVs */
+void otrl_tlv_free(OtrlTLV *tlv);
+
+/* Find the serialized length of a chain of TLVs */
+size_t otrl_tlv_seriallen(const OtrlTLV *tlv);
+
+/* Serialize a chain of TLVs.  The supplied buffer must already be large
+ * enough. */
+void otrl_tlv_serialize(unsigned char *buf, const OtrlTLV *tlv);
+
+/* Return the first TLV with the given type in the chain, or NULL if one
+ * isn't found.  (The tlvs argument isn't const because the return type
+ * needs to be non-const.) */
+OtrlTLV *otrl_tlv_find(OtrlTLV *tlvs, unsigned short type);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/userstate.c b/libotr/libotr-4.1.1/src/userstate.c
new file mode 100644
index 0000000..58f5a05
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/userstate.c
@@ -0,0 +1,57 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Rob Smits, Chris Alexander,
+ *  			      Willy Lew, Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* system headers */
+#include <stdlib.h>
+
+/* libotr headers */
+#include "context.h"
+#include "privkey.h"
+#include "userstate.h"
+
+/* Create a new OtrlUserState.  Most clients will only need one of
+ * these.  A OtrlUserState encapsulates the list of known fingerprints
+ * and the list of private keys; if you have separate files for these
+ * things for (say) different users, use different OtrlUserStates.  If
+ * you've got only one user, with multiple accounts all stored together
+ * in the same fingerprint store and privkey store files, use just one
+ * OtrlUserState. */
+OtrlUserState otrl_userstate_create(void)
+{
+    OtrlUserState us = malloc(sizeof(struct s_OtrlUserState));
+    if (!us) return NULL;
+    us->context_root = NULL;
+    us->privkey_root = NULL;
+    us->instag_root = NULL;
+    us->pending_root = NULL;
+    us->timer_running = 0;
+    return us;
+}
+
+/* Free a OtrlUserState.  If you have a timer running for this userstate,
+stop it before freeing the userstate. */
+void otrl_userstate_free(OtrlUserState us)
+{
+    otrl_context_forget_all(us);
+    otrl_privkey_forget_all(us);
+    otrl_privkey_pending_forget_all(us);
+    otrl_instag_forget_all(us);
+    free(us);
+}
diff --git a/libotr/libotr-4.1.1/src/userstate.h b/libotr/libotr-4.1.1/src/userstate.h
new file mode 100644
index 0000000..3f1e3b8
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/userstate.h
@@ -0,0 +1,51 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2012  Ian Goldberg, Rob Smits, Chris Alexander,
+ *  			      Willy Lew, Lisa Du, Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __USERSTATE_H__
+#define __USERSTATE_H__
+
+typedef struct s_OtrlUserState* OtrlUserState;
+
+#include "instag.h"
+#include "context.h"
+#include "privkey-t.h"
+
+struct s_OtrlUserState {
+    ConnContext *context_root;
+    OtrlPrivKey *privkey_root;
+    OtrlInsTag *instag_root;
+    OtrlPendingPrivKey *pending_root;
+    int timer_running;
+};
+
+/* Create a new OtrlUserState.  Most clients will only need one of
+ * these.  A OtrlUserState encapsulates the list of known fingerprints
+ * and the list of private keys; if you have separate files for these
+ * things for (say) different users, use different OtrlUserStates.  If
+ * you've got only one user, with multiple accounts all stored together
+ * in the same fingerprint store and privkey store files, use just one
+ * OtrlUserState. */
+OtrlUserState otrl_userstate_create(void);
+
+/* Free a OtrlUserState.  If you have a timer running for this userstate,
+stop it before freeing the userstate. */
+void otrl_userstate_free(OtrlUserState us);
+
+#endif
diff --git a/libotr/libotr-4.1.1/src/version.h b/libotr/libotr-4.1.1/src/version.h
new file mode 100644
index 0000000..c7f990f
--- /dev/null
+++ b/libotr/libotr-4.1.1/src/version.h
@@ -0,0 +1,31 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2016  Ian Goldberg, David Goulet, Rob Smits,
+ *                           Chris Alexander, Willy Lew, Lisa Du,
+ *                           Nikita Borisov
+ *                           <otr@cypherpunks.ca>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of version 2.1 of the GNU Lesser General
+ *  Public License as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+#define OTRL_VERSION "4.1.1"
+
+#define OTRL_VERSION_MAJOR 4
+#define OTRL_VERSION_MINOR 1
+#define OTRL_VERSION_SUB 1
+
+#endif