[Pkg-privacy-commits] [irssi-plugin-otr] 04/267: lots of changes:

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 12:41:21 UTC 2015


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch debian
in repository irssi-plugin-otr.

commit d84a9bf06e2fb9f54aad58e4504052cdc09daf46
Author: Uli Meis <a.sporto+bee at gmail.com>
Date:   Sat May 31 00:01:29 2008 +0200

    lots of changes:
    
    * moved to cmake. Seems overkill for such a small project but it does make
      life easier for developing and also for packaging (should that ever happen).
      Autotools never was an option for me.
    * implemented socialist millionaire protocol
      (some problems with it though, but they seem to be libotr problems)
    * put all text into /formats so messages are totally configurable.
      Also keeps the code clean.
    * moved code around a bit (e.g. only one header now besides formats)
    * some other things I dont recall right now ;)
---
 .gitignore                        |   4 +
 CMakeLists.txt                    | 113 +++++++
 INSTALL                           |  10 +
 Makefile                          |  39 ---
 README                            |  36 ++
 cmake-extensions/FindLibOTR.cmake |  49 +++
 cmake-extensions/cscope.cmake     |  17 +
 formats.txt                       |  70 ++++
 makeformats.py                    |  84 +++++
 otr.c                             | 156 ++++++---
 otr.h                             | 117 +++++--
 otr_key.c                         | 224 +++++++++++++
 otr_ops.c                         | 203 ++++++++++++
 otrutil.c                         | 677 ++++++++++++++++++--------------------
 otrutil.h                         |  41 ---
 ui.c                              |  57 ++--
 ui.h                              |  29 --
 17 files changed, 1366 insertions(+), 560 deletions(-)

diff --git a/.gitignore b/.gitignore
index c0cd457..886bc2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,7 @@
 term.h
 statusbar.h
 mainwindows.h
+.exrc
+*.swp
+cscope.files
+cscope.out
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..e7b6100
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,113 @@
+#
+# Off-the-Record Messaging (OTR) module for the irssi IRC client
+# Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
+#
+
+PROJECT(IRSSIOTR)
+
+SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake-extensions/)
+INCLUDE(cmake-extensions/cscope.cmake)
+
+# GLIB
+
+FIND_PACKAGE(PkgConfig REQUIRED)
+pkg_check_modules(GLIB REQUIRED glib-2.0)
+
+# LIBOTR
+
+FIND_PACKAGE(LibOTR REQUIRED)
+IF (LIBOTR_VERSION LESS "3.1.0")
+  MESSAGE(FATAL_ERROR "Need libotr version >= 3.1.0 (fragmentation)")
+ENDIF (LIBOTR_VERSION LESS "3.1.0")
+
+# irssi public headers
+
+FIND_PATH(IRSSI_INCLUDE_DIR NAMES irssi/src/core/module.h)
+MARK_AS_ADVANCED(IRSSI_INCLUDE_DIR)
+
+IF(NOT IRSSI_INCLUDE_DIR)
+  MESSAGE(FATAL_ERROR "Couldn't find irssi headers, "
+    "usually installed in /usr/include/irssi")
+ENDIF(NOT IRSSI_INCLUDE_DIR)
+
+# Bad hack for irssi private headers
+
+FIND_PACKAGE(Wget REQUIRED)
+
+IF (NOT EXISTS "mainwindows.h")
+  MESSAGE(STATUS "Need to fetch and patch irssi private headers "
+    "mainwindows.h,statusbar.h,term.h from SVN (see irssi FS#535)")
+  EXECUTE_PROCESS(COMMAND "bash" "-c"
+    "${WGET_EXECUTABLE} '--post-data=revision=4806&root=irssi' \\
+    'http://svn.irssi.org/cgi-bin/viewvc.cgi/irssi/trunk/src/fe-text/mainwindows.h' \\
+    'http://svn.irssi.org/cgi-bin/viewvc.cgi/irssi/trunk/src/fe-text/term.h' \\
+    'http://svn.irssi.org/cgi-bin/viewvc.cgi/irssi/trunk/src/fe-text/statusbar.h' || exit 1
+    patch -p0 mainwindows.h < \"$0/privheaders.patch\" || exit 1" 
+    ${PROJECT_SOURCE_DIR} RESULT_VARIABLE IIPRIV_RET)
+  IF(NOT IIPRIV_RET EQUAL 0)
+    MESSAGE(FATAL_ERROR "Couldn't check out irssi private headers from SVN")
+  ENDIF(NOT IIPRIV_RET EQUAL 0)
+ENDIF (NOT EXISTS "mainwindows.h")
+
+# includes
+
+SET(IRSSIOTR_INCLUDE_DIRS
+  ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ${GLIB_INCLUDE_DIRS} 
+  ${LIBOTR_INCLUDE_DIRS} 
+  ${IRSSI_INCLUDE_DIR}/irssi
+  ${IRSSI_INCLUDE_DIR}/irssi/src
+  ${IRSSI_INCLUDE_DIR}/irssi/src/core)
+
+include_directories(${IRSSIOTR_INCLUDE_DIRS})
+
+# defs
+
+ADD_DEFINITIONS(-DHAVE_CONFIG_H -Wall -g)
+
+# generate otr-formats.{c,h}
+
+ADD_CUSTOM_COMMAND(OUTPUT ${PROJECT_BINARY_DIR}/otr-formats.c 
+  DEPENDS makeformats.py formats.txt README
+  COMMAND 
+  ${PROJECT_SOURCE_DIR}/makeformats.py 
+  ${PROJECT_SOURCE_DIR}/formats.txt
+  ${PROJECT_SOURCE_DIR}/README
+  )
+
+# lib
+
+ADD_LIBRARY(otr SHARED otr.c otrutil.c otr_ops.c otr_key.c ui.c ${PROJECT_BINARY_DIR}/otr-formats.c)
+
+TARGET_LINK_LIBRARIES(otr ${GLIB_LIBRARIES} ${LIBOTR_LIBRARIES})
+
+# Install
+
+EXECUTE_PROCESS(COMMAND "whoami" OUTPUT_VARIABLE WHOAMI)
+IF(WHOAMI STREQUAL "root\n")
+  SET(IRSSIOTR_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/irssi/modules/")
+  MESSAGE(STATUS "Install will be into ${IRSSIOTR_INSTALL_DIR}")
+ELSE(WHOAMI STREQUAL "root\n")
+  SET(IRSSIOTR_INSTALL_DIR "$ENV{HOME}/.irssi/modules/")
+  MESSAGE(STATUS "You're not root. Install will be into ${IRSSIOTR_INSTALL_DIR}")
+ENDIF(WHOAMI STREQUAL "root\n")
+
+INSTALL(TARGETS otr DESTINATION ${IRSSIOTR_INSTALL_DIR})
+
+# cscope
+
+FILE(GLOB CSANDHS *.c *.h)
+ADD_CSCOPE_TARGET(${CSANDHS} ${IRSSIOTR_INCLUDE_DIRS})
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..d372465
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,10 @@
+Usually the following will do:
+
+	$ cmake /path/to/src
+	$ make
+	$ make install
+
+"make install" will install libotr.so either
+
+1. into the system wide irssi modules folder if you're root or
+2. into ~/.irssi/modules if you're not root
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 541377c..0000000
--- a/Makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-SRCS=otr.c otrutil.c ui.c
-HDRS=otr.h otrutil.h ui.h mainwindows.h
-OBJS=$(SRCS:%.c=%.o)
-
-INCLUDES=-I/usr/include/irssi/ -I/usr/include/irssi/src -I/usr/include/irssi/src/core -I.
-DEFINES=-DHAVE_CONFIG_H
-
-CFLAGS=-Wall -g -fPIC ${INCLUDES} ${DEFINES} `pkg-config --cflags glib-2.0`
-LDFLAGS=-shared -lotr
-
-CC=gcc
-LD=ld
-
-.PHONY: deploy compile
-
-compile: libotr.so
-
-deploy: libotr.so
-	cp libotr.so ~/.irssi/modules/libotr.so
-
-
-%.so:
-	${LD} ${LDFLAGS} $^ -o $@
-
-mainwindows.h:
-	@echo "**** Fetching headers from irssi svn..."
-	@for hdr in mainwindows.h term.h statusbar.h; do \
-		svn cat -r 4815 http://svn.irssi.org/repos/irssi/trunk/src/fe-text/$$hdr >$$hdr \
-	 ;done
-	patch -p0 mainwindows.h <privheaders.patch
-
-otr.o:	    otr.c	${HDRS}
-otrutil.o:  otrutil.c	${HDRS}
-ui.o:	    ui.c	ui.h
-
-libotr.so: ${OBJS}
-
-clean:
-	rm *.o *.so
diff --git a/README b/README
new file mode 100644
index 0000000..1341e1f
--- /dev/null
+++ b/README
@@ -0,0 +1,36 @@
+Usually, you shouldn't have to do anything besides "/load otr" to have encrypted
+conversations.  However,  some IRC  servers  strip  off  the  tabs OTR  uses  as
+announcement, there you or your buddy will have to type "?OTR?" to get going.
+
+Initially  a private  key will  also have  to be  generated...that can  take two
+minutes or even  an hour. You can wait  for OTR to trigger key  generation or do
+"/otr genkey nick at irc.server.com" yourself.
+
+To make  sure that you are  actually talking to your  buddy, you can agree  on a
+secret somehow  and then one does  "/otr auth <secret>". Shortly  afterwards the
+other one will be asked to do  the same and you're done. Well, unfortunately the
+world ain't perfect and  it seems libotr isn't either (goes for  me as well), so
+currently only the responder will be  able to authenticate this way. You'll have
+to switch roles and do this twice - sry.
+
+I also strongly  recommend to do "/statusbar window add  otr" so you're informed
+about  what's going  on.  Status  of "manual"  means  manual authentication  was
+performed,  "smp"  means  the  above  protocol  was  used  (the  thing's  called
+"socialist millionaire protocol").
+
+In  "~/.irssi/otr/otr.{key,fp}" you'll  find the  fingerprints and  your private
+keys(should you at any point be interested).
+
+Commands:
+
+/otr genkey nick at irc.server.com 
+	Manually generate a key for the given account(also done on demand)
+/otr auth <secret>
+	Initiate or respond to an authentication challenge
+/otr authabort
+	Abort any ongoing authentication
+/otr trust
+	Trust the fingerprint of the user in the current window blindly.
+	Better use "/otr auth"
+/otr debug
+	Switch debug mode on/off
diff --git a/cmake-extensions/FindLibOTR.cmake b/cmake-extensions/FindLibOTR.cmake
new file mode 100644
index 0000000..63624c9
--- /dev/null
+++ b/cmake-extensions/FindLibOTR.cmake
@@ -0,0 +1,49 @@
+# 
+# Uli Meis <a.sporto+bee at gmail.com>
+#
+# Mostly taken from cmake findcurl, version stuff from kopete
+#
+# - Find libotr
+# Find the libotr headers and library.
+#
+#  LIBOTR_INCLUDE_DIR
+#  LIBOTR_LIBRARIES
+#  LIBOTR_FOUND
+
+# Look for the header file.
+FIND_PATH(LIBOTR_INCLUDE_DIR NAMES libotr/version.h)
+MARK_AS_ADVANCED(LIBOTR_INCLUDE_DIR)
+
+# Look for the library.
+FIND_LIBRARY(LIBOTR_LIBRARY NAMES otr)
+MARK_AS_ADVANCED(LIBOTR_LIBRARY)
+
+# Copy the results to the output variables.
+IF(LIBOTR_INCLUDE_DIR AND LIBOTR_LIBRARY)
+  SET(LIBOTR_FOUND 1)
+  SET(LIBOTR_LIBRARIES ${LIBOTR_LIBRARY})
+  SET(LIBOTR_INCLUDE_DIRS ${LIBOTR_INCLUDE_DIR})
+  EXECUTE_PROCESS(COMMAND grep "OTRL_VERSION" 
+    "${LIBOTR_INCLUDE_DIR}/libotr/version.h" OUTPUT_VARIABLE output)
+  STRING(REGEX MATCH "OTRL_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+" 
+    LIBOTR_VERSION "${output}")
+  STRING(REGEX REPLACE "^OTRL_VERSION \"" "" LIBOTR_VERSION "${LIBOTR_VERSION}")
+  MESSAGE(STATUS "  found libotr, version ${LIBOTR_VERSION}" )
+ELSE(LIBOTR_INCLUDE_DIR AND LIBOTR_LIBRARY)
+  SET(LIBOTR_FOUND 0)
+  SET(LIBOTR_LIBRARIES)
+  SET(LIBOTR_INCLUDE_DIRS)
+ENDIF(LIBOTR_INCLUDE_DIR AND LIBOTR_LIBRARY)
+
+# Report the results.
+IF(NOT LIBOTR_FOUND)
+  SET(LIBOTR_DIR_MESSAGE
+    "LIBOTR was not found. Make sure LIBOTR_LIBRARY and LIBOTR_INCLUDE_DIR are set.")
+  IF(NOT LIBOTR_FIND_QUIETLY)
+    MESSAGE(STATUS "${LIBOTR_DIR_MESSAGE}")
+  ELSE(NOT LIBOTR_FIND_QUIETLY)
+    IF(LIBOTR_FIND_REQUIRED)
+      MESSAGE(FATAL_ERROR "${LIBOTR_DIR_MESSAGE}")
+    ENDIF(LIBOTR_FIND_REQUIRED)
+  ENDIF(NOT LIBOTR_FIND_QUIETLY)
+ENDIF(NOT LIBOTR_FOUND)
diff --git a/cmake-extensions/cscope.cmake b/cmake-extensions/cscope.cmake
new file mode 100644
index 0000000..59594b4
--- /dev/null
+++ b/cmake-extensions/cscope.cmake
@@ -0,0 +1,17 @@
+#
+# Uli Meis <a.sporto+bee at gmail.com>
+#
+# Handy macro for generating the cscope database
+#
+
+MACRO(ADD_CSCOPE_TARGET CSCOPE_SOURCES CSCOPE_INCLUDES)
+  ADD_CUSTOM_COMMAND(
+    OUTPUT cscope.out
+    DEPENDS ${CSCOPE_SOURCES}
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+    COMMAND 
+      echo '${CSCOPE_SOURCES}' | tr ' ' '\\n' >cscope.files
+    COMMAND
+      cscope -b `echo ${CSCOPE_INCLUDES} | xargs -n1 bash -c 'echo -I$$0'`)
+  ADD_CUSTOM_TARGET(cscope DEPENDS cscope.out)
+ENDMACRO(ADD_CSCOPE_TARGET)
diff --git a/formats.txt b/formats.txt
new file mode 100644
index 0000000..5ce4412
--- /dev/null
+++ b/formats.txt
@@ -0,0 +1,70 @@
+damn	{hilight Damn!}
+bumsum	One {hilight two}
+whatever	One %s hell %s
+kg_failed	Key generation for %s: failed: %s (%s)
+kg_completed	Key generation for %s: completed in %d seconds. Reloading keys
+kg_aborted_dup	Key generation for %s: aborted. Key generation for %s still in progress
+kg_aborted_dir	Key generation for %s: aborted, failed creating directory %s: %s
+kg_mkdir	created directory %s
+kg_pipe	Key generation for %s: error creating pipe: %s
+kg_fork	Key generation for %s: fork() error: %s
+kg_initiated	Key generation for %s: initiated. This might take several minutes or on some systems even an hour. If you wanna check that something is happening, see if there are two irssi processes.
+fp_saved	fingerprints saved
+fp_save_error	Error saving fingerprints: %s (%s)
+ops_notify_bug	BUG() in ops_notify
+ops_notify	title: %s prim: %s sec: %s
+ops_display_bug	BUG() in ops_display
+ops_display	msg: %s
+ops_sec	gone %9secure%9
+ops_insec	gone %9insecure%9
+ops_still_reply	still %9secure%9 (is reply)
+ops_still_no_reply	still %9secure%9 (is not reply)
+ops_log	log msg: %s
+key_not_found	no private keys found
+key_loaded	private keys loaded
+key_load_error	Error loading private keys: %s (%s)
+fp_not_found	no fingerprints found
+fp_loaded	fingerprints loaded
+fp_load_error	Error loading fingerprints: %s (%s)
+fp_trust	Trusting fingerprint from %s
+send_failed	send failed: msg=%s
+send_change	couldn't find context also OTR changed the outgoing message(BUG?)
+send_fragment	failed to fragment message: msg=%s
+send_converted	OTR converted sent message to %s
+ctx_not_found	couldn't find context: acc=%s nick=%s
+auth_aborted_ongoing	Ongoing authentication aborted
+auth_aborted	Authentication aborted
+auth_responding	Responding to authentication request...
+auth_initiated	Initiated authentication...
+ctx_not_create	couldn't create/find context: acc=%s from=%s
+receive_ignore_query	ignoring rest of OTR default query msg
+receive_dequeued	dequeued msg of length %d
+receive_queued	queued msg of length %d
+receive_ignore	ignoring protocol message of length %s, acc=%s, from=%s
+receive_converted	OTR converted received message
+auth_have_old	%s wanted to authenticate but an old authentication was still ongoing.  Old authentication will be aborted, please try again.
+auth_peer	%s wants to authenticate. Type /otr auth <your-shared-secret> to complete.
+auth_peer_reply_wrong	%s replied to an auth we didn't start.
+auth_peer_replied	%s replied to our auth request...
+auth_peer_wrong_smp3	%s sent a wrong authentication message (SMP3).
+auth_successful	Authentication successful!
+auth_failed	Authentication failed!
+otr_better_two	<b>%s</b> has requested an <a href=\"http://otr.cypherpunks.ca/\">Off-the-Record private conversation</a>.  However, you do not have a plugin to support that.
+otr_better_three	See <a href=\"http://otr.cypherpunks.ca/\">http://otr.cypherpunks.ca/</a> for more information.
+cmd_otr	We're alive
+cmd_trust	failed: Can't get query details
+cmd_auth	Please agree on a secret and then run /otr auth <secret>
+cmd_debug_on	Debug mode is on
+cmd_debug_off	Debug mode is off
+nickignore	xmlconsole
+st_plaintext	{sb plaintext}
+st_untrusted	{sb {hilight encrypted}(untrusted)}
+st_trust_smp	{sb {hilight authenticated}(smp)}
+st_trust_manual	{sb {hilight authenticated}(manual)}
+st_smp_wait_2	{sb {hilight awaiting auth reply...}}
+st_smp_have_2	{sb {hilight finalizing auth... (won't happen with libotr 3.1(bug), ask the other guy to initiate)}}
+st_smp_failed	{sb {hilight auth failed}}
+st_smp_finalize	{sb {hilight finalizing auth...}}
+st_smp_unknown	{sb {hilight unknown auth state!}}
+st_finished	{sb finished}
+st_unknown	{sb {hilight state unknown (BUG!)}}
diff --git a/makeformats.py b/makeformats.py
new file mode 100755
index 0000000..d2c3bab
--- /dev/null
+++ b/makeformats.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+#
+# Uli Meis <a.sporto+bee at gmail.com>
+#
+# Just a short script to generate our FORMAT_REC
+#
+
+import sys,os,re
+
+lines = map(lambda x: x.strip(),open(sys.argv[1],"r").readlines())
+
+hdr = open("otr-formats.h","w")
+src = open("otr-formats.c","w")
+
+src.write('#include "otr.h"\nFORMAT_REC formats[] = {\n')
+
+src.write('{ MODULE_NAME, "otr", 0},\n')
+
+src.write("""{ "help", "%s", 0 }""" % "\\n".join(
+	["{hilight - OTR help -}"]+
+	[re.sub('^(/otr.*)$','%_\\1%_',
+		re.sub('"(.*)"','\\"%_\\1%_\\"',
+			x.replace('\n','').replace("\t","        ") 
+			))
+		for x in open(sys.argv[2],"r").readlines()]+
+	["{hilight - End of OTR help -}"]))
+
+hdr.write("enum {\n")
+
+hdr.write("TXT_OTR_MODULE_NAME,\nTXT_HELP")
+
+for line in lines:
+	src.write(",\n")
+
+	e = line.split("\t")
+
+	params = []
+	fo = e[1]
+	new = ""
+	last=0
+	i=0
+	for m in re.finditer("(^|[^%])%[ds]",fo):
+		if m.group()[-1]=='d':
+			params += ['1']
+		else:
+			params += ['0']
+		new += fo[last:m.start()]+"$%d" % i
+		last = m.end()
+		i += 1
+
+	new += fo[last:]
+
+	e[1] = new
+	e += [len(params)] + params
+
+	#print "Handling line %s with elen %d" % (line,len(e))
+
+	premsg = ""
+	if e[1][0] != "{":
+		premsg = "%9OTR%9: "
+
+	src.write("""{ "%s", "%s%s", %s""" % (e[0],premsg,e[1],e[2]))
+
+	if len(params)>0:
+		src.write(", { %s }" % ", ".join(params))
+
+	src.write("}")
+
+	hdr.write(",\n")
+
+	hdr.write("TXT_%s" % e[0].upper())
+
+hdr.write("""
+};
+
+extern FORMAT_REC formats[];
+""")
+
+src.write("""
+};
+""")
+
+hdr.close()
+src.close()
diff --git a/otr.c b/otr.c
index f2824df..6d2f4ee 100644
--- a/otr.c
+++ b/otr.c
@@ -1,31 +1,32 @@
 /*
-	Off-the-Record Messaging (OTR) module for the irssi IRC client
-	Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program 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 General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-*/
+ * Off-the-Record Messaging (OTR) module for the irssi IRC client
+ * Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
+ */
 
 #include "otr.h"
 
 int debug = FALSE;
+GRegex *regex_nickignore;
 
 /*
  * Pipes all outgoing private messages through OTR
  */
 static void sig_server_sendmsg(SERVER_REC *server, const char *target,
-                               const char *msg, void *target_type_p)
+			       const char *msg, void *target_type_p)
 {
 	if (GPOINTER_TO_INT(target_type_p)==SEND_TARGET_NICK) {
 		char *otrmsg = otr_send(server,msg,target);
@@ -41,15 +42,13 @@ static void sig_server_sendmsg(SERVER_REC *server, const char *target,
  * Pipes all incoming private messages through OTR
  */
 static void sig_message_private(SERVER_REC *server, const char *msg,
-                                const char *nick, const char *address)
+				const char *nick, const char *address)
 {
 	char *newmsg;
 
-	/* hack for bitlbee so we're not too busy 
-	 * with the jabber xml console */
-	if (strstr(nick,"xmlconsole"))
+	if (g_regex_match(regex_nickignore,nick,0,NULL))
 		return;
-	
+
 	newmsg = otr_receive(server,msg,nick);
 
 	if (newmsg&&(newmsg!=msg)) {
@@ -62,76 +61,151 @@ static void sig_message_private(SERVER_REC *server, const char *msg,
 /*
  * /otr
  */
-static void cmd_otr(const char *data,void *server,WI_ITEM_REC *item) {
+static void cmd_otr(const char *data,void *server,WI_ITEM_REC *item) 
+{
 	if (*data == '\0')
-		otr_logst(LVL_NOTICE,"We're alive");
+		otr_noticest(TXT_CMD_OTR);
 	else {
 		command_runsub("otr", data, server, item);
 	}
 }
 
-static void cmd_trust(const char *data, void *server, WI_ITEM_REC *item) {
+/*
+ * /otr trust
+ */
+static void cmd_trust(const char *data, void *server, WI_ITEM_REC *item)
+{
 	QUERY_REC *query = QUERY(item);
 	if (query&&query->server&&query->server->connrec)
-		otr_trust(query->server->nick,query->name,query->server->connrec->address);
+		otr_trust(query->server,query->name);
 	else
-		otr_log(item->server,NULL,query ? query->name : NULL,LVL_NOTICE,
-			"failed: Can't get query details");
+		otr_notice(item->server,query ? query->name : NULL,
+			   TXT_CMD_TRUST);
+}
+
+/*
+ * /otr genkey nick at irc.server.com
+ */
+static void cmd_genkey(const char *data, void *server, WI_ITEM_REC *item)
+{
+	//TODO check data
+	keygen_run(data);
+}
+
+/*
+ * /otr auth <secret>
+ */
+static void cmd_auth(const char *data, void *server, WI_ITEM_REC *item)
+{
+	WI_ITEM_REC *wi = active_win->active;
+	QUERY_REC *query = QUERY(wi);
+
+	if (query&&query->server&&query->server->connrec) {
+		if (!data||(*data=='\0')) {
+			otr_notice(server,query->name,
+				   TXT_CMD_AUTH);
+			return;
+		}
+		otr_auth(query->server,query->name,data);
+	}
+}
+
+/*
+ * /otr authabort
+ */
+static void cmd_authabort(const char *data, void *server, WI_ITEM_REC *item)
+{
+	WI_ITEM_REC *wi = active_win->active;
+	QUERY_REC *query = QUERY(wi);
+
+	if (query&&query->server&&query->server->connrec)
+		otr_authabort(query->server,query->name);
 }
 
 /*
  * /otr debug
  */
-static void cmd_debug(const char *data, void *server, WI_ITEM_REC *item) {
+static void cmd_debug(const char *data, void *server, WI_ITEM_REC *item)
+{
 	debug = !debug;
-	otr_logst(LVL_NOTICE,"Debug mode %s", debug ? "on" : "off" );
+	otr_noticest(debug ? TXT_CMD_DEBUG_ON : TXT_CMD_DEBUG_OFF);
+}
+
+/*
+ * /otr help
+ */
+static void cmd_help(const char *data, void *server, WI_ITEM_REC *item)
+{
+	printformat(NULL,NULL,MSGLEVEL_CRAP,TXT_HELP);
 }
 
-static void otr_statusbar(SBAR_ITEM_REC *item, int get_size_only) {
+/*
+ * otr statusbar
+ */
+static void otr_statusbar(SBAR_ITEM_REC *item, int get_size_only)
+{
 	WI_ITEM_REC *wi = active_win->active;
 	QUERY_REC *query = QUERY(wi);
-	char *data = NULL;
+	int formatnum=0;
 
 	if (query&&query->server&&query->server->connrec)
-		data = otr_getstatus(query->server->nick,query->name,query->server->connrec->address);
-	
+		formatnum = otr_getstatus(query->server->nick,query->name,query->server->connrec->address);
+
 	statusbar_item_default_handler(
 		item, 
 		get_size_only, 
-		 data ? "{sb Otr: $0-}" : "",data,FALSE);
+		formatnum ? formats[formatnum].def : ""," ",FALSE);
 }
 
 /*
  * irssi init()
  */
-void otr_init(void) {
+void otr_init(void)
+{
+	regex_nickignore = g_regex_new(formats[TXT_NICKIGNORE].def,0,0,NULL);
+
 	module_register(MODULE_NAME,  "core");
 
+	theme_register(formats);
+
 	if (otrlib_init())
 		return;
 
 	signal_add_first("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);
 	signal_add_first("message private", (SIGNAL_FUNC) sig_message_private);
-	
+
 	command_bind("otr", NULL, (SIGNAL_FUNC) cmd_otr);
 	command_bind("otr debug", NULL, (SIGNAL_FUNC) cmd_debug);
 	command_bind("otr trust", NULL, (SIGNAL_FUNC) cmd_trust);
+	command_bind("otr genkey", NULL, (SIGNAL_FUNC) cmd_genkey);
+	command_bind("otr auth", NULL, (SIGNAL_FUNC) cmd_auth);
+	command_bind("otr authabort", NULL, (SIGNAL_FUNC) cmd_authabort);
+	command_bind("otr help", NULL, (SIGNAL_FUNC) cmd_help);
 
 	statusbar_item_register("otr", NULL, otr_statusbar);
 
 	statusbar_items_redraw("window");
-	/* use standard irssi style messages */
-	theme_register_module(MODULE_NAME,fecommon_core_formats);
+
 }
 
 /*
  * irssi deinit()
  */
-void otr_deinit(void) {
+void otr_deinit(void)
+{
+	g_regex_unref(regex_nickignore);
 
 	signal_remove("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg);
 	signal_remove("message private", (SIGNAL_FUNC) sig_message_private);
 
+	command_unbind("otr", (SIGNAL_FUNC) cmd_otr);
+	command_unbind("otr debug", (SIGNAL_FUNC) cmd_debug);
+	command_unbind("otr trust", (SIGNAL_FUNC) cmd_trust);
+	command_unbind("otr genkey", (SIGNAL_FUNC) cmd_genkey);
+	command_unbind("otr auth", (SIGNAL_FUNC) cmd_auth);
+	command_unbind("otr authabort", (SIGNAL_FUNC) cmd_authabort);
+	command_unbind("otr help", (SIGNAL_FUNC) cmd_help);
+
 	statusbar_item_unregister("otr");
 
 	otrlib_deinit();
diff --git a/otr.h b/otr.h
index 9ba99ae..e7c6ece 100644
--- a/otr.h
+++ b/otr.h
@@ -1,27 +1,28 @@
 /*
-	Off-the-Record Messaging (OTR) module for the irssi IRC client
-	Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program 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 General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-*/
+ * Off-the-Record Messaging (OTR) module for the irssi IRC client
+ * Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
+ */
 
 #include <stdlib.h>
 
 /* OTR */
 
 #include <libotr/proto.h>
+#include <libotr/context.h>
 #include <libotr/message.h>
 #include <libotr/privkey.h>
 
@@ -50,9 +51,87 @@
 
 /* own */
 
-#include "otrutil.h"
-#include "ui.h"
+#include "otr-formats.h"
 
 /* irssi module name */
 #define MODULE_NAME "otr"
 
+/* 
+ * maybe this should be configurable?
+ * I believe bitlbee has something >500.
+ */
+#define OTR_MAX_MSG_SIZE 400
+
+/* otr protocol id */
+#define PROTOCOLID "IRC"
+
+#define KEYFILE "/otr/otr.key"
+#define FPSFILE "/otr/otr.fp"
+
+/* one for each OTR context (=communication pair) */
+struct co_info {
+	char *msgqueue;			/* holds partially reconstructed base64
+					   messages */
+	SERVER_REC *server;		/* irssi server object for this peer */
+	int received_smp_init;		/* received SMP init msg */
+	int received_smp_reply;		/* received SMP reply msg */
+	int smp_failed;			/* SMP failed */
+	char better_msg_two[256];	/* what the second line of the "better"
+					   default query msg should like. Eat it
+					   up when it comes in */
+};
+
+extern int debug;
+
+/* init stuff */
+
+int otrlib_init();
+void otrlib_deinit();
+void otr_initops();
+
+/* basic send/receive/status stuff */
+
+char *otr_send(SERVER_REC *server,const char *msg,const char *to);
+char *otr_receive(SERVER_REC *server,const char *msg,const char *from);
+int otr_getstatus(char *mynick, char *nick, char *server);
+ConnContext *otr_getcontext(const char *accname,const char *nick,int create,void *data);
+
+/* user interaction */
+
+void otr_trust(SERVER_REC *server, char *nick);
+void otr_auth(SERVER_REC *server, char *nick, const char *secret);
+void otr_authabort(SERVER_REC *server, char *nick);
+
+
+/* key/fingerprint stuff */
+
+void keygen_run(const char *accname);
+void keygen_abort();
+void key_load();
+void fps_load();
+void otr_writefps();
+
+/* log stuff */
+
+#define LOGMAX 1024
+
+#define LVL_NOTICE  0
+#define LVL_DEBUG   1
+
+#define otr_logst(level,format,...) \
+	otr_log(NULL,NULL,level,format, ## __VA_ARGS__)
+
+#define otr_noticest(formatnum,...) \
+	printformat(NULL,NULL,MSGLEVEL_CRAP, formatnum, ## __VA_ARGS__)
+
+#define otr_notice(server,nick,formatnum,...) \
+	printformat(server,nick,MSGLEVEL_CRAP, formatnum, ## __VA_ARGS__)
+
+#define otr_debug(server,nick,formatnum,...) { \
+	if (debug) \
+		printformat(server,nick, \
+			    MSGLEVEL_CRAP, formatnum, ## __VA_ARGS__); \
+}
+
+void otr_log(SERVER_REC *server, const char *to, 
+	     int level, const char *format, ...);
diff --git a/otr_key.c b/otr_key.c
new file mode 100644
index 0000000..aa355f9
--- /dev/null
+++ b/otr_key.c
@@ -0,0 +1,224 @@
+/*
+ * Off-the-Record Messaging (OTR) module for the irssi IRC client
+ * Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
+ */
+
+#include "otr.h"
+
+#include <libgen.h>
+
+extern OtrlUserState otr_state;
+
+typedef enum { KEYGEN_NO, KEYGEN_RUNNING } keygen_status_t;
+
+struct {
+	keygen_status_t status;
+	char *accountname;
+	char *protocol;
+	time_t started;
+	GIOChannel *ch[2];
+	guint eid;
+} kg_st = {.status = KEYGEN_NO };
+
+/*
+ * Installed as g_io_watch and called when the key generation
+ * process finishs.
+ */
+gboolean keygen_complete(GIOChannel *source, GIOCondition condition, 
+			 gpointer data)
+{
+	gcry_error_t err;
+
+	read(g_io_channel_unix_get_fd(kg_st.ch[0]),&err,sizeof(err));
+
+	g_io_channel_shutdown(kg_st.ch[0],FALSE,NULL);
+	g_io_channel_shutdown(kg_st.ch[1],FALSE,NULL);
+	g_io_channel_unref(kg_st.ch[0]);
+	g_io_channel_unref(kg_st.ch[1]);
+
+	if (err)
+		otr_noticest(TXT_KG_FAILED,
+			     kg_st.accountname,
+			     gcry_strerror(err),
+			     gcry_strsource(err));
+	else {
+		/* reload keys */
+		otr_noticest(TXT_KG_COMPLETED,
+			     kg_st.accountname,
+			     time(NULL)-kg_st.started);
+		//otrl_privkey_forget_all(otr_state); <-- done by lib
+		key_load();
+	}
+
+	kg_st.status = KEYGEN_NO;
+	g_free(kg_st.accountname);
+
+	return FALSE;
+}
+
+/*
+ * Run key generation in a seperate process (takes ages).
+ * The other process will rewrite the key file, we shouldn't 
+ * change anything till it's done and we've reloaded the keys.
+ */
+void keygen_run(const char *accname)
+{
+	gcry_error_t err;
+	int ret;
+	int fds[2];
+	char *filename = g_strconcat(get_irssi_dir(),KEYFILE,NULL);
+	char *dir = dirname(g_strdup(filename));
+
+	if (kg_st.status!=KEYGEN_NO) {
+		if (strcmp(accname,kg_st.accountname)!=0)
+			otr_noticest(TXT_KG_ABORTED_DUP,
+				     accname,kg_st.accountname);
+		return;
+	}
+
+	if (!g_file_test(dir, G_FILE_TEST_EXISTS)) {
+		if (g_mkdir(dir,S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
+			otr_noticest(TXT_KG_ABORTED_DIR,
+				     accname,dir,strerror(errno));
+			g_free(dir);
+			g_free(filename);
+			return;
+		} else
+			otr_noticest(TXT_KG_MKDIR,dir);
+	}
+	g_free(dir);
+
+	if (pipe(fds) != 0) {
+		otr_noticest(TXT_KG_PIPE,
+			     accname,strerror(errno));
+		g_free(filename);
+		return;
+	}
+
+	kg_st.ch[0] = g_io_channel_unix_new(fds[0]);
+	kg_st.ch[1] = g_io_channel_unix_new(fds[1]);
+
+	kg_st.accountname = g_strdup(accname);
+	kg_st.protocol = PROTOCOLID;
+	kg_st.started = time(NULL);
+
+	if ((ret = fork())) {
+		g_free(filename);
+		if (ret==-1) {
+			otr_noticest(TXT_KG_FORK,
+				     accname,strerror(errno));
+			return;
+		}
+
+		kg_st.status = KEYGEN_RUNNING;
+		otr_noticest(TXT_KG_INITIATED,
+			     accname);
+
+		kg_st.eid = g_io_add_watch(kg_st.ch[0], G_IO_IN, 
+					   (GIOFunc) keygen_complete, NULL);
+		kg_st.started = time(NULL);
+		return;
+	}
+
+	/* child */
+
+	err = otrl_privkey_generate(otr_state,filename,accname,PROTOCOLID);
+	write(fds[1],&err,sizeof(err));
+
+	//g_free(filename);
+	_exit(0);
+}
+
+/*
+ * Abort ongoing key generation.
+ */
+void keygen_abort()
+{
+	if (kg_st.status==KEYGEN_RUNNING)
+		g_source_remove(kg_st.eid);
+}
+
+/* 
+ * Write fingerprints to file.
+ */
+void otr_writefps()
+{
+	gcry_error_t err;
+	char *filename = g_strconcat(get_irssi_dir(),FPSFILE,NULL);
+
+	err = otrl_privkey_write_fingerprints(otr_state,filename);
+
+	if (err == GPG_ERR_NO_ERROR) {
+		otr_noticest(TXT_FP_SAVED);
+	} else {
+		otr_noticest(TXT_FP_SAVE_ERROR,
+			     gcry_strerror(err),
+			     gcry_strsource(err));
+	}
+	g_free(filename);
+}
+
+/*
+ * Load private keys.
+ */
+void key_load()
+{
+	gcry_error_t err;
+	char *filename = g_strconcat(get_irssi_dir(),KEYFILE,NULL);
+
+	if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+		otr_noticest(TXT_KEY_NOT_FOUND);
+		return;
+	}
+
+	err =  otrl_privkey_read(otr_state, filename);
+
+	if (err == GPG_ERR_NO_ERROR) {
+		otr_noticest(TXT_KEY_LOADED);
+	} else {
+		otr_noticest(TXT_KEY_LOAD_ERROR,
+			     gcry_strerror(err),
+			     gcry_strsource(err));
+	}
+	g_free(filename);
+}
+
+/*
+ * Load fingerprints.
+ */
+void fps_load()
+{
+	gcry_error_t err;
+	char *filename = g_strconcat(get_irssi_dir(),FPSFILE,NULL);
+
+	if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+		otr_noticest(TXT_FP_NOT_FOUND);
+		return;
+	}
+
+	err =  otrl_privkey_read_fingerprints(otr_state,filename,NULL,NULL);
+
+	if (err == GPG_ERR_NO_ERROR) {
+		otr_noticest(TXT_FP_LOADED);
+	} else {
+		otr_noticest(TXT_FP_LOAD_ERROR,
+			     gcry_strerror(err),
+			     gcry_strsource(err));
+	}
+	g_free(filename);
+}
+
diff --git a/otr_ops.c b/otr_ops.c
new file mode 100644
index 0000000..bcc3ca1
--- /dev/null
+++ b/otr_ops.c
@@ -0,0 +1,203 @@
+/*
+ * Off-the-Record Messaging (OTR) module for the irssi IRC client
+ * Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
+ */
+
+#include "otr.h"
+
+OtrlMessageAppOps otr_ops;
+
+/*
+ * Policy is currently fixed as OTR lib default (meaning opportunistic).
+ */
+OtrlPolicy ops_policy(void *opdata, ConnContext *context)
+{
+	return OTRL_POLICY_DEFAULT;
+}
+
+/*
+ * Request for key generation.
+ * The lib actually expects us to be finished before the call returns.
+ * Since this can take more than an hour on some systems there isn't even
+ * a point in trying...
+ */
+void ops_create_privkey(void *opdata, const char *accountname,
+			const char *protocol)
+{
+	keygen_run(accountname);
+}
+
+/*
+ * Inject OTR message.
+ * Deriving the server is currently a hack,
+ * need to derive the server from accountname.
+ */
+void ops_inject_msg(void *opdata, const char *accountname,
+		    const char *protocol, const char *recipient, const char *message)
+{
+	SERVER_REC *a_serv;
+	char *msgcopy = g_strdup(message);
+
+	/* OTR sometimes gives us multiple lines 
+	 * (e.g. the default query (a.k.a. "better") message) */
+	g_strdelimit (msgcopy,"\n",' ');
+	a_serv = active_win->active_server; 
+	a_serv->send_message(a_serv, recipient, msgcopy,
+			     GPOINTER_TO_INT(SEND_TARGET_NICK));
+	g_free(msgcopy);
+}
+
+/*
+ * OTR notification. Haven't seen one yet.
+ */
+void ops_notify(void *opdata, OtrlNotifyLevel level, const char *accountname, 
+		const char *protocol, const char *username, 
+		const char *title, const char *primary, 
+		const char *secondary)
+{
+	ConnContext *co = otr_getcontext(accountname,username,FALSE,NULL);
+	SERVER_REC *server = active_win->active_server;
+	struct co_info *coi;
+	if (co) {
+		coi = co->app_data;
+		server = coi->server;
+	} else 
+		otr_notice(server,username,TXT_OPS_NOTIFY_BUG);
+
+	otr_notice(server,username,TXT_OPS_NOTIFY,
+		   title,primary,secondary);
+}
+
+/*
+ * OTR message. E.g. "following has been transmitted in clear: ...".
+ * We're trying to kill the ugly HTML.
+ */
+int ops_display_msg(void *opdata, const char *accountname, 
+		    const char *protocol, const char *username, 
+		    const char *msg)
+{
+	ConnContext *co = otr_getcontext(accountname,username,FALSE,NULL);
+	SERVER_REC *server = active_win->active_server;
+	struct co_info *coi;
+	/* This is kind of messy. */
+	GRegex *regex_bold  = g_regex_new("</?i([ /][^>]*)?>",0,0,NULL);
+	GRegex *regex_del   = g_regex_new("</?b([ /][^>]*)?>",0,0,NULL);
+	gchar *msgnohtml = 
+		g_regex_replace_literal(regex_del,msg,-1,0,"",0,NULL);
+	msg = g_regex_replace_literal(regex_bold,msgnohtml,-1,0,"%9",0,NULL);
+
+	if (co) {
+		coi = co->app_data;
+		server = coi->server;
+	} else 
+		otr_notice(server,username,TXT_OPS_DISPLAY_BUG);
+
+	otr_notice(server,username,TXT_OPS_DISPLAY,msg);
+
+	g_free(msgnohtml);
+	g_free((char*)msg);
+	g_regex_unref(regex_del);
+	g_regex_unref(regex_bold);
+	return 0;
+}
+
+/* 
+ * Gone secure.
+ */
+void ops_secure(void *opdata, ConnContext *context)
+{
+	struct co_info *coi = context->app_data;
+	otr_notice(coi->server,
+		   context->username,TXT_OPS_SEC);
+}
+
+/*
+ * Gone insecure.
+ */
+void ops_insecure(void *opdata, ConnContext *context)
+{
+	struct co_info *coi = context->app_data;
+	otr_notice(coi->server,
+		   context->username,TXT_OPS_INSEC);
+}
+
+/*
+ * Still secure? Need to find out what that means...
+ */
+void ops_still_secure(void *opdata, ConnContext *context, int is_reply)
+{
+	struct co_info *coi = context->app_data;
+	otr_notice(coi->server,
+		   context->username,is_reply ?
+		   TXT_OPS_STILL_REPLY :
+		   TXT_OPS_STILL_NO_REPLY);
+}
+
+/*
+ * OTR log message. IIRC heartbeats are of this category.
+ */
+void ops_log(void *opdata, const char *message)
+{
+	otr_noticest(TXT_OPS_LOG,message);
+}
+
+/*
+ * Really critical with IRC. 
+ * Unfortunately, we can't tell our peer which size to use.
+ * (reminds me of MTU determination...)
+ */
+int ops_max_msg(void *opdata, ConnContext *context)
+{
+	return OTR_MAX_MSG_SIZE;
+}
+
+/*
+ * A context changed. 
+ * I believe this is not happening for the SMP expects.
+ */
+void ops_up_ctx_list(void *opdata)
+{
+	statusbar_items_redraw("otr");
+}
+
+/*
+ * Save fingerprint changes.
+ */
+void ops_writefps(void *data)
+{
+	otr_writefps();
+}
+
+/*
+ * Initialize our OtrlMessageAppOps
+ */
+void otr_initops() {
+	memset(&otr_ops,0,sizeof(otr_ops));
+
+	otr_ops.policy = ops_policy;
+	otr_ops.create_privkey = ops_create_privkey;
+	otr_ops.inject_message = ops_inject_msg;
+	otr_ops.notify = ops_notify;
+	otr_ops.display_otr_message = ops_display_msg;
+	otr_ops.gone_secure = ops_secure;
+	otr_ops.gone_insecure = ops_insecure;
+	otr_ops.still_secure = ops_still_secure;
+	otr_ops.log_message = ops_log;
+	otr_ops.max_message_size = ops_max_msg;
+	otr_ops.update_context_list = ops_up_ctx_list;
+	otr_ops.write_fingerprints = ops_writefps;
+}
diff --git a/otrutil.c b/otrutil.c
index d97ed4a..2b9679f 100644
--- a/otrutil.c
+++ b/otrutil.c
@@ -1,268 +1,35 @@
 /*
-	Off-the-Record Messaging (OTR) module for the irssi IRC client
-	Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program 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 General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-*/
+ * Off-the-Record Messaging (OTR) module for the irssi IRC client
+ * Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
+ */
 
 #include "otr.h"
 
-#include <libgen.h>
 #include <gcrypt.h>
 
-static OtrlUserState otr_state = NULL;
-static OtrlMessageAppOps otr_ops;
+OtrlUserState otr_state = NULL;
+extern OtrlMessageAppOps otr_ops;
 static int otrinited = FALSE;
 
-/* Key generation stuff */
-
-typedef enum { KEYGEN_NO, KEYGEN_RUNNING } keygen_status_t;
-
-struct {
-	keygen_status_t status;
-	char *accountname;
-	char *protocol;
-	time_t started;
-	GIOChannel *ch[2];
-	guint eid;
-} kg_st = {.status = KEYGEN_NO };
-
-#define KEYGENMSG "Key generation for %s: "
-
-/*
- * Installed as g_io_watch and called when the key generation
- * process finishs.
- */
-gboolean keygen_complete(GIOChannel *source, GIOCondition condition, gpointer data) {
-	gcry_error_t err;
-
-	read(g_io_channel_unix_get_fd(kg_st.ch[0]),&err,sizeof(err));
-
-	g_io_channel_shutdown(kg_st.ch[0],FALSE,NULL);
-	g_io_channel_shutdown(kg_st.ch[1],FALSE,NULL);
-	g_io_channel_unref(kg_st.ch[0]);
-	g_io_channel_unref(kg_st.ch[1]);
-
-	if (err)
-		otr_logst(LVL_NOTICE,KEYGENMSG "failed: %s (%s)",
-			kg_st.accountname,
-			gcry_strerror(err),
-			gcry_strsource(err));
-	else {
-		/* reload keys */
-		otr_logst(LVL_NOTICE,KEYGENMSG "completed in %d seconds. Reloading keys",
-			kg_st.accountname,
-			time(NULL)-kg_st.started);
-		//otrl_privkey_forget_all(otr_state); <-- done by lib
-		key_load();
-	}
-
-	kg_st.status = KEYGEN_NO;
-	g_free(kg_st.accountname);
-
-	return FALSE;
-}
-
-/*
- * Run key generation in a seperate process (takes ages).
- * The other process will rewrite the key file, we shouldn't 
- * change anything till it's done and we've reloaded the keys.
- */
-void keygen_run(const char *accname) {
-	gcry_error_t err;
-	int ret;
-	int fds[2];
-	char *filename = g_strconcat(get_irssi_dir(),KEYFILE,NULL);
-	char *dir = dirname(g_strdup(filename));
-
-	if (kg_st.status!=KEYGEN_NO) {
-		if (strcmp(accname,kg_st.accountname)!=0)
-			otr_logst(LVL_NOTICE,KEYGENMSG 
-				"aborted. Key generation for %s"
-				"still in progress",
-				accname,kg_st.accountname);
-		return;
-	}
-
-	if (!g_file_test(dir, G_FILE_TEST_EXISTS)) {
-		if (g_mkdir(dir,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
-			otr_logst(LVL_NOTICE,KEYGENMSG "aborted, failed creating directory %s: %s",
-				accname,dir,strerror(errno));
-			g_free(dir);
-			g_free(filename);
-			return;
-		} else
-			otr_logst(LVL_NOTICE,KEYGENMSG "created directory %s\n",dir);
-	}
-	g_free(dir);
-
-	if (pipe(fds) != 0) {
-		otr_logst(LVL_NOTICE,KEYGENMSG "error creating pipe: %s",accname,strerror(errno));
-		g_free(filename);
-		return;
-	}
-
-	kg_st.ch[0] = g_io_channel_unix_new(fds[0]);
-	kg_st.ch[1] = g_io_channel_unix_new(fds[1]);
-
-	kg_st.accountname = g_strdup(accname);
-	kg_st.protocol = PROTOCOLID;
-	kg_st.started = time(NULL);
-
-	if ((ret = fork())) {
-		g_free(filename);
-		if (ret==-1) {
-			otr_logst(LVL_NOTICE,KEYGENMSG "fork() error: %s",accname,strerror(errno));
-			return;
-		}
-
-		kg_st.status = KEYGEN_RUNNING;
-		otr_logst(LVL_NOTICE,KEYGENMSG "initiated. This might take several minutes.",accname);
-
-		kg_st.eid = g_io_add_watch(kg_st.ch[0], G_IO_IN, (GIOFunc) keygen_complete, NULL);
-		kg_st.started = time(NULL);
-		return;
-	}
-	
-	/* child */
-
-	err = otrl_privkey_generate(otr_state,filename,accname,PROTOCOLID);
-	write(fds[1],&err,sizeof(err));
-
-	//g_free(filename);
-        _exit(0);
-}
-
-void otr_writefps() {
-	gcry_error_t err;
-	char *filename = g_strconcat(get_irssi_dir(),FPSFILE,NULL);
-
-	err = otrl_privkey_write_fingerprints(otr_state,filename);
-
-	if (err == GPG_ERR_NO_ERROR) {
-	    otr_logst(LVL_NOTICE,"fingerprints saved");
-	} else {
-	    otr_logst(LVL_NOTICE,"Error saving fingerprints: %s (%s)",
-		    gcry_strerror(err),
-		    gcry_strsource(err));
-	}
-	g_free(filename);
-}
-
-/* Callbacks from the OTR lib */
-
-OtrlPolicy ops_policy(void *opdata, ConnContext *context) {
-	/* meaning opportunistic */
-	return OTRL_POLICY_DEFAULT;
-}
-
-void ops_create_privkey(void *opdata, const char *accountname,
-	const char *protocol) {
-	keygen_run(accountname);
-}
-
-/*
- * Inject OTR message.
- * Deriving the server is currently a hack,
- * need to derive the server from accountname.
- */
-void ops_inject_msg(void *opdata, const char *accountname,
-	    const char *protocol, const char *recipient, const char *message) {
-	SERVER_REC *a_serv;
-	char *msgcopy = g_strdup(message);
-
-	/* OTR sometimes gives us multiple lines (e.g. the init message) */
-	g_strdelimit (msgcopy,"\n",' ');
-	a_serv = active_win->active_server; 
-	a_serv->send_message(a_serv, recipient, msgcopy,
-		GPOINTER_TO_INT(SEND_TARGET_NICK));
-	g_free(msgcopy);
-}
-
-/*
- * OTR notification. Haven't seen one yet.
- */
-void ops_notify(void *opdata, OtrlNotifyLevel level, const char *accountname, 
-		const char *protocol, const char *username, 
-		const char *title, const char *primary, 
-		const char *secondary) {
-	otr_log(active_win->active_server,accountname,username,LVL_NOTICE,
-		"title: %s prim: %s sec: %s",title,primary,secondary);
-}
-
-/*
- * OTR message. E.g. "following has been transmitted in clear: ...".
- * We're trying to kill the ugly HTML.
- */
-int ops_display_msg(void *opdata, const char *accountname, 
-		    const char *protocol, const char *username, 
-		    const char *msg) {
-	/* This is kind of messy. */
-	GRegex *regex_bold  = g_regex_new("</?i([ /][^>]*)?>",0,0,NULL);
-	GRegex *regex_del   = g_regex_new("</?b([ /][^>]*)?>",0,0,NULL);
-	gchar *msgnohtml = g_regex_replace_literal(regex_del,msg,-1,0,"",0,NULL);
-	msg = g_regex_replace_literal(regex_bold,msgnohtml,-1,0,"%9",0,NULL);
-
-	otr_log(active_win->active_server,accountname,username,LVL_NOTICE,
-		"msg: %s",msg);
-
-	g_free(msgnohtml);
-	g_free((char*)msg);
-	g_regex_unref(regex_del);
-	g_regex_unref(regex_bold);
-	return 0;
-}
-
-void ops_secure(void *opdata, ConnContext *context) {
-	otr_log(active_win->active_server,context->accountname,
-		context->username,LVL_NOTICE,"gone %s","%9secure%9");
-}
-
-void ops_insecure(void *opdata, ConnContext *context) {
-	otr_log(active_win->active_server,context->accountname,
-	context->username,LVL_NOTICE,"gone %s","%9insecure%9");
-}
-
-void ops_still_secure(void *opdata, ConnContext *context, int is_reply) {
-	otr_log(active_win->active_server,context->accountname,
-		context->username,LVL_NOTICE,
-		"still %s (%s reply)", 
-		"%9secure%9",
-		is_reply ? "is" : "is not");
-}
-
-void ops_log(void *opdata, const char *message) {
-	otr_logst(LVL_NOTICE,"log msg: %s",message);
-}
-
-int ops_max_msg(void *opdata, ConnContext *context) {
-	return OTR_MAX_MSG_SIZE;
-}
-
-void ops_up_ctx_list(void *opdata) {
-	statusbar_items_redraw("otr");
-}
-
-void ops_writefps(void *data) {
-	otr_writefps();
-}
-
 /*
  * init otr lib.
  */
-int otrlib_init() {
+int otrlib_init()
+{
 
 	if (!otrinited) {
 		OTRL_INIT;
@@ -276,95 +43,75 @@ int otrlib_init() {
 	key_load();
 	fps_load();
 
-	//otrl_privkey_generate(otr_state,"/tmp/somekey","jesus at somewhere.com","proto");
-
-	/* set otr ops */
-	memset(&otr_ops,0,sizeof(otr_ops));
-
-	otr_ops.policy = ops_policy;
-	otr_ops.create_privkey = ops_create_privkey;
-	otr_ops.inject_message = ops_inject_msg;
-	otr_ops.notify = ops_notify;
-	otr_ops.display_otr_message = ops_display_msg;
-	otr_ops.gone_secure = ops_secure;
-	otr_ops.gone_insecure = ops_insecure;
-	otr_ops.still_secure = ops_still_secure;
-	otr_ops.log_message = ops_log;
-	otr_ops.max_message_size = ops_max_msg;
-	otr_ops.update_context_list = ops_up_ctx_list;
-	otr_ops.write_fingerprints = ops_writefps;
+	otr_initops();
+
 	return otr_state==NULL;
 }
 
-void otrlib_deinit() {
+/*
+ * deinit otr lib.
+ */
+void otrlib_deinit()
+{
 	if (otr_state) {
 		otr_writefps();
 		otrl_userstate_free(otr_state);
 		otr_state = NULL;
 	}
-	if (kg_st.status==KEYGEN_RUNNING)
-		g_source_remove(kg_st.eid);
+
+	keygen_abort();
 }
 
 
 /*
- * load private keys.
+ * Free our app data.
  */
-void key_load() {
-	gcry_error_t err;
-	char *filename = g_strconcat(get_irssi_dir(),KEYFILE,NULL);
-
-	if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
-		otr_logst(LVL_NOTICE,"no private keys found");
-		return;
-	}
-
-	err =  otrl_privkey_read(otr_state, filename);
-
-	if (err == GPG_ERR_NO_ERROR) {
-	    otr_logst(LVL_NOTICE,"private keys loaded");
-	} else {
-	    otr_logst(LVL_NOTICE,"Error loading private keys: %s (%s)",
-		    gcry_strerror(err),
-		    gcry_strsource(err));
+void context_free_app_info(void *data)
+{
+	struct co_info *coi = data;
+	if (coi->msgqueue) {
+		g_free(coi->msgqueue);
 	}
-	g_free(filename);
 }
 
 /*
- * load fingerprints.
+ * Add app data to context.
+ * See struct co_info for details.
  */
-void fps_load() {
-	gcry_error_t err;
-	char *filename = g_strconcat(get_irssi_dir(),FPSFILE,NULL);
-
-	if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
-		otr_logst(LVL_NOTICE,"no fingerprints found");
-		return;
-	}
+void context_add_app_info(void *data,ConnContext *co)
+{
+	SERVER_REC *server = data;
+	struct co_info *coi = g_malloc(sizeof(struct co_info));
 
-	err =  otrl_privkey_read_fingerprints(otr_state,filename,NULL,NULL);
+	memset(coi,0,sizeof(struct co_info));
+	co->app_data = coi;
+	co->app_data_free = context_free_app_info;
 
-	if (err == GPG_ERR_NO_ERROR) {
-	    otr_logst(LVL_NOTICE,"fingerprints loaded");
-	} else {
-	    otr_logst(LVL_NOTICE,"Error loading fingerprints: %s (%s)",
-		    gcry_strerror(err),
-		    gcry_strsource(err));
-	}
-	g_free(filename);
+	coi->server = server;
+	sprintf(coi->better_msg_two,formats[TXT_OTR_BETTER_TWO].def,co->accountname);
 }
 
-ConnContext *otr_getcontext(const char *accname,const char *nick,int create) {
-	return otrl_context_find(
+/*
+ * Get a context from a pair.
+ */
+ConnContext *otr_getcontext(const char *accname,const char *nick,
+			    int create,void *data)
+{
+	ConnContext *co = otrl_context_find(
 		otr_state,
 		nick,
 		accname,
 		PROTOCOLID,
 		create,
 		NULL,
-		NULL,
-		NULL);
+		context_add_app_info,
+		data);
+
+	/* context came from a fingerprint */
+	if (co&&data&&!co->app_data)
+		context_add_app_info(data,co);
+
+	return co;
 }
 
 /*
@@ -393,11 +140,11 @@ char *otr_send(SERVER_REC *server, const char *msg,const char *to)
 		msg, 
 		NULL, 
 		&newmessage, 
-		NULL, 
-		NULL);
+		context_add_app_info, 
+		server);
 
 	if (err != 0) {
-		otr_logst(LVL_NOTICE,"send failed: acc=%s to=%s msg=%s",accname,to,msg);
+		otr_notice(server,to,TXT_SEND_FAILED,msg);
 		return NULL;
 	}
 
@@ -406,8 +153,8 @@ char *otr_send(SERVER_REC *server, const char *msg,const char *to)
 
 	/* OTR message. Need to do fragmentation */
 
-	if (!(co = otr_getcontext(accname,to,FALSE))) {
-		otr_logst(LVL_NOTICE,"couldn't find context: acc=%s to=%s",accname,to);
+	if (!(co = otr_getcontext(accname,to,FALSE,server))) {
+		otr_notice(server,to,TXT_SEND_CHANGE);
 		return NULL;
 	}
 
@@ -420,52 +167,176 @@ char *otr_send(SERVER_REC *server, const char *msg,const char *to)
 		NULL);
 
 	if (err != 0) {
-		otr_logst(LVL_NOTICE,"failed to fragment message: msg=%s",msg);
+		otr_notice(server,to,TXT_SEND_FRAGMENT,msg);
 	} else
-		otr_log(server,accname,to,LVL_DEBUG,"OTR converted sent message to %s",newmessage);
+		otr_debug(server,to,TXT_SEND_CONVERTED,newmessage);
 
 	return NULL;
 }
 
-char *otr_getstatus(char *mynick, char *nick, char *server) {
+/*
+ * Get the OTR status of this conversation.
+ * This wouldn't be half as long if the SMP state machine would work better.
+ */
+int otr_getstatus(char *mynick, char *nick, char *server)
+{
 	ConnContext *co;
 	char accname[128];
+	struct co_info *coi;
 
 	sprintf(accname, "%s@%s", mynick, server);
 
-	if (!(co = otr_getcontext(accname,nick,FALSE))) {
-		//otr_logst(LVL_NOTICE,"couldn't find context: acc=%s to=%s",accname,nick);
-		return NULL;
+	if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
+		return 0;
 	}
 
+	coi = co->app_data;
+
 	switch (co->msgstate) {
-		case OTRL_MSGSTATE_PLAINTEXT:
-			return "plaintext";
-		case OTRL_MSGSTATE_ENCRYPTED:
-		{
-			char *trust = co->active_fingerprint->trust;
-			return trust&&*trust!='\0' ? trust : "encrypted";
-		}
-		case OTRL_MSGSTATE_FINISHED:
-			return "finished";
+	case OTRL_MSGSTATE_PLAINTEXT:
+		return TXT_ST_PLAINTEXT;
+	case OTRL_MSGSTATE_ENCRYPTED: {
+		char *trust = co->active_fingerprint->trust;
+		int ex = co->smstate->nextExpected;
+
+		if (trust&&(*trust!='\0'))
+			return strcmp(trust,"smp")==0 ? TXT_ST_TRUST_SMP : TXT_ST_TRUST_MANUAL;
+
+		switch (ex) {
+		case OTRL_SMP_EXPECT1:
+			return TXT_ST_UNTRUSTED;
+		case OTRL_SMP_EXPECT2:
+			if (!coi->received_smp_reply)
+				return TXT_ST_SMP_WAIT_2;
+			else
+				return TXT_ST_SMP_HAVE_2;
+		case OTRL_SMP_EXPECT3: 
+			/* unfortunately, this also covers the case 
+			 * where authentication failed */
+			return coi->smp_failed ? 
+				TXT_ST_SMP_FAILED : TXT_ST_SMP_FINALIZE;
+		case OTRL_SMP_EXPECT4: /* unreachable with libotr 3.1 */
+			return TXT_ST_SMP_FINALIZE;
 		default:
-			return "unknown(BUG)";
+			return TXT_ST_SMP_UNKNOWN;
+		}
+	}
+	case OTRL_MSGSTATE_FINISHED:
+		return TXT_ST_FINISHED;
+	default:
+		return TXT_ST_UNKNOWN;
 	}
 }
 
-void otr_trust(char *mynick, char *nick, char *server) {
+/*
+ * Trust our peer.
+ */
+void otr_trust(SERVER_REC *server, char *nick)
+{
 	ConnContext *co;
 	char accname[128];
 
-	sprintf(accname, "%s@%s", mynick, server);
+	sprintf(accname, "%s@%s", server->nick, server->connrec->address);
 
-	if (!(co = otr_getcontext(accname,nick,FALSE))) {
-		otr_logst(LVL_NOTICE,"couldn't find context: acc=%s nick=%s",accname,nick);
+	if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
+		otr_noticest(TXT_CTX_NOT_FOUND,
+			     accname,nick);
 		return;
 	}
 
-	otrl_context_set_trust(co->active_fingerprint,"trusted");
-	otr_logst(LVL_NOTICE,"trusting fingerprint from %s",accname);
+	otrl_context_set_trust(co->active_fingerprint,"manual");
+
+	otr_notice(server,nick,TXT_FP_TRUST,accname);
+}
+
+/*
+ * Abort any ongoing SMP authentication.
+ */
+void otr_abort_auth(ConnContext *co, SERVER_REC *server, const char *nick)
+{
+	struct co_info *coi;
+
+	coi = co->app_data;
+
+	coi->received_smp_reply = FALSE;
+	coi->received_smp_init = FALSE;
+	coi->smp_failed = FALSE;
+
+	otrl_message_abort_smp(otr_state,&otr_ops,NULL,co);
+
+	otr_notice(server,nick,
+		   co->smstate->nextExpected!=OTRL_SMP_EXPECT1 ? 
+		   TXT_AUTH_ABORTED_ONGOING :
+		   TXT_AUTH_ABORTED);
+}
+
+/*
+ * implements /otr authabort
+ */
+void otr_authabort(SERVER_REC *server, char *nick)
+{
+	ConnContext *co;
+	char accname[128];
+
+	sprintf(accname, "%s@%s", server->nick, server->connrec->address);
+
+	if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
+		otr_noticest(TXT_CTX_NOT_FOUND,
+			     accname,nick);
+		return;
+	}
+
+	otr_abort_auth(co,server,nick);
+}
+
+/*
+ * Initiate or respond to SMP authentication.
+ */
+void otr_auth(SERVER_REC *server, char *nick, const char *secret)
+{
+	ConnContext *co;
+	char accname[128];
+	struct co_info *coi;
+
+	sprintf(accname, "%s@%s", server->nick, server->connrec->address);
+
+	if (!(co = otr_getcontext(accname,nick,FALSE,NULL))) {
+		otr_noticest(TXT_CTX_NOT_FOUND,
+			     accname,nick);
+		return;
+	}
+
+	coi = co->app_data;
+
+	/* Aborting an ongoing auth */
+	if (co->smstate->nextExpected!=OTRL_SMP_EXPECT1)
+		otr_abort_auth(co,server,nick);
+
+	/* reset trust level */
+	otrl_context_set_trust(co->active_fingerprint, "");
+	otr_writefps();
+
+	if (!coi->received_smp_init)
+		otrl_message_initiate_smp(
+			otr_state, 
+			&otr_ops,
+			NULL,
+			co,
+			(unsigned char*)secret,
+			strlen(secret));
+	else
+		otrl_message_respond_smp(
+			otr_state,
+			&otr_ops,
+			NULL,
+			co,
+			(unsigned char*)secret,
+			strlen(secret));
+
+	otr_notice(server,nick,coi->received_smp_init ? 
+		   TXT_AUTH_RESPONDING : 
+		   TXT_AUTH_INITIATED);
+	statusbar_items_redraw("otr");
 }
 
 /*
@@ -477,37 +348,61 @@ char *otr_receive(SERVER_REC *server, const char *msg,const char *from)
 {
 	int ignore_message;
 	char *newmessage = NULL;
-	const char *nick = server->nick;
-	const char *address = server->connrec->address;
 	char accname[256];
 	char *lastmsg;
 	ConnContext *co;
+	struct co_info *coi;
+	OtrlTLV *tlvs;
 
-	sprintf(accname, "%s@%s", nick, address);
+	sprintf(accname, "%s@%s", server->nick, server->connrec->address);
 
-	if (!(co = otr_getcontext(accname,from,TRUE))) {
-		otr_logst(LVL_NOTICE,"couldn't create/find context: acc=%s from=%s",accname,from);
+	if (!(co = otr_getcontext(accname,from,TRUE,server))) {
+		otr_noticest(TXT_CTX_NOT_CREATE,
+			     accname,from);
+		return NULL;
+	}
+
+	coi = co->app_data;
+
+	/* Really lame but I don't see how you could do this in a generic
+	 * way unless the IRC server would somehow marks continuation messages.
+	 */
+	if ((strcmp(msg,coi->better_msg_two)==0)||
+	    (strcmp(msg,formats[TXT_OTR_BETTER_THREE].def)==0)) {
+		otr_debug(server,from,TXT_RECEIVE_IGNORE_QUERY);
 		return NULL;
 	}
 
 	/* The server might have split lines that were too long 
 	 * (bitlbee does that). The heuristic is simple: If we can find ?OTR:
 	 * in the message but it doesn't end with a ".", queue it and wait
-	 * for the rest. This works if there are only two fragments which
-	 * (fortunately) seems to be the maximum.
+	 * for the rest.
 	 */
 	lastmsg = co->app_data;
 
-	if (lastmsg) {
-		strcpy(lastmsg+strlen(lastmsg),msg);
-		otr_log(server,accname,from,LVL_DEBUG,"dequeued");
-		msg = lastmsg;
-		co->app_data = NULL;
-	} else if (strstr(msg,"?OTR:")&&(strlen(msg)>OTR_MAX_MSG_SIZE)&&msg[strlen(msg)-1]!='.') {
-		co->app_data = malloc(1024*sizeof(char));
-		strcpy(co->app_data,msg);
-		co->app_data_free = g_free;
-		otr_log(server,accname,from,LVL_DEBUG,"queued");
+	if (coi->msgqueue) { /* already something in the queue */
+		strcpy(coi->msgqueue+strlen(coi->msgqueue),msg);
+
+		/* wait for more? */
+		if ((strlen(msg)>OTR_MAX_MSG_SIZE)&&msg[strlen(msg)-1]!='.')
+			return NULL;
+
+		otr_debug(server,from,TXT_RECEIVE_DEQUEUED,
+			  strlen(coi->msgqueue));
+
+		msg = coi->msgqueue;
+		coi->msgqueue = NULL;
+
+		/* this is freed thru our caller by otrl_message_free.
+		 * Currently ok since that just uses free().
+		 */
+
+	} else if (strstr(msg,"?OTR:")&&
+		   (strlen(msg)>OTR_MAX_MSG_SIZE)&&
+		   msg[strlen(msg)-1]!='.') {
+		coi->msgqueue = malloc(4096*sizeof(char));
+		strcpy(coi->msgqueue,msg);
+		otr_debug(server,from,TXT_RECEIVE_QUEUED,strlen(msg));
 		return NULL;
 	}
 
@@ -520,17 +415,75 @@ char *otr_receive(SERVER_REC *server, const char *msg,const char *from)
 		from, 
 		msg, 
 		&newmessage,
-		NULL,
+		&tlvs,
 		NULL,
 		NULL);
 
+	if (tlvs) {
+		OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
+		int abort = FALSE;
+		if (tlv) {
+			if (co->smstate->nextExpected != OTRL_SMP_EXPECT1) {
+				otr_notice(server,from,TXT_AUTH_HAVE_OLD,
+					   accname);
+				abort = TRUE;
+			} else {
+				otr_notice(server,from,TXT_AUTH_PEER,
+					   accname);
+				coi->received_smp_init = TRUE;
+			}
+		} else
+			coi->received_smp_init = FALSE;
+		tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
+		if (tlv) {
+			if (co->smstate->nextExpected != OTRL_SMP_EXPECT2) {
+				otr_notice(server,from,
+					   TXT_AUTH_PEER_REPLY_WRONG,
+					   accname);
+				abort = TRUE;
+			} else {
+				otr_notice(server,from,
+					   TXT_AUTH_PEER_REPLIED,
+					   accname);
+				coi->received_smp_reply = TRUE;
+			}
+		} else
+			coi->received_smp_reply = FALSE;
+		tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
+		if (tlv) {
+			if (co->smstate->nextExpected != OTRL_SMP_EXPECT3) {
+				otr_notice(server,from,TXT_AUTH_PEER_WRONG_SMP3,accname);
+				abort = TRUE;
+			} else {
+				char *trust = co->active_fingerprint->trust;
+				if (trust&&(*trust!='\0'))
+					otr_notice(server,from,
+						   TXT_AUTH_SUCCESSFUL,
+						   accname);
+				else {
+					otr_notice(server,from,
+						   TXT_AUTH_FAILED,
+						   accname);
+					coi->smp_failed = TRUE;
+				}
+			}
+		} else
+			coi->smp_failed = FALSE;
+
+		if (abort)
+			otr_abort_auth(co,server,from);
+
+		statusbar_items_redraw("otr");
+	}
+
 	if (ignore_message) {
-		otr_log(server,accname,from,LVL_DEBUG,"ignoring protocol message of length %zd, acc=%s, from=%s", strlen(msg),accname,from);
+		otr_debug(server,from,
+			  TXT_RECEIVE_IGNORE, strlen(msg),accname,from);
 		return NULL;
 	}
 
 	if (newmessage)
-		otr_log(server,accname,from,LVL_DEBUG,"OTR converted received message");
+		otr_notice(server,from,TXT_RECEIVE_CONVERTED);
 
 	return newmessage ? : (char*)msg;
 }
diff --git a/otrutil.h b/otrutil.h
deleted file mode 100644
index 42afb99..0000000
--- a/otrutil.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-	Off-the-Record Messaging (OTR) module for the irssi IRC client
-	Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program 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 General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-*/
-
-
-/* 
- * maybe this should be configurable?
- * I believe bitlbee has something >500.
- */
-#define OTR_MAX_MSG_SIZE 400
-
-/* otr protocol id */
-#define PROTOCOLID "IRC"
-
-#define KEYFILE "/otr/otr.key"
-#define FPSFILE "/otr/otr.fp"
-
-int otrlib_init();
-void otrlib_deinit();
-void key_load();
-void fps_load();
-char *otr_send(SERVER_REC *server,const char *msg,const char *to);
-char *otr_receive(SERVER_REC *server,const char *msg,const char *from);
-void keygen_run(const char *accname);
-char *otr_getstatus(char *mynick, char *nick, char *server);
-void otr_trust(char *mynick, char *nick, char *server);
diff --git a/ui.c b/ui.c
index aa9d389..7a3e78f 100644
--- a/ui.c
+++ b/ui.c
@@ -1,40 +1,39 @@
 /*
-	Off-the-Record Messaging (OTR) module for the irssi IRC client
-	Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program 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 General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-*/
+ * Off-the-Record Messaging (OTR) module for the irssi IRC client
+ * Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA
+ */
 
 #include "otr.h"
 
 char *lvlstring[] = { 
-    "NOTICE",
-    "DEBUG"
+	"NOTICE",
+	"DEBUG"
 };
 
-extern int debug;
 
-void otr_log(SERVER_REC *server, const char *accname, const char *nick, 
-		int level, const char *format, ...) {
-        va_list params;
-        va_start( params, format );
-        char msg[LOGMAX], *s = msg;
+void otr_log(SERVER_REC *server, const char *nick, 
+	     int level, const char *format, ...) {
+	va_list params;
+	va_start( params, format );
+	char msg[LOGMAX], *s = msg;
 
 	if ((level==LVL_DEBUG)&&!debug)
 		return;
-	
+
 	s += sprintf(s,"%s","%9OTR%9");
 
 	if (level!=LVL_NOTICE)	
@@ -42,9 +41,9 @@ void otr_log(SERVER_REC *server, const char *accname, const char *nick,
 
 	s += sprintf(s,": ");
 
-        if( vsnprintf( s, LOGMAX, format, params ) < 0 )
-                sprintf( s, "internal error parsing error string (BUG)" );
-        va_end( params );
+	if( vsnprintf( s, LOGMAX, format, params ) < 0 )
+		sprintf( s, "internal error parsing error string (BUG)" );
+	va_end( params );
 
 	printtext(server, nick, MSGLEVEL_CRAP, msg);
 }
diff --git a/ui.h b/ui.h
deleted file mode 100644
index 09cd037..0000000
--- a/ui.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-	Off-the-Record Messaging (OTR) module for the irssi IRC client
-	Copyright (C) 2008  Uli Meis <a.sporto+bee at gmail.com>
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program 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 General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-*/
-
-#define LOGMAX 1024
-
-#define LVL_NOTICE  0
-#define LVL_DEBUG   1
-
-#define otr_logst(level,format,...) otr_log(NULL,NULL,NULL,level,format, \
-					    ## __VA_ARGS__)
-
-void otr_log(SERVER_REC *server, const char *accname, const char *to, 
-		int level, const char *format, ...);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/irssi-plugin-otr.git



More information about the Pkg-privacy-commits mailing list