[Pkg-privacy-commits] [libotr] 59/225: 2009-04-28:

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 12:44:54 UTC 2015


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

infinity0 pushed a commit to branch master
in repository libotr.

commit f6a3018ff353e65e345f3135efbe3dbe0be87e75
Author: cypherpunk <cypherpunk>
Date:   Tue Apr 28 13:32:12 2009 +0000

    2009-04-28:
    
    	* src/auth.c: pubkey_type should be shifted by 8, not 16.  It
    	doesn't matter right now, because it's always 0, but still.
    	(Thanks to Can Tang.)
    
    2008-08-15:
    
    	* src/Makefile.am:
    	* src/context.c:
    	* src/context.h:
    	* src/context_priv.c:
    	* src/context_priv.h:
    	* src/message.c:
    	* src/message.h:
    	* src/proto.c:
    	* src/proto.h: Willy Lew's updates of the libotr API
    
    2008-08-06:
    
    	* src/proto.c: gcc 4.2 with -O2 assumes that integer overflow
---
 AUTHORS            |   3 +-
 ChangeLog          |  18 ++
 README             |   3 +-
 src/Makefile.am    |   5 +-
 src/auth.c         |  11 +-
 src/auth.h         |   3 +-
 src/b64.c          |   3 +-
 src/b64.h          |   3 +-
 src/context.c      |  77 +----
 src/context.h      |  58 +---
 src/context_priv.c |  94 ++++++
 src/context_priv.h |  91 ++++++
 src/dh.c           |   3 +-
 src/dh.h           |   3 +-
 src/mem.c          |   3 +-
 src/mem.h          |   3 +-
 src/message.c      | 848 ++++++++++++++++++++++++++---------------------------
 src/message.h      | 202 ++++++++++---
 src/privkey-t.h    |   3 +-
 src/privkey.c      |   3 +-
 src/privkey.h      |   3 +-
 src/proto.c        | 270 ++++++++---------
 src/proto.h        |   6 +-
 src/serial.h       |   3 +-
 src/sm.c           |   3 +-
 src/sm.h           |   3 +-
 src/tlv.c          |   3 +-
 src/tlv.h          |   3 +-
 src/userstate.c    |   3 +-
 src/userstate.h    |   3 +-
 src/version.h      |   3 +-
 31 files changed, 972 insertions(+), 768 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 50a839d..ef73f85 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,6 +2,7 @@ Off-the-Record Messaging Library and Toolkit
 
 Authors:
 
-    Ian Goldberg, Chris Alexander, Nikita Borisov <otr at cypherpunks.ca>
+    Ian Goldberg, Chris Alexander, Willy Lew, Nikita Borisov
+    <otr at cypherpunks.ca>
 
 See the README file for mailing list information
diff --git a/ChangeLog b/ChangeLog
index 4077cfa..e492c21 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2009-04-28:
+
+	* src/auth.c: pubkey_type should be shifted by 8, not 16.  It
+	doesn't matter right now, because it's always 0, but still.
+	(Thanks to Can Tang.)
+
+2008-08-15:
+
+	* src/Makefile.am:
+	* src/context.c:
+	* src/context.h:
+	* src/context_priv.c:
+	* src/context_priv.h:
+	* src/message.c:
+	* src/message.h:
+	* src/proto.c:
+	* src/proto.h: Willy Lew's updates of the libotr API
+
 2008-08-06:
 
 	* src/proto.c: gcc 4.2 with -O2 assumes that integer overflow
diff --git a/README b/README
index 0b87bcc..04e5092 100644
--- a/README
+++ b/README
@@ -267,7 +267,8 @@ The Off-the-Record Messaging library (in the src directory) is
 covered by the following (LGPL) license:
 
     Off-the-Record Messaging library
-    Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+    Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+    			     Nikita Borisov
 			     <otr at cypherpunks.ca>
 
     This library is free software; you can redistribute it and/or
diff --git a/src/Makefile.am b/src/Makefile.am
index c75fcbe..cc4d26f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,11 +3,12 @@ INCLUDES = @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
+		    userstate.c tlv.c auth.c sm.c context_priv.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
+		 version.h userstate.h tlv.h serial.h auth.h sm.h privkey-t.h \
+		 context_priv.h
diff --git a/src/auth.c b/src/auth.c
index a6752c3..36267b5 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
@@ -382,7 +383,7 @@ static gcry_error_t calculate_pubkey_auth(unsigned char **authbufp,
     /* 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) >> 16) & 0xff;
+    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);
@@ -413,7 +414,7 @@ static gcry_error_t calculate_pubkey_auth(unsigned char **authbufp,
     lenp = totallen;
 
     /* Write the data to be encrypted */
-    bufp[0] = ((privkey->pubkey_type) >> 16) & 0xff;
+    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);
@@ -520,7 +521,7 @@ static gcry_error_t check_pubkey_auth(unsigned char fingerprintbufp[20],
 
     write_mpi(their_dh_pub, theirpublen, "Their DH pubkey");
     write_mpi(our_dh_pub, ourpublen, "Our DH pubkey");
-    bufp[0] = (pubkey_type >> 16) & 0xff;
+    bufp[0] = (pubkey_type >> 8) & 0xff;
     bufp[1] = pubkey_type & 0xff;
     bufp += 2; lenp -= 2;
     memmove(bufp, fingerprintstart, fingerprintend - fingerprintstart);
@@ -1030,7 +1031,7 @@ gcry_error_t otrl_auth_handle_signature(OtrlAuthInfo *auth,
 	    if (auth_succeeded) err = auth_succeeded(auth, asdata);
 	    free(auth->lastauthmsg);
 	    auth->lastauthmsg = NULL;
-	    *havemsgp = 1;
+	    *havemsgp = 0;
 	    auth->our_keyid = 0;
 	    auth->authstate = OTRL_AUTHSTATE_NONE;
 
diff --git a/src/auth.h b/src/auth.h
index 6de75dd..4ca5aa3 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/b64.c b/src/b64.c
index b8736da..bfe163a 100644
--- a/src/b64.c
+++ b/src/b64.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/b64.h b/src/b64.h
index 34ef03f..9a4e636 100644
--- a/src/b64.h
+++ b/src/b64.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/context.c b/src/context.c
index dd5536f..e584769 100644
--- a/src/context.c
+++ b/src/context.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
@@ -38,10 +39,6 @@ static ConnContext * new_context(const char * user, const char * accountname,
     context->username = strdup(user);
     context->accountname = strdup(accountname);
     context->protocol = strdup(protocol);
-    context->fragment = NULL;
-    context->fragment_len = 0;
-    context->fragment_n = 0;
-    context->fragment_k = 0;
     context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
     otrl_auth_new(&(context->auth));
 
@@ -55,34 +52,14 @@ static ConnContext * new_context(const char * user, const char * accountname,
     context->fingerprint_root.next = NULL;
     context->fingerprint_root.tous = NULL;
     context->active_fingerprint = NULL;
-    context->their_keyid = 0;
-    context->their_y = NULL;
-    context->their_old_y = NULL;
-    context->our_keyid = 0;
-    context->our_dh_key.groupid = 0;
-    context->our_dh_key.priv = NULL;
-    context->our_dh_key.pub = NULL;
-    context->our_old_dh_key.groupid = 0;
-    context->our_old_dh_key.priv = NULL;
-    context->our_old_dh_key.pub = NULL;
-    otrl_dh_session_blank(&(context->sesskeys[0][0]));
-    otrl_dh_session_blank(&(context->sesskeys[0][1]));
-    otrl_dh_session_blank(&(context->sesskeys[1][0]));
-    otrl_dh_session_blank(&(context->sesskeys[1][1]));
     memset(context->sessionid, 0, 20);
     context->sessionid_len = 0;
     context->protocol_version = 0;
-    context->numsavedkeys = 0;
-    context->preshared_secret = NULL;
-    context->preshared_secret_len = 0;
-    context->saved_mac_keys = NULL;
-    context->generation = 0;
-    context->lastsent = 0;
-    context->lastmessage = NULL;
-    context->may_retransmit = 0;
     context->otr_offer = OFFER_NOT;
     context->app_data = NULL;
     context->app_data_free = NULL;
+    context->context_priv = context_priv_new();
+    assert(context->context_priv != NULL);
     context->next = NULL;
     return context;
 }
@@ -174,61 +151,17 @@ void otrl_context_set_trust(Fingerprint *fprint, const char *trust)
     fprint->trust = trust ? strdup(trust) : NULL;
 }
 
-/* Set the preshared secret for a given fingerprint.  Note that this
- * currently only stores the secret in the ConnContext structure, but
- * doesn't yet do anything with it. */
-void otrl_context_set_preshared_secret(ConnContext *context,
-	const unsigned char *secret, size_t secret_len)
-{
-    free(context->preshared_secret);
-    context->preshared_secret = NULL;
-    context->preshared_secret_len = 0;
-
-    if (secret_len) {
-	context->preshared_secret = malloc(secret_len);
-	if (context->preshared_secret) {
-	    memmove(context->preshared_secret, secret, secret_len);
-	    context->preshared_secret_len = secret_len;
-	}
-    }
-}
-
 /* 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));
-    free(context->fragment);
-    context->fragment = NULL;
-    context->fragment_len = 0;
-    context->fragment_n = 0;
-    context->fragment_k = 0;
     context->active_fingerprint = NULL;
-    context->their_keyid = 0;
-    gcry_mpi_release(context->their_y);
-    context->their_y = NULL;
-    gcry_mpi_release(context->their_old_y);
-    context->their_old_y = NULL;
-    context->our_keyid = 0;
-    otrl_dh_keypair_free(&(context->our_dh_key));
-    otrl_dh_keypair_free(&(context->our_old_dh_key));
-    otrl_dh_session_free(&(context->sesskeys[0][0]));
-    otrl_dh_session_free(&(context->sesskeys[0][1]));
-    otrl_dh_session_free(&(context->sesskeys[1][0]));
-    otrl_dh_session_free(&(context->sesskeys[1][1]));
     memset(context->sessionid, 0, 20);
     context->sessionid_len = 0;
-    free(context->preshared_secret);
-    context->preshared_secret = NULL;
-    context->preshared_secret_len = 0;
     context->protocol_version = 0;
-    context->numsavedkeys = 0;
-    free(context->saved_mac_keys);
-    context->saved_mac_keys = NULL;
-    gcry_free(context->lastmessage);
-    context->lastmessage = NULL;
-    context->may_retransmit = 0;
     otrl_sm_state_free(context->smstate);
+    context_priv_force_finished(context->context_priv);
 }
 
 /* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */
diff --git a/src/context.h b/src/context.h
index e722c56..1ae658a 100644
--- a/src/context.h
+++ b/src/context.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
@@ -20,6 +21,8 @@
 #ifndef __CONTEXT_H__
 #define __CONTEXT_H__
 
+#include "context_priv.h"
+
 #include <gcrypt.h>
 
 #include "dh.h"
@@ -51,20 +54,17 @@ typedef 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 */
 
-    char *fragment;                    /* The part of the fragmented message
-					  we've seen so far */
-    size_t fragment_len;               /* The length of fragment */
-    unsigned short fragment_n;         /* The total number of fragments
-					  in this message */
-    unsigned short fragment_k;         /* The highest fragment number
-					  we've seen so far for this
-					  message */
-
     OtrlMessageState msgstate;         /* The state of message disposition
 					  with this user */
     OtrlAuthInfo auth;                 /* The state of ongoing
@@ -74,20 +74,6 @@ typedef struct context {
 					  Fingerprints entries */
     Fingerprint *active_fingerprint;   /* Which fingerprint is in use now?
                                           A pointer into the above list */
-    unsigned int their_keyid;          /* current keyid used by other side;
-                                          this is set to 0 if we get a
-					  OTRL_TLV_DISCONNECTED message from
-					  them. */
-    gcry_mpi_t their_y;                /* Y[their_keyid] (their DH pubkey) */
-    gcry_mpi_t their_old_y;            /* Y[their_keyid-1] (their prev DH
-					  pubkey) */
-    unsigned int our_keyid;            /* current keyid used by us */
-    DH_keypair our_dh_key;             /* DH key[our_keyid] */
-    DH_keypair our_old_dh_key;         /* DH key[our_keyid-1] */
-
-    DH_sesskeys sesskeys[2][2];        /* sesskeys[i][j] are the session keys
-					  derived from DH key[our_keyid-i]
-					  and mpi Y[their_keyid-j] */
 
     unsigned char sessionid[20];       /* The sessionid and bold half */
     size_t sessionid_len;              /* determined when this private */
@@ -95,24 +81,6 @@ typedef struct context {
 
     unsigned int protocol_version;     /* The version of OTR in use */
 
-    unsigned char *preshared_secret;   /* A secret you share with this
-					  user, in order to do
-					  authentication. */
-    size_t preshared_secret_len;       /* The length of the above secret. */
-
-    /* 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;
-
-    time_t lastsent;      /* The last time a Data Message was sent */
-    char *lastmessage;    /* The plaintext of the last Data Message sent */
-    int may_retransmit;   /* Is the last message eligible for
-			     retransmission? */
-
     enum {
 	OFFER_NOT,
 	OFFER_SENT,
@@ -150,12 +118,6 @@ Fingerprint *otrl_context_find_fingerprint(ConnContext *context,
 /* Set the trust level for a given fingerprint */
 void otrl_context_set_trust(Fingerprint *fprint, const char *trust);
 
-/* Set the preshared secret for a given fingerprint.  Note that this
- * currently only stores the secret in the ConnContext structure, but
- * doesn't yet do anything with it. */
-void otrl_context_set_preshared_secret(ConnContext *context,
-	const unsigned char *secret, size_t secret_len);
-
 /* Force a context into the OTRL_MSGSTATE_FINISHED state. */
 void otrl_context_force_finished(ConnContext *context);
 
diff --git a/src/context_priv.c b/src/context_priv.c
new file mode 100644
index 0000000..62ea68b
--- /dev/null
+++ b/src/context_priv.c
@@ -0,0 +1,94 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *			     Nikita Borisov
+ *                           <otr at 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 *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->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 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/src/context_priv.h b/src/context_priv.h
new file mode 100644
index 0000000..b05b5ff
--- /dev/null
+++ b/src/context_priv.h
@@ -0,0 +1,91 @@
+/*
+ *  Off-the-Record Messaging library
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *			     Nikita Borisov
+ *                           <otr at 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 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 *context_priv_new();
+
+/* Frees up memory that was used in context_priv_new */
+void context_priv_force_finished(ConnContextPriv *context_priv);
+
+#endif
diff --git a/src/dh.c b/src/dh.c
index 8ffe1ba..a28d376 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/dh.h b/src/dh.h
index facf043..788b20f 100644
--- a/src/dh.h
+++ b/src/dh.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/mem.c b/src/mem.c
index b2a2191..075f3c0 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/mem.h b/src/mem.h
index 19e00cf..e1f5a1e 100644
--- a/src/mem.h
+++ b/src/mem.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/message.c b/src/message.c
index c61cd13..dcc18db 100644
--- a/src/message.c
+++ b/src/message.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
@@ -42,6 +43,76 @@ extern unsigned int otrl_api_version;
  * resending in response to a rekey? */
 #define RESEND_INTERVAL 60
 
+/* 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 (otrl_api_version >= 0x030100 && 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 fragment_count = ((msglen - 1) / (mms -19)) + 1;
+		/* like ceil(msglen/(mms - 19)) */
+
+	    err = otrl_proto_fragment_create(mms, fragment_count, &fragments,
+		    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. */
+		int l = strlen(message) + 1;
+		*returnFragment = malloc(sizeof(char)*l);
+		strcpy(*returnFragment, message);
+	    }
+	}
+    }
+    return gcry_error(GPG_ERR_NO_ERROR);
+}
+
 /* Deallocate a message allocated by other otrl_message_* routines. */
 void otrl_message_free(char *message)
 {
@@ -55,37 +126,51 @@ void otrl_message_free(char *message)
  * 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.  
+ * 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 this 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.  Call otrl_message_free(*messagep) when you're
+ * 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 if 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, const char *message, OtrlTLV *tlvs,
-	char **messagep,
+	const char *recipient, char **original_msgp, OtrlTLV *tlvs,
+	char **messagep, OtrlFragmentPolicy fragPolicy,
+	void (*convert_msg)(void *convert_data, const char *source, char **target),
+	void *convert_data,
 	void (*add_appdata)(void *data, ConnContext *context),
 	void *data)
 {
     struct context * context;
     char * msgtosend;
-    gcry_error_t err;
+    const char * err_msg;
+    gcry_error_t err_code, err;
     OtrlPolicy policy = OTRL_POLICY_DEFAULT;
     int context_added = 0;
 
     *messagep = NULL;
+    err = gcry_error(GPG_ERR_NO_ERROR);	/* Default to no error */
 
-    if (!accountname || !protocol || !recipient || !message || !messagep)
-        return gcry_error(GPG_ERR_NO_ERROR);
+    if (!accountname || !protocol || !recipient ||
+    		!original_msgp || !*original_msgp || !messagep) {
+    	err = gcry_error(GPG_ERR_NO_ERROR);
+    	goto fragment;
+    }
 
     /* See if we have a fingerprint for this user */
     context = otrl_context_find(us, recipient, accountname, protocol,
@@ -103,7 +188,8 @@ gcry_error_t otrl_message_sending(OtrlUserState us,
 
     /* Should we go on at all? */
     if ((policy & OTRL_POLICY_VERSION_MASK) == 0) {
-        return gcry_error(GPG_ERR_NO_ERROR);
+        err =  gcry_error(GPG_ERR_NO_ERROR);
+    	goto fragment;
     }
 
     /* XXX: Add flags to the policy specifying whether to treat a typed
@@ -111,13 +197,14 @@ gcry_error_t otrl_message_sending(OtrlUserState us,
      * for (1) unencrypted conversations, (2) encrypted conversations. */
 
     /* If this is an OTR Query message, don't encrypt it. */
-    if (otrl_proto_message_type(message) == OTRL_MSGTYPE_QUERY) {
+    if (otrl_proto_message_type(*original_msgp) == OTRL_MSGTYPE_QUERY) {
 	/* Replace the "?OTR?" with a custom message */
 	char *bettermsg = otrl_proto_default_query_msg(accountname, policy);
 	if (bettermsg) {
 	    *messagep = bettermsg;
 	}
-	return gcry_error(GPG_ERR_NO_ERROR);
+	err = gcry_error(GPG_ERR_NO_ERROR);
+	goto fragment;
     }
 
     /* What is the current message disposition? */
@@ -127,38 +214,25 @@ gcry_error_t otrl_message_sending(OtrlUserState us,
 		/* 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->display_otr_message) ||
-			ops->display_otr_message(opdata, accountname,
-			    protocol, recipient, "Attempting to start a "
-			    "private conversation...")) && ops->notify) {
-		    const char *format = "You attempted to send an "
-			"unencrypted message to %s";
-		    char *primary = malloc(strlen(format) +
-			    strlen(recipient) - 1);
-		    if (primary) {
-			sprintf(primary, format, recipient);
-			ops->notify(opdata, OTRL_NOTIFY_WARNING, accountname,
-				protocol, recipient, "OTR Policy Violation",
-				primary,
-				"Unencrypted messages to this recipient are "
-				"not allowed.  Attempting to start a private "
-				"conversation.\n\nYour message will be "
-				"retransmitted when the private conversation "
-				"starts.");
-			free(primary);
-		    }
+		if (ops->handle_msg_event) {
+		    ops->handle_msg_event(opdata,
+			    OTRL_MSGEVENT_ENCRYPTION_REQUIRED,
+			    context, NULL, (gcry_error_t)NULL);
 		}
-		context->lastmessage = gcry_malloc_secure(strlen(message) + 1);
-		if (context->lastmessage) {
+
+		context->context_priv->lastmessage =
+			gcry_malloc_secure(strlen(*original_msgp) + 1);
+		if (context->context_priv->lastmessage) {
 		    char *bettermsg = otrl_proto_default_query_msg(accountname,
 			    policy);
-		    strcpy(context->lastmessage, message);
-		    context->lastsent = time(NULL);
-		    context->may_retransmit = 2;
+		    strcpy(context->context_priv->lastmessage, *original_msgp);
+		    context->context_priv->lastsent = time(NULL);
+		    context->context_priv->may_retransmit = 2;
 		    if (bettermsg) {
 			*messagep = bettermsg;
 		    } else {
-			return gcry_error(GPG_ERR_ENOMEM);
+			err = gcry_error(GPG_ERR_ENOMEM);
+			goto fragment;
 		    }
 		}
 	    } else {
@@ -167,7 +241,7 @@ gcry_error_t otrl_message_sending(OtrlUserState us,
 		    /* 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(message);
+		    size_t msglen = strlen(*original_msgp);
 		    size_t basetaglen = strlen(OTRL_MESSAGE_TAG_BASE);
 		    size_t v1taglen = (policy & OTRL_POLICY_ALLOW_V1) ?
 			strlen(OTRL_MESSAGE_TAG_V1) : 0;
@@ -176,7 +250,7 @@ gcry_error_t otrl_message_sending(OtrlUserState us,
 		    char *taggedmsg = malloc(msglen + basetaglen + v1taglen
 			    +v2taglen + 1);
 		    if (taggedmsg) {
-			strcpy(taggedmsg, message);
+			strcpy(taggedmsg, *original_msgp);
 			strcpy(taggedmsg + msglen, OTRL_MESSAGE_TAG_BASE);
 			if (v1taglen) {
 			    strcpy(taggedmsg + msglen + basetaglen,
@@ -195,59 +269,83 @@ gcry_error_t otrl_message_sending(OtrlUserState us,
 	    }
 	    break;
 	case OTRL_MSGSTATE_ENCRYPTED:
+	    /* convert the original message if necessary */
+	    if (convert_msg) {
+	    	/* using msgtosend as a temporary placeholder */
+	        msgtosend = *original_msgp;
+	        convert_msg(convert_data, msgtosend, original_msgp);
+	        free(msgtosend);
+	        msgtosend = NULL;
+	    }
+
 	    /* Create the new, encrypted message */
-	    err = otrl_proto_create_data(&msgtosend, context, message, tlvs,
-		    0, NULL);
-	    if (!err) {
-		context->lastsent = time(NULL);
+	    err_code = otrl_proto_create_data(&msgtosend, context,
+		    *original_msgp, tlvs, 0, NULL);
+	    if (!err_code) {
+		context->context_priv->lastsent = time(NULL);
 		*messagep = msgtosend;
 	    } else {
 		/* Uh, oh.  Whatever we do, *don't* send the message in the
 		 * clear. */
-		*messagep = strdup("?OTR Error: Error occurred encrypting "
-			"message");
-		if ((!(ops->display_otr_message) ||
-			ops->display_otr_message(opdata, accountname,
-			    protocol, recipient, "An error occurred when "
-			    "encrypting your message.  The message was not "
-			    "sent.")) && ops->notify) {
-		    ops->notify(opdata, OTRL_NOTIFY_ERROR, 
-			    accountname, protocol, recipient,
-			    "Error encrypting message",
-			    "An error occurred when encrypting your message",
-			    "The message was not sent.");
+		if (ops->handle_msg_event) {
+		ops->handle_msg_event(opdata, OTRL_MSGEVENT_ENCRYPTION_ERROR,
+		    context, NULL, (gcry_error_t)NULL);
 		}
-		if (!(*messagep)) {
-		    return gcry_error(GPG_ERR_ENOMEM);
+		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:
-	    *messagep = strdup("");
-	    if ((!(ops->display_otr_message) ||
-		    ops->display_otr_message(opdata, accountname,
-			protocol, recipient, "Your message was not sent.  "
-			"Either end your private conversation, or restart "
-			"it.")) && ops->notify) {
-		const char *fmt = "%s has already closed his/her private "
-		    "connection to you";
-		char *primary = malloc(strlen(fmt) + strlen(recipient) - 1);
-		if (primary) {
-		    sprintf(primary, fmt, recipient);
-		    ops->notify(opdata, OTRL_NOTIFY_ERROR, 
-			    accountname, protocol, recipient,
-			    "Private connection closed", primary,
-			    "Your message was not sent.  Either close your "
-			    "private connection to him, or refresh it.");
-		}
+	    if (ops->handle_msg_event) {
+		ops->handle_msg_event(opdata, OTRL_MSGEVENT_CONNECTION_ENDED,
+		    context, NULL, (gcry_error_t)NULL);
 	    }
+	    *messagep = strdup("");
 	    if (!(*messagep)) {
-		return gcry_error(GPG_ERR_ENOMEM);
+		err = gcry_error(GPG_ERR_ENOMEM);
+		goto fragment;
 	    }
 	    break;
     }
 
-    return gcry_error(GPG_ERR_NO_ERROR);
+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 == NULL) {
+	    /* Do not send plaintext */
+	    char *ourm = strdup("");
+	    free(*original_msgp);
+	    *original_msgp = ourm;
+    	} else if (*messagep) {
+	    ConnContext *conncontext = otrl_context_find(us, recipient,
+		    accountname, protocol, 0, NULL, NULL, NULL);
+	    free(*original_msgp);
+	    *original_msgp = NULL;
+	    if (conncontext) {
+		err = fragment_and_send(ops, NULL, conncontext, *messagep,
+			fragPolicy, original_msgp);
+	    }
+    	}
+    	return err;
+    }
 }
 
 /* If err == 0, send the last auth message for the given context to the
@@ -259,38 +357,15 @@ static gcry_error_t send_or_error_auth(const OtrlMessageAppOps *ops,
     if (!err) {
 	const char *msg = context->auth.lastauthmsg;
 	if (msg && *msg) {
-	    otrl_message_fragment_and_send(ops, opdata, context, msg, OTRL_FRAGMENT_SEND_ALL, NULL);
-	    /*if (ops->inject_message) {
-		ops->inject_message(opdata, context->accountname,
-			context->protocol, context->username, msg);
-	    }*/
+ 	    fragment_and_send(ops, opdata, context, msg,
+		    OTRL_FRAGMENT_SEND_ALL, NULL);
+	    context->context_priv->lastsent = time(NULL);
 	}
     } else {
-	const char *buf_format = "Error setting up private conversation: %s";
-	const char *strerr;
-	char *buf;
-	
-	switch(gcry_err_code(err)) {
-	    case GPG_ERR_INV_VALUE:
-		strerr = "Malformed message received";
-		break;
-	    default:
-		strerr = gcry_strerror(err);
-		break;
-	}
-	buf = malloc(strlen(buf_format) + strlen(strerr) - 1);
-	if (buf) {
-	    sprintf(buf, buf_format, strerr);
-	}
-	if ((!(ops->display_otr_message) ||
-		ops->display_otr_message(opdata, context->accountname,
-		    context->protocol, context->username, buf))
-		&& ops->notify) {
-	    ops->notify(opdata, OTRL_NOTIFY_ERROR, context->accountname,
-		    context->protocol, context->username, "OTR error",
-		    buf, NULL);
-	}
-	free(buf);
+     	if (ops->handle_msg_event) {
+	    ops->handle_msg_event(opdata, OTRL_MSGEVENT_SETUP_ERROR,
+		    context, NULL, err);
+     	}
     }
     return err;
 }
@@ -316,23 +391,12 @@ static gcry_error_t go_encrypted(const OtrlAuthInfo *auth, void *asdata)
 
     /* See if we're talking to ourselves */
     if (!gcry_mpi_cmp(auth->their_pub, auth->our_dh.pub)) {
-	/* Yes, we are. */
-	if ((!(edata->ops->display_otr_message) ||
-		edata->ops->display_otr_message(edata->opdata,
-		    edata->context->accountname, edata->context->protocol,
-		    edata->context->username,
-		    "We are receiving our own OTR messages.  "
-		    "You are either trying to talk to yourself, "
-		    "or someone is reflecting your messages back "
-		    "at you.")) && edata->ops->notify) {
-	    edata->ops->notify(edata->opdata, OTRL_NOTIFY_ERROR,
-		edata->context->accountname, edata->context->protocol,
-		edata->context->username, "OTR Error",
-		"We are receiving our own OTR messages.",
-		"You are either trying to talk to yourself, "
-		"or someone is reflecting your messages back "
-		"at you.");
-	}
+    	/* 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_t)NULL);
+    	}
 	edata->ignore_message = 1;
 	return gcry_error(GPG_ERR_NO_ERROR);
     }
@@ -357,19 +421,19 @@ static gcry_error_t go_encrypted(const OtrlAuthInfo *auth, void *asdata)
     /* 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->our_keyid - 1 == edata->context->auth.our_keyid &&
-	    !gcry_mpi_cmp(edata->context->our_old_dh_key.pub,
+	    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->their_keyid > 0 &&
-	      edata->context->their_keyid ==
+	    ((edata->context->context_priv->their_keyid > 0 &&
+	      edata->context->context_priv->their_keyid ==
 		    edata->context->auth.their_keyid &&
-	      !gcry_mpi_cmp(edata->context->their_y,
+	      !gcry_mpi_cmp(edata->context->context_priv->their_y,
 		  edata->context->auth.their_pub)) ||
-	    (edata->context->their_keyid > 1 &&
-	     edata->context->their_keyid - 1 ==
+	    (edata->context->context_priv->their_keyid > 1 &&
+	     edata->context->context_priv->their_keyid - 1 ==
 		    edata->context->auth.their_keyid &&
-	     edata->context->their_old_y != NULL &&
-	     !gcry_mpi_cmp(edata->context->their_old_y,
+	     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) {
@@ -390,35 +454,35 @@ static gcry_error_t go_encrypted(const OtrlAuthInfo *auth, void *asdata)
     edata->context->protocol_version =
 	edata->context->auth.protocol_version;
 
-    edata->context->their_keyid = edata->context->auth.their_keyid;
-    gcry_mpi_release(edata->context->their_y);
-    gcry_mpi_release(edata->context->their_old_y);
-    edata->context->their_y = gcry_mpi_copy(edata->context->auth.their_pub);
-    edata->context->their_old_y = NULL;
+    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->our_keyid - 1 != edata->context->auth.our_keyid ||
-	gcry_mpi_cmp(edata->context->our_old_dh_key.pub,
+    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->our_dh_key));
-	otrl_dh_keypair_free(&(edata->context->our_old_dh_key));
-	otrl_dh_keypair_copy(&(edata->context->our_old_dh_key),
+	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->our_old_dh_key.groupid,
-		&(edata->context->our_dh_key));
-	edata->context->our_keyid = edata->context->auth.our_keyid + 1;
+	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->sesskeys[0][0]));
-    err = otrl_dh_session(&(edata->context->sesskeys[0][0]),
-	&(edata->context->our_dh_key), edata->context->their_y);
+    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->sesskeys[1][0]));
-    err = otrl_dh_session(&(edata->context->sesskeys[1][0]),
-	&(edata->context->our_old_dh_key), edata->context->their_y);
+    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->generation++;
+    edata->context->context_priv->generation++;
     edata->context->active_fingerprint = found_print;
     edata->context->msgstate = OTRL_MSGSTATE_ENCRYPTED;
 
@@ -450,51 +514,62 @@ static void maybe_resend(EncrData *edata)
 
     /* See if there's a message we sent recently that should be resent. */
     now = time(NULL);
-    if (edata->context->lastmessage != NULL &&
-	    edata->context->may_retransmit &&
-	    edata->context->lastsent >= (now - RESEND_INTERVAL)) {
+    if (edata->context->context_priv->lastmessage != NULL &&
+	    edata->context->context_priv->may_retransmit &&
+	    edata->context->context_priv->lastsent >= (now - RESEND_INTERVAL)) {
 	char *resendmsg;
-	int resending = (edata->context->may_retransmit == 1);
+	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);
+	    }
+	    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, edata->context->lastmessage, NULL, 0, NULL);
+		edata->context, msg_to_send, NULL, 0, NULL);
+	if (resending && msg_to_send) {
+		free(msg_to_send);
+	}
 	if (!err) {
-	    const char *format = "<b>The last message "
-		"to %s was resent.</b>";
-	    char *buf;
-
 	    /* Resend the message */
-	    otrl_message_fragment_and_send(edata->ops, edata->opdata, edata->context, resendmsg, OTRL_FRAGMENT_SEND_ALL, NULL);
+	    fragment_and_send(edata->ops, edata->opdata, edata->context,
+		    resendmsg, OTRL_FRAGMENT_SEND_ALL, NULL);
 	    free(resendmsg);
-	    edata->context->lastsent = now;
-
-	    if (!resending) {
-		/* We're actually just sending it
-		 * for the first time. */
-		edata->ignore_message = 1;
-	    } else {
-		/* Let the user know we resent it */
-		buf = malloc(strlen(format) +
-			strlen(edata->context->username) - 1);
-		if (buf) {
-		    sprintf(buf, format, edata->context->username);
-		    if (edata->ops->display_otr_message) {
-			if (!edata->ops->display_otr_message(
-				    edata->opdata, edata->context->accountname,
-				    edata->context->protocol,
-				    edata->context->username, buf)) {
-			    edata->ignore_message = 1;
-			}
-		    }
-		    if (edata->ignore_message != 1) {
-			*(edata->messagep) = buf;
-			edata->ignore_message = 0;
-		    } else {
-			free(buf);
-		    }
+	    edata->context->context_priv->lastsent = now;
+	    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_t)NULL);
 		}
 	    }
+	    edata->ignore_message = 1;
 	}
     }
 }
@@ -589,7 +664,7 @@ static void init_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
     if (!err) {
         /*  Send it, and set the next expected message to the
 	 *  logical response */
-        err = otrl_message_fragment_and_send(ops, opdata, context,
+        err = fragment_and_send(ops, opdata, context,
 		sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL);
         context->smstate->nextExpected =
 	    initiating ? OTRL_SMP_EXPECT2 : OTRL_SMP_EXPECT3;
@@ -633,7 +708,7 @@ void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
 	    (const unsigned char *)"");
     char *sendsmp = NULL;
     gcry_error_t err;
-    
+
     context->smstate->nextExpected = OTRL_SMP_EXPECT1;
 
     err = otrl_proto_create_data(&sendsmp,
@@ -641,7 +716,7 @@ void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
 	    OTRL_MSGFLAGS_IGNORE_UNREADABLE, NULL);
     if (!err) {
 	/* Send the abort signal so our buddy knows we've stopped */
-	err = otrl_message_fragment_and_send(ops, opdata, context,
+	err = fragment_and_send(ops, opdata, context,
 		sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL);
     }
     free(sendsmp);
@@ -655,7 +730,10 @@ void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
  * 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.  
+ * can pass NULL for the last two arguments of otrl_message_receiving.
+ *
+ * convert_msg is a function that will be called on each msg that is received.
+ * You can use it to perform some tweaks on your incoming messages.
  *
  * If otrl_message_receiving returns 1, then the message you received
  * was an internal protocol message, and no message should be delivered
@@ -676,6 +754,8 @@ 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,
+	void (*convert_msg)(void *convert_data, const char *source, char **target),
+	void *convert_data,
 	void (*add_appdata)(void *data, ConnContext *context),
 	void *data)
 {
@@ -763,8 +843,8 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 	    /* See if we should use an existing DH keypair, or generate
 	     * a fresh one. */
 	    if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
-		our_dh = &(context->our_old_dh_key);
-		our_keyid = context->our_keyid - 1;
+		our_dh = &(context->context_priv->our_old_dh_key);
+		our_keyid = context->context_priv->our_keyid - 1;
 	    } else {
 		our_dh = NULL;
 		our_keyid = 0;
@@ -875,7 +955,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 		    maybe_resend(&edata);
 		}
 	    }
-	    
+
 	    if (edata.ignore_message == -1) edata.ignore_message = 1;
 	    break;
 
@@ -884,8 +964,8 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 		/* See if we should use an existing DH keypair, or generate
 		 * a fresh one. */
 		if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
-		    our_dh = &(context->our_old_dh_key);
-		    our_keyid = context->our_keyid - 1;
+		    our_dh = &(context->context_priv->our_old_dh_key);
+		    our_keyid = context->context_priv->our_keyid - 1;
 		} else {
 		    our_dh = NULL;
 		    our_keyid = 0;
@@ -913,7 +993,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 		    }
 		}
 	    }
-	    
+
 	    if (edata.ignore_message == -1) edata.ignore_message = 1;
 	    break;
 
@@ -923,8 +1003,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 		OtrlTLV *tlvs, *tlv;
 		char *plaintext;
 		char *buf;
-		const char *format;
-		const char *displayaccountname;
+		const char *err_msg;
 		unsigned char *extrakey;
 		unsigned char flags;
 		NextExpectedSMP nextMsg;
@@ -938,92 +1017,76 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 			edata.ignore_message = 1;
 			break;
 		    }
-
-		    /* Don't use g_strdup_printf here, because someone
-		     * (not us) is going to free() the *newmessagep pointer,
-		     * not g_free() it. */
-		    format = "<b>The encrypted message received from %s is "
-			"unreadable, as you are not currently communicating "
-			"privately.</b>";
-		    buf = malloc(strlen(format) + strlen(context->username)
-			    - 1);  /* Remove "%s", add username + '\0' */
-		    if (buf) {
-			sprintf(buf, format, context->username);
-			if (ops->display_otr_message) {
-			    if (!ops->display_otr_message(opdata, accountname,
-					protocol, sender, buf)) {
-				edata.ignore_message = 1;
-			    }
-			}
-			if (edata.ignore_message != 1) {
-			    *newmessagep = buf;
-			    edata.ignore_message = 0;
-			} else {
-			    free(buf);
-			}
-		    }
-		    format = "?OTR Error: You sent encrypted "
-			    "data to %s, who wasn't expecting it.";
-		    if (otrl_api_version >= 0x00030100 &&
-			    ops->account_name) {
-			displayaccountname = ops->account_name(opdata,
-				context->accountname, protocol);
-		    } else {
-			displayaccountname = NULL;
+		    if (ops->handle_msg_event) {
+		    	ops->handle_msg_event(opdata,
+				OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE,
+				context, NULL, (gcry_error_t)NULL);
 		    }
-		    buf = malloc(strlen(format) + strlen(displayaccountname ?
-				displayaccountname : context->accountname)
-			    - 1);
-		    if (buf) {
-			sprintf(buf, format, displayaccountname ?
-				displayaccountname : context->accountname);
-			if (ops->inject_message) {
+		    edata.ignore_message = 1;
+		    if (ops->inject_message && ops->otr_error_message) {
+		    	err_msg = ops->otr_error_message(opdata, context,
+		    			OTRL_ERRCODE_MSG_NOT_IN_PRIVATE);
+		    	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 (displayaccountname && otrl_api_version >= 0x00030100 &&
-			    ops->account_name_free) {
-			ops->account_name_free(opdata, displayaccountname);
+			    free(buf);
+		    	}
+		    	if (ops->otr_error_message_free) {
+		    		ops->otr_error_message_free(opdata, err_msg);
+		    	}
 		    }
-
 		    break;
 
 		case OTRL_MSGSTATE_ENCRYPTED:
 		    extrakey = gcry_malloc_secure(OTRL_EXTRAKEY_BYTES);
 		    err = otrl_proto_accept_data(&plaintext, &tlvs, context,
-			    message, &flags, extrakey);
+				    message, &flags, extrakey);
 		    if (err) {
 			int is_conflict =
-			    (gpg_err_code(err) == GPG_ERR_CONFLICT);
+				(gpg_err_code(err) == GPG_ERR_CONFLICT);
 			if ((flags & OTRL_MSGFLAGS_IGNORE_UNREADABLE)) {
 			    edata.ignore_message = 1;
 			    break;
 			}
-			format = is_conflict ? "We received an unreadable "
-			    "encrypted message from %s." :
-			    "We received a malformed data message from %s.";
-			buf = malloc(strlen(format) + strlen(sender) - 1);
-			if (buf) {
-			    sprintf(buf, format, sender);
-			    if ((!(ops->display_otr_message) ||
-				    ops->display_otr_message(opdata,
-					accountname, protocol, sender,
-					buf)) && ops->notify) {
-				ops->notify(opdata, OTRL_NOTIFY_ERROR,
-					accountname, protocol, sender,
-					"OTR Error", buf, NULL);
+			if (is_conflict) {
+			    if (ops->handle_msg_event) {
+				ops->handle_msg_event(opdata,
+					OTRL_MSGEVENT_RCVDMSG_UNREADABLE,
+					context, NULL, (gcry_error_t)NULL);
+			    }
+			} else {
+			    if (ops->handle_msg_event) {
+				ops->handle_msg_event(opdata,
+					OTRL_MSGEVENT_RCVDMSG_MALFORMED,
+					context, NULL, (gcry_error_t)NULL);
 			    }
-			    free(buf);
 			}
-			if (ops->inject_message) {
-			    ops->inject_message(opdata, accountname, protocol,
-				    sender, is_conflict ? "?OTR Error: "
-					    "You transmitted an unreadable "
-					    "encrypted message." :
-					    "?OTR Error: You transmitted "
-					    "a malformed data message");
+			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;
@@ -1094,7 +1157,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 			    }
 			}
 		    }
-		    
+
 		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
 		    if (tlv) {
 			if (nextMsg == OTRL_SMP_EXPECT1) {
@@ -1129,7 +1192,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 			    }
 			}
 		    }
-		    
+
 		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
 		    if (tlv) {
 			if (nextMsg == OTRL_SMP_EXPECT2) {
@@ -1139,7 +1202,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 			    char *sendsmp;
 			    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 */
@@ -1150,7 +1213,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 				    OTRL_MSGFLAGS_IGNORE_UNREADABLE,
 				    NULL);
 				if (!err) {
-				err = otrl_message_fragment_and_send(ops,
+				err = fragment_and_send(ops,
 				    opdata, context, sendsmp,
 				    OTRL_FRAGMENT_SEND_ALL, NULL);
 				}
@@ -1182,9 +1245,9 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 					OTRL_SMPEVENT_ERROR, context,
 					0, NULL);
 			    }
-			}   
+			}
 		    }
-		    
+
 		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
 		    if (tlv) {
 			if (nextMsg == OTRL_SMP_EXPECT3) {
@@ -1199,7 +1262,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 				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 */
@@ -1210,7 +1273,7 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 				    OTRL_MSGFLAGS_IGNORE_UNREADABLE,
 				    NULL);
 				if (!err) {
-				err = otrl_message_fragment_and_send(ops,
+				err = fragment_and_send(ops,
 				    opdata, context, sendsmp,
 				    OTRL_FRAGMENT_SEND_ALL, NULL);
 				}
@@ -1246,9 +1309,9 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 					OTRL_SMPEVENT_ERROR, context,
 					0, NULL);
 			    }
-			}   
+			}
 		    }
-		    
+
 		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
 		    if (tlv) {
 			if (nextMsg == OTRL_SMP_EXPECT4) {
@@ -1288,9 +1351,9 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 					OTRL_SMPEVENT_ERROR, context,
 					0, NULL);
 			    }
-			}   
+			}
 		    }
-			    
+
 		    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
 		    if (tlv) {
 			context->smstate->nextExpected = OTRL_SMP_EXPECT1;
@@ -1303,23 +1366,20 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 		    if (plaintext[0] == '\0') {
 			/* If it's a heartbeat (an empty message), don't
 			 * display it to the user, but log a debug message. */
-			format = "Heartbeat received from %s.\n";
-			buf = malloc(strlen(format) + strlen(sender) - 1);
-			if (buf) {
-			    sprintf(buf, format, sender);
-			    if (ops->log_message) {
-				ops->log_message(opdata, buf);
-			    }
-			    free(buf);
+			if (ops->handle_msg_event) {
+			    ops->handle_msg_event(opdata,
+				    OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD,
+				    context, NULL, (gcry_error_t)NULL);
 			}
 			edata.ignore_message = 1;
-		    } else if (edata.ignore_message == 0 &&
-			    context->their_keyid > 0) {
+		    } 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->lastsent < (now - HEARTBEAT_INTERVAL)) {
+			if (context->context_priv->lastsent <
+				(now - HEARTBEAT_INTERVAL)) {
 			    char *heartbeat;
 
 			    /* Create the heartbeat message */
@@ -1335,18 +1395,13 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 				}
 				free(heartbeat);
 
-				context->lastsent = now;
+				context->context_priv->lastsent = now;
 
-				/* Log a debug message */
-				format = "Heartbeat sent to %s.\n";
-				buf = malloc(strlen(format) + strlen(sender)
-					- 1);
-				if (buf) {
-				    sprintf(buf, format, sender);
-				    if (ops->log_message) {
-					ops->log_message(opdata, buf);
-				    }
-				    free(buf);
+				/* Log the heartbeat message */
+				if (ops->handle_msg_event) {
+				    ops->handle_msg_event(opdata,
+					OTRL_MSGEVENT_LOG_HEARTBEAT_SENT,
+					context, NULL, (gcry_error_t)NULL);
 				}
 			    }
 			}
@@ -1361,8 +1416,17 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 		    }
 
 		    if (edata.ignore_message != 1) {
-			*newmessagep = plaintext;
-			edata.ignore_message = 0;
+		    	*newmessagep = plaintext;
+		    	edata.ignore_message = 0;
+		    	/* convert the original message if necessary */
+		    	if (convert_msg && *newmessagep) {
+			    char *original_msg;
+			    original_msg = *newmessagep;
+			    convert_msg(convert_data, original_msg,
+				    newmessagep);
+			    free(original_msg);
+			    original_msg = NULL;
+		    	}
 		    } else {
 			free(plaintext);
 		    }
@@ -1382,27 +1446,31 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 		free(msgtosend);
 	    }
 
-	    if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
-		/* Mark the last message we sent as eligible for
-		 * retransmission */
-		context->may_retransmit = 1;
-	    }
+	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->display_otr_message) {
-		const char *otrerror = strstr(message, "?OTR Error:");
-		if (otrerror) {
-		    /* Skip the leading '?' */
-		    ++otrerror;
-		} else {
-		    otrerror = message;
-		}
-		if (!ops->display_otr_message(opdata, accountname, protocol,
-			    sender, otrerror)) {
-		    edata.ignore_message = 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_t)NULL);
+	    	}
 	    }
+	    edata.ignore_message = 1;
 	    break;
 
 	case OTRL_MSGTYPE_TAGGEDPLAINTEXT:
@@ -1459,49 +1527,25 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 	    if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT ||
 		    (policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) {
 		/* Not fine.  Let the user know. */
-
-		/* Don't use g_strdup_printf here, because someone
-		 * (not us) is going to free() the *message pointer,
-		 * not g_free() it. */
 		const char *plainmsg = (*newmessagep) ? *newmessagep : message;
-		const char *format = "<b>The following message received "
-		    "from %s was <i>not</i> encrypted: [</b>%s<b>]</b>";
-		char *buf = malloc(strlen(format) + strlen(context->username)
-			+ strlen(plainmsg) - 3);
-			/* Remove "%s%s", add username + message + '\0' */
-		if (buf) {
-		    sprintf(buf, format, context->username, plainmsg);
-		    if (ops->display_otr_message) {
-			if (!ops->display_otr_message(opdata, accountname,
-				    protocol, sender, buf)) {
-			    free(*newmessagep);
-			    *newmessagep = NULL;
-			    edata.ignore_message = 1;
-			}
-		    }
-		    if (edata.ignore_message != 1) {
-			free(*newmessagep);
-			*newmessagep = buf;
-			edata.ignore_message = 0;
-		    } else {
-			free(buf);
-		    }
+		if (ops->handle_msg_event) {
+		    ops->handle_msg_event(opdata,
+			    OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED,
+			    context, plainmsg, (gcry_error_t)NULL);
 		}
+		free(*newmessagep);
+		*newmessagep = NULL;
+		edata.ignore_message = 1;
 	    }
 	    break;
 
 	case OTRL_MSGTYPE_UNKNOWN:
 	    /* We received an OTR message we didn't recognize.  Ignore
 	     * it, but make a log entry. */
-	    if (ops->log_message) {
-		const char *format = "Unrecognized OTR message received "
-		    "from %s.\n";
-		char *buf = malloc(strlen(format) + strlen(sender) - 1);
-		if (buf) {
-		    sprintf(buf, format, sender);
-		    ops->log_message(opdata, buf);
-		    free(buf);
-		}
+	    if (ops->handle_msg_event) {
+		ops->handle_msg_event(opdata,
+			OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED,
+			context, NULL, (gcry_error_t)NULL);
 	    }
 	    if (edata.ignore_message == -1) edata.ignore_message = 1;
 	    break;
@@ -1517,76 +1561,6 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
     return edata.ignore_message;
 }
 
-/* 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. */
-gcry_error_t otrl_message_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 (otrl_api_version >= 0x030100 && 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 fragment_count = ((msglen - 1) / (mms -19)) + 1;
-		/* like ceil(msglen/(mms - 19)) */
-
-	    err = otrl_proto_fragment_create(mms, fragment_count, &fragments,
-		    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. */
-		int l = strlen(message) + 1;
-		*returnFragment = malloc(sizeof(char)*l);
-		strcpy(*returnFragment, message);
-	    }
-	}
-    }
-    return gcry_error(GPG_ERR_NO_ERROR);
-}
-
 /* 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. */
@@ -1600,7 +1574,7 @@ void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops,
     if (!context) return;
 
     if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
-	    context->their_keyid > 0 &&
+	    context->context_priv->their_keyid > 0 &&
 	    ops->is_logged_in &&
 	    ops->is_logged_in(opdata, accountname, protocol, username) == 1) {
 	if (ops->inject_message) {
@@ -1638,7 +1612,7 @@ gcry_error_t otrl_message_symkey(OtrlUserState us,
     }
 
     if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
-	    context->their_keyid > 0) {
+	    context->context_priv->their_keyid > 0) {
 	unsigned char *tlvdata = malloc(usedatalen+4);
 	char *encmsg = NULL;
 	gcry_error_t err;
diff --git a/src/message.h b/src/message.h
index c3b60e1..f2d1c7a 100644
--- a/src/message.h
+++ b/src/message.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
@@ -20,8 +21,19 @@
 #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,
@@ -32,6 +44,26 @@ typedef enum {
     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
+} OtrlMessageEvent;
+
 typedef enum {
     OTRL_NOTIFY_ERROR,
     OTRL_NOTIFY_WARNING,
@@ -61,33 +93,10 @@ typedef struct s_OtrlMessageAppOps {
     void (*inject_message)(void *opdata, const char *accountname,
 	    const char *protocol, const char *recipient, const char *message);
 
-    /* Display a notification message for a particular accountname /
-     * protocol / username conversation. */
-    void (*notify)(void *opdata, OtrlNotifyLevel level,
-	    const char *accountname, const char *protocol,
-	    const char *username, const char *title,
-	    const char *primary, const char *secondary);
-
-    /* Display an OTR control message for a particular accountname /
-     * protocol / username conversation.  Return 0 if you are able to
-     * successfully display it.  If you return non-0 (or if this
-     * function is NULL), the control message will be displayed inline,
-     * as a received message, or else by using the above notify()
-     * callback. */
-    int (*display_otr_message)(void *opdata, const char *accountname,
-	    const char *protocol, const char *username, const char *msg);
-
     /* 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);
 
-    /* Return a newly allocated string containing a human-friendly name
-     * for the given protocol id */
-    const char *(*protocol_name)(void *opdata, const char *protocol);
-
-    /* Deallocate a string allocated by protocol_name */
-    void (*protocol_name_free)(void *opdata, const char *protocol_name);
-
     /* A new fingerprint for the given user has been received. */
     void (*new_fingerprint)(void *opdata, OtrlUserState us,
 	    const char *accountname, const char *protocol,
@@ -106,9 +115,6 @@ typedef struct s_OtrlMessageAppOps {
      * already knew.  is_reply indicates whether we initiated the AKE. */
     void (*still_secure)(void *opdata, ConnContext *context, int is_reply);
 
-    /* Log a message.  The passed message will end in "\n". */
-    void (*log_message)(void *opdata, const char *message);
-
     /* Find the maximum message size supported by this protocol. */
     int (*max_message_size)(void *opdata, ConnContext *context);
 
@@ -128,12 +134,104 @@ typedef struct s_OtrlMessageAppOps {
     void (*received_symkey)(void *opdata, ConnContext *context,
 	    unsigned int use, const unsigned char *usedata,
 	    size_t usedatalen, const unsigned char *symkey);
-    
-    /* Update the auth UI with respect to SMP events */
+
+    /* 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 'smessage' will
+     *      also be passed and it will contain the plaintext message.
+     * - OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED
+     *      Cannot recognize the type of OTR message received.
+     * */
+    void (*handle_msg_event)(void *opdata, OtrlMessageEvent msg_event,
+                ConnContext *context, const char *message,
+                gcry_error_t err);
 } OtrlMessageAppOps;
 
 /* Deallocate a message allocated by other otrl_message_* routines. */
@@ -146,24 +244,36 @@ void otrl_message_free(char *message);
  * 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.  
+ * 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 this 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.  Call otrl_message_free(*messagep) when you're
+ * convert_msg is a function that will be called on each msg to be sent. You
+ * can use it to perform some tweaks on your outgoing messages.
+ *
+ * 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, const char *message, OtrlTLV *tlvs,
-	char **messagep,
+	const char *recipient, char **original_msgp, OtrlTLV *tlvs,
+	char **messagep, OtrlFragmentPolicy fragPolicy,
+	void (*convert_msg)(void *convert_data, const char *source, char **target),
+	void *convert_data,
 	void (*add_appdata)(void *data, ConnContext *context),
 	void *data);
 
@@ -174,7 +284,10 @@ gcry_error_t otrl_message_sending(OtrlUserState us,
  * 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.  
+ * can pass NULL for the last two arguments of otrl_message_receiving.
+ *
+ * convert_msg is a function that will be called on each msg that is received.
+ * You can use it to perform some tweaks on your incoming messages.
  *
  * If otrl_message_receiving returns 1, then the message you received
  * was an internal protocol message, and no message should be delivered
@@ -195,16 +308,11 @@ 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,
+	void (*convert_msg)(void *convert_data, const char *source, char **target),
+	void *convert_data,
 	void (*add_appdata)(void *data, ConnContext *context),
 	void *data);
 
-/* 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. */
-gcry_error_t otrl_message_fragment_and_send(const OtrlMessageAppOps *ops,
-	void *opdata, ConnContext *context, const char *message,
-	OtrlFragmentPolicy fragPolicy, char **returnFragment);
-
 /* 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. */
diff --git a/src/privkey-t.h b/src/privkey-t.h
index 92f23e6..bda064e 100644
--- a/src/privkey-t.h
+++ b/src/privkey-t.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/privkey.c b/src/privkey.c
index b25cbc0..6e58f80 100644
--- a/src/privkey.c
+++ b/src/privkey.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/privkey.h b/src/privkey.h
index 686f04a..200168e 100644
--- a/src/privkey.h
+++ b/src/privkey.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/proto.c b/src/proto.c
index 561fd95..f5e3980 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
@@ -90,33 +91,33 @@ static gcry_error_t reveal_macs(ConnContext *context,
 	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->numsavedkeys + numnew;
-    newmacs = realloc(context->saved_mac_keys,
+    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->numsavedkeys * 20, sess1->rcvmackey, 20);
-	context->numsavedkeys++;
+	memmove(newmacs + context->context_priv->numsavedkeys * 20, sess1->rcvmackey, 20);
+	context->context_priv->numsavedkeys++;
     }
     if (sess1->sendmacused) {
-	memmove(newmacs + context->numsavedkeys * 20, sess1->sendmackey, 20);
-	context->numsavedkeys++;
+	memmove(newmacs + context->context_priv->numsavedkeys * 20, sess1->sendmackey, 20);
+	context->context_priv->numsavedkeys++;
     }
     if (sess2->rcvmacused) {
-	memmove(newmacs + context->numsavedkeys * 20, sess2->rcvmackey, 20);
-	context->numsavedkeys++;
+	memmove(newmacs + context->context_priv->numsavedkeys * 20, sess2->rcvmackey, 20);
+	context->context_priv->numsavedkeys++;
     }
     if (sess2->sendmacused) {
-	memmove(newmacs + context->numsavedkeys * 20, sess2->sendmackey, 20);
-	context->numsavedkeys++;
+	memmove(newmacs + context->context_priv->numsavedkeys * 20, sess2->sendmackey, 20);
+	context->context_priv->numsavedkeys++;
     }
-    context->saved_mac_keys = newmacs;
+    context->context_priv->saved_mac_keys = newmacs;
 
     return gcry_error(GPG_ERR_NO_ERROR);
 }
@@ -128,39 +129,43 @@ static gcry_error_t rotate_dh_keys(ConnContext *context)
     gcry_error_t err;
 
     /* Rotate the keypair */
-    otrl_dh_keypair_free(&(context->our_old_dh_key));
-    memmove(&(context->our_old_dh_key), &(context->our_dh_key),
-	    sizeof(DH_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->sesskeys[1][0]),
-	    &(context->sesskeys[1][1]));
+    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->sesskeys[1][0]));
-    otrl_dh_session_free(&(context->sesskeys[1][1]));
-    memmove(&(context->sesskeys[1][0]), &(context->sesskeys[0][0]),
-	    sizeof(DH_sesskeys));
-    memmove(&(context->sesskeys[1][1]), &(context->sesskeys[0][1]),
-	    sizeof(DH_sesskeys));
+    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->our_dh_key));
-    context->our_keyid++;
+    otrl_dh_gen_keypair(DH1536_GROUP_ID, &(context->context_priv->our_dh_key));
+    context->context_priv->our_keyid++;
 
     /* Make the session keys */
-    if (context->their_y) {
-	err = otrl_dh_session(&(context->sesskeys[0][0]),
-		&(context->our_dh_key), context->their_y);
+    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->sesskeys[0][0]));
+	otrl_dh_session_blank(&(context->context_priv->sesskeys[0][0]));
     }
-    if (context->their_old_y) {
-	err = otrl_dh_session(&(context->sesskeys[0][1]),
-		&(context->our_dh_key), context->their_old_y);
+    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->sesskeys[0][1]));
+	otrl_dh_session_blank(&(context->context_priv->sesskeys[0][1]));
     }
     return gcry_error(GPG_ERR_NO_ERROR);
 }
@@ -172,30 +177,32 @@ 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->their_old_y);
-    context->their_old_y = context->their_y;
+    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->sesskeys[0][1]),
-	    &(context->sesskeys[1][1]));
+    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->sesskeys[0][1]));
-    otrl_dh_session_free(&(context->sesskeys[1][1]));
-    memmove(&(context->sesskeys[0][1]), &(context->sesskeys[0][0]),
-	    sizeof(DH_sesskeys));
-    memmove(&(context->sesskeys[1][1]), &(context->sesskeys[1][0]),
-	    sizeof(DH_sesskeys));
+    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->their_y = gcry_mpi_copy(new_y);
-    context->their_keyid++;
+    context->context_priv->their_y = gcry_mpi_copy(new_y);
+    context->context_priv->their_keyid++;
 
     /* Make the session keys */
-    err = otrl_dh_session(&(context->sesskeys[0][0]),
-	    &(context->our_dh_key), context->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;
-    err = otrl_dh_session(&(context->sesskeys[1][0]),
-	    &(context->our_old_dh_key), context->their_y);
+    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);
@@ -373,9 +380,9 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
     unsigned char *buf = NULL;
     unsigned char *bufp;
     size_t lenp;
-    DH_sesskeys *sess = &(context->sesskeys[1][0]);
+    DH_sesskeys *sess = &(context->context_priv->sesskeys[1][0]);
     gcry_error_t err;
-    size_t reveallen = 20 * context->numsavedkeys;
+    size_t reveallen = 20 * context->context_priv->numsavedkeys;
     size_t base64len;
     char *base64buf = NULL;
     unsigned char *msgbuf = NULL;
@@ -385,7 +392,7 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
 
     /* Make sure we're actually supposed to be able to encrypt */
     if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED ||
-	    context->their_keyid == 0) {
+	    context->context_priv->their_keyid == 0) {
 	return gcry_error(GPG_ERR_CONFLICT);
     }
 
@@ -403,7 +410,8 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
      * len of revealed mac keys, revealed mac keys, MAC */
     buflen = 3 + (version == 2 ? 1 : 0) + 4 + 4 + 8 + 4 + msglen +
 	4 + reveallen + 20;
-    gcry_mpi_print(format, NULL, 0, &pubkeylen, context->our_dh_key.pub);
+    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);
@@ -429,12 +437,12 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
 	bufp[0] = flags;
 	bufp += 1; lenp -= 1;
     }
-    write_int(context->our_keyid-1);                    /* sender keyid */
+    write_int(context->context_priv->our_keyid-1);                /* sender keyid */
     debug_int("Sender keyid", bufp-4);
-    write_int(context->their_keyid);                    /* recipient keyid */
+    write_int(context->context_priv->their_keyid);                /* recipient keyid */
     debug_int("Recipient keyid", bufp-4);
 
-    write_mpi(context->our_dh_key.pub, pubkeylen, "Y");      /* Y */
+    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) */
@@ -465,12 +473,12 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
     debug_int("Revealed MAC length", bufp-4);
 
     if (reveallen > 0) {
-	memmove(bufp, context->saved_mac_keys, reveallen);
+	memmove(bufp, context->context_priv->saved_mac_keys, reveallen);
 	debug_data("Revealed MAC data", bufp, reveallen);
 	bufp += reveallen; lenp -= reveallen;
-	free(context->saved_mac_keys);
-	context->saved_mac_keys = NULL;
-	context->numsavedkeys = 0;
+	free(context->context_priv->saved_mac_keys);
+	context->context_priv->saved_mac_keys = NULL;
+	context->context_priv->numsavedkeys = 0;
     }
 
     assert(lenp == 0);
@@ -490,21 +498,13 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
     free(buf);
     gcry_free(msgbuf);
     *encmessagep = base64buf;
-    gcry_free(context->lastmessage);
-    context->lastmessage = NULL;
-    context->may_retransmit = 0;
+    gcry_free(context->context_priv->lastmessage);
+    context->context_priv->lastmessage = NULL;
+    context->context_priv->may_retransmit = 0;
     if (msglen > 0) {
-	const char *prefix = "[resent] ";
-	size_t prefixlen = strlen(prefix);
-	if (!strncmp(prefix, msgdup, prefixlen)) {
-	    /* The prefix is already there.  Don't add it again. */
-	    prefix = "";
-	    prefixlen = 0;
-	}
-	context->lastmessage = gcry_malloc_secure(prefixlen + justmsglen + 1);
-	if (context->lastmessage) {
-	    strcpy(context->lastmessage, prefix);
-	    strcat(context->lastmessage, msgdup);
+	context->context_priv->lastmessage = gcry_malloc_secure(justmsglen + 1);
+	if (context->context_priv->lastmessage) {
+	    strcpy(context->context_priv->lastmessage, msgdup);
 	}
     }
     gcry_free(msgdup);
@@ -674,24 +674,24 @@ gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
     /* 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->their_keyid == 0 ||
-	    (sender_keyid != context->their_keyid &&
-		sender_keyid != context->their_keyid - 1) ||
-	    (recipient_keyid != context->our_keyid &&
-	     recipient_keyid != context->our_keyid - 1) ||
+    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->their_keyid - 1 &&
-	    context->their_old_y == NULL) {
+    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->sesskeys
-	    [context->our_keyid - recipient_keyid]
-	    [context->their_keyid - sender_keyid]);
+    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);
@@ -723,13 +723,13 @@ gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
 
     /* See if either set of keys needs rotating */
 
-    if (recipient_keyid == context->our_keyid) {
+    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->their_keyid) {
+    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;
@@ -778,70 +778,70 @@ OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep,
 	    if (k == 1) {
 		int fraglen = end - start - 1;
 		size_t newsize = fraglen + 1;
-		free(context->fragment);
-		context->fragment = NULL;
+		free(context->context_priv->fragment);
+		context->context_priv->fragment = NULL;
 		if (newsize > fraglen) {  /* Check for overflow */
-		    context->fragment = malloc(newsize);
+		    context->context_priv->fragment = malloc(newsize);
 		}
-		if (context->fragment) {
-		    memmove(context->fragment, tag + start, fraglen);
-		    context->fragment_len = fraglen;
-		    context->fragment[context->fragment_len] = '\0';
-		    context->fragment_n = n;
-		    context->fragment_k = k;
+		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->fragment_len = 0;
-		    context->fragment_n = 0;
-		    context->fragment_k = 0;
+		    context->context_priv->fragment_len = 0;
+		    context->context_priv->fragment_n = 0;
+		    context->context_priv->fragment_k = 0;
 		}
-	    } else if (n == context->fragment_n &&
-		    k == context->fragment_k + 1) {
+	    } else if (n == context->context_priv->fragment_n &&
+		    k == context->context_priv->fragment_k + 1) {
 		int fraglen = end - start - 1;
 		char *newfrag = NULL;
-		size_t newsize = context->fragment_len + fraglen + 1;
+		size_t newsize = context->context_priv->fragment_len + fraglen + 1;
 		if (newsize > fraglen) {  /* Check for overflow */
-		    newfrag = realloc(context->fragment, newsize);
+		    newfrag = realloc(context->context_priv->fragment, newsize);
 		}
 		if (newfrag) {
-		    context->fragment = newfrag;
-		    memmove(context->fragment + context->fragment_len,
+		    context->context_priv->fragment = newfrag;
+		    memmove(context->context_priv->fragment + context->context_priv->fragment_len,
 			    tag + start, fraglen);
-		    context->fragment_len += fraglen;
-		    context->fragment[context->fragment_len] = '\0';
-		    context->fragment_k = k;
+		    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->fragment);
-		    context->fragment = NULL;
-		    context->fragment_len = 0;
-		    context->fragment_n = 0;
-		    context->fragment_k = 0;
+		    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->fragment);
-		context->fragment = NULL;
-		context->fragment_len = 0;
-		context->fragment_n = 0;
-		context->fragment_k = 0;
+		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->fragment_n > 0 &&
-		context->fragment_n == context->fragment_k) {
+	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->fragment;
-	    context->fragment = NULL;
-	    context->fragment_len = 0;
-	    context->fragment_n = 0;
-	    context->fragment_k = 0;
+	    *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;
 	}
     } else {
 	/* Unfragmented message, so discard any fragment we may have */
-	free(context->fragment);
-	context->fragment = NULL;
-	context->fragment_len = 0;
-	context->fragment_n = 0;
-	context->fragment_k = 0;
+	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;
     }
 
@@ -861,7 +861,7 @@ gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count,
 
     char **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.
      */
@@ -882,7 +882,7 @@ gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count,
     	}
     	strncpy(fragdata, message, fragdatalen);
     	fragdata[fragdatalen] = 0;
-    	
+
     	fragmentmsg = malloc(fragdatalen+headerlen+1);
     	if(!fragmentmsg) {
 	    for (i=0; i<curfrag-1; free(fragmentarray[i++])) {}
@@ -891,19 +891,19 @@ gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count,
     	    return gcry_error(GPG_ERR_ENOMEM);
     	}
 
-    	/* 
+    	/*
     	 * Create the actual fragment and store it in the array
     	 */
     	snprintf(fragmentmsg, fragdatalen + headerlen, "?OTR,%05hu,%05hu,%s,", curfrag, 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);
 }
diff --git a/src/proto.h b/src/proto.h
index 4a60098..afd74fe 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
@@ -87,7 +88,8 @@ typedef enum {
 typedef enum {
     OTRL_FRAGMENT_SEND_ALL,
     OTRL_FRAGMENT_SEND_ALL_BUT_FIRST,
-    OTRL_FRAGMENT_SEND_ALL_BUT_LAST
+    OTRL_FRAGMENT_SEND_ALL_BUT_LAST,
+    OTRL_FRAGMENT_SEND_SKIP
 } OtrlFragmentPolicy;
 
 /* Initialize the OTR library.  Pass the version of the API you are
diff --git a/src/serial.h b/src/serial.h
index edc3184..439a271 100644
--- a/src/serial.h
+++ b/src/serial.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/sm.c b/src/sm.c
index 535ae22..f3bcbd0 100644
--- a/src/sm.c
+++ b/src/sm.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/sm.h b/src/sm.h
index 2e94f07..2e44b46 100644
--- a/src/sm.h
+++ b/src/sm.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/tlv.c b/src/tlv.c
index 0cea7b5..687051b 100644
--- a/src/tlv.c
+++ b/src/tlv.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/tlv.h b/src/tlv.h
index b5822b5..f1c3436 100644
--- a/src/tlv.h
+++ b/src/tlv.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/userstate.c b/src/userstate.c
index 5ce5f5a..51d543c 100644
--- a/src/userstate.c
+++ b/src/userstate.c
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/userstate.h b/src/userstate.h
index 9815714..2f0106a 100644
--- a/src/userstate.h
+++ b/src/userstate.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/src/version.h b/src/version.h
index 78acf17..d755018 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,6 +1,7 @@
 /*
  *  Off-the-Record Messaging library
- *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
+ *  Copyright (C) 2004-2009  Ian Goldberg, Chris Alexander, Willy Lew,
+ *  			     Nikita Borisov
  *                           <otr at cypherpunks.ca>
  *
  *  This library is free software; you can redistribute it and/or

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



More information about the Pkg-privacy-commits mailing list