adding a keystore for otr, adding buttons which display fingerprints
authorNikita Kozlov <nikita@beem-project.com>
Sat, 16 Apr 2011 19:43:53 +0200
changeset 900 ab30d289a86c
parent 899 9443da4a7fb7
child 901 6c77794969c5
adding a keystore for otr, adding buttons which display fingerprints
res/menu/chat.xml
res/values/strings.xml
src/com/beem/project/beem/otr/BeemOtrManager.java
src/com/beem/project/beem/service/ChatAdapter.java
src/com/beem/project/beem/service/aidl/IChat.aidl
src/com/beem/project/beem/ui/Chat.java
src/net/java/otr4j/OtrKeyManagerImpl.java
--- a/res/menu/chat.xml	Fri Apr 15 23:58:06 2011 +0200
+++ b/res/menu/chat.xml	Sat Apr 16 19:43:53 2011 +0200
@@ -13,4 +13,8 @@
 		android:title="@string/chat_menu_listen_otr_session" />
 	<item android:id="@+id/chat_menu_stop_otr_session" android:visible="true"
 		android:title="@string/chat_menu_stop_otr_session" />
+	<item android:id="@+id/chat_menu_otr_local_key" android:visible="true"
+		android:title="@string/chat_menu_otr_local_key" />
+	<item android:id="@+id/chat_menu_otr_remote_key" android:visible="true"
+		android:title="@string/chat_menu_otr_remote_key" />
 </menu>
--- a/res/values/strings.xml	Fri Apr 15 23:58:06 2011 +0200
+++ b/res/values/strings.xml	Sat Apr 16 19:43:53 2011 +0200
@@ -274,6 +274,8 @@
 	<string name="chat_menu_start_otr_session">Start OTR session</string>
 	<string name="chat_menu_listen_otr_session">Listen for OTR session</string>
 	<string name="chat_menu_stop_otr_session">Stop OTR session</string>
+	<string name="chat_menu_otr_local_key">OTR local key</string>
+	<string name="chat_menu_otr_remote_key">OTR remote key</string>
 	<string name="chat_dialog_change_chat_title">Opened chats</string>
 	<string name="chat_menu_close_chat">Close this chat</string>
 	<string name="chat_no_more_chats">No more active chats</string>
@@ -284,6 +286,8 @@
 	<string name="chat_otrstate_plaintext">PLAINTEXT</string>
 	<string name="chat_otrstate_encrypted">ENCRYPTED</string>
 	<string name="chat_otrstate_finished">FINISHED</string>
+	<string name="chat_otr_verify_key">Verify remote fingerprint %s ?</string>
+	<string name="chat_otr_local_key">Local fingerprint %s </string>
 
 	<string name="contact_status_msg_available">Available</string>
 	<string name="contact_status_msg_available_chat">Available to chat</string>
--- a/src/com/beem/project/beem/otr/BeemOtrManager.java	Fri Apr 15 23:58:06 2011 +0200
+++ b/src/com/beem/project/beem/otr/BeemOtrManager.java	Sat Apr 16 19:43:53 2011 +0200
@@ -1,9 +1,33 @@
+/*
+    BEEM is a videoconference application on the Android Platform.
+
+    Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+                               Nikita Kozlov,
+                               Vincent Veronis.
+
+    This file is part of BEEM.
+
+    BEEM is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    BEEM is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with BEEM.  If not, see <http://www.gnu.org/licenses/>.
+
+    Please send bug reports with examples or suggestions to
+    contact@beem-project.com or http://www.beem-project.com/
+
+ */
 package com.beem.project.beem.otr;
 
 import java.io.IOException;
 import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -11,113 +35,142 @@
 import net.java.otr4j.OtrEngineHost;
 import net.java.otr4j.OtrEngineImpl;
 import net.java.otr4j.OtrEngineListener;
+import net.java.otr4j.OtrException;
 import net.java.otr4j.OtrKeyManagerImpl;
 import net.java.otr4j.OtrPolicy;
 import net.java.otr4j.OtrPolicyImpl;
 import net.java.otr4j.session.SessionID;
+import net.java.otr4j.session.SessionStatus;
+import android.os.RemoteException;
 import android.util.Log;
 
 import com.beem.project.beem.service.ChatAdapter;
-
+/**
+ * BeemOtrManager.
+ */
 public class BeemOtrManager implements OtrEngineHost {
 
-	private static final String TAG = "BeemOtrEngineHostImpl";
-	private static BeemOtrManager INSTANCE;
+    private static final String TAG = "BeemOtrEngineHostImpl";
+    private static BeemOtrManager INSTANCE;
+    //We will have a global policy for Beem as long as we won't need to modify the policy per chat.
+    private static final OtrPolicy mGlobalPolicy = new OtrPolicyImpl(OtrPolicy.ALLOW_V2 | OtrPolicy.ERROR_START_AKE);
+
 
-	private OtrEngine mOtrEngine;
-	private OtrKeyManagerImpl mOtrKeyManager;
+    private OtrEngine mOtrEngine;
+    private OtrKeyManagerImpl mOtrKeyManager;
+
+    //Map of chat, needed because of the message injection
+    private final Map<SessionID, ChatAdapter> mChats = new HashMap<SessionID, ChatAdapter>();
 
-	//Map of chat, needed because of the message injection
-	private final Map<SessionID, ChatAdapter> mChats = new HashMap<SessionID, ChatAdapter>();
+    /**
+     * Private constructor prevents instantiation from other classes.
+     */
+    private BeemOtrManager() {
+	mOtrEngine = new OtrEngineImpl(this);
+	mOtrEngine.addOtrEngineListener(new BeemOtrListener());
+	try {
+	    mOtrKeyManager = new OtrKeyManagerImpl("/sdcard/beem.keystore");
+	} catch (IOException e) {
+	    e.printStackTrace();
+	}
+    }
 
-	//We will have a global policy for Beem as long as we won't need to modify the policy per chat.
-	private static final OtrPolicy mGlobalPolicy = new OtrPolicyImpl(OtrPolicy.ALLOW_V2 | OtrPolicy.ERROR_START_AKE);
-
+    /**
+     * getOtrManager.
+     * @return OtrEngine
+     */
+    public OtrEngine getOtrManager() {
+	return mOtrEngine;
+    }
 
 
-	private Map<SessionID, KeyPair> mKeys = new HashMap<SessionID, KeyPair>();
-
-	public OtrEngine getOtrManager() {
-		return mOtrEngine;
-	}
+    /**
+     * BeemOtrManager.getInstance.
+     * @return BeemOtrManager
+     */
+    public static BeemOtrManager getInstance() {
+	if (INSTANCE == null)
+	    INSTANCE = new BeemOtrManager();
+	return INSTANCE;
+    }
 
-	// Private constructor prevents instantiation from other classes
-	private BeemOtrManager() {  
-		mOtrEngine = new OtrEngineImpl(this);;
-		mOtrEngine.addOtrEngineListener(new BeemOtrListener());
-		try {
-			mOtrKeyManager = new OtrKeyManagerImpl("/sdcard/beem.keystore");
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-	}
+    /**
+     * We must call addChat before stating a new otr session because we will need the chat instance for message injection.
+     * @param sessionID the otr sessionID.
+     * @param chat instance.
+     */
+    public void addChat(final SessionID sessionID, final ChatAdapter chat) {
+	mChats.put(sessionID, chat);
+	Log.d(TAG, "adding new OTR session " + sessionID);
+    }
+
+    /**
+     * We must remove the chat from the map after we ended the corresponding otr session.
+     * @param sessionID the otr sessionID to remove.
+     */
+    public void removeChat(final SessionID sessionID) {
+	mChats.remove(sessionID);
+    }
+
+    public String getRemoteFingerprint(final SessionID sessionID) {
+	return mOtrKeyManager.getRemoteFingerprint(sessionID);
+    }
+
+    public String getLocalFingerprint(final SessionID sessionID) {
+	return mOtrKeyManager.getLocalFingerprint(sessionID);
+    }
 
-	public static BeemOtrManager getInstance() {
-		if (INSTANCE == null)
-			INSTANCE = new BeemOtrManager();
-		return INSTANCE;
-	}
+    @Override
+    public void injectMessage(SessionID sessionID, String msg) {
+	ChatAdapter chat = mChats.get(sessionID);
+	chat.sendMessage(msg);
+    }
+
+    @Override
+    public void showWarning(SessionID sessionID, String warning) {
+	Log.d(TAG, "Warning for " + sessionID + " : " + warning);
+    }
+
+    @Override
+    public void showError(SessionID sessionID, String error) {
+	Log.d(TAG, "Error for " + sessionID + " : " + error);
+    }
 
-	/*
-	 * We must call addChat before stating a new otr session because we will need the chat instance for message injection
-	 */
-	public void addChat(final SessionID sessionID, final ChatAdapter chat) {
-		mChats.put(sessionID, chat);
-	}
+    @Override
+    public OtrPolicy getSessionPolicy(SessionID sessionID) {
+	return mGlobalPolicy;
+    }
+
+    @Override
+    public KeyPair getKeyPair(SessionID sessionID) {	
+	KeyPair kp = mOtrKeyManager.loadLocalKeyPair(sessionID);
 
-	/*
-	 * We must remove the chat from the map after we ended the corresponding otr session.
-	 */
-	public void removeChat(final SessionID sessionID) {
-		mChats.remove(sessionID);
-	}
+	if(kp != null)
+	    return kp;
+
+	mOtrKeyManager.generateLocalKeyPair(sessionID);	
+	return mOtrKeyManager.loadLocalKeyPair(sessionID);
+    }
+
+    /**
+     * BeemOtrListener.
+     */
+    private class BeemOtrListener implements OtrEngineListener {
 
 	@Override
-	public void injectMessage(SessionID sessionID, String msg) {
-		ChatAdapter chat = mChats.get(sessionID);
-		chat.sendMessage(msg);		
-	}
-
-	@Override
-	public void showWarning(SessionID sessionID, String warning) {
-		Log.d(TAG, "Warning for "+sessionID + " : "+warning);
-	}
-
-	@Override
-	public void showError(SessionID sessionID, String error) {
-		Log.d(TAG, "Error for "+sessionID + " : "+error);
-	}
-
-	@Override
-	public OtrPolicy getSessionPolicy(SessionID sessionID) {
-		return mGlobalPolicy;
+	public void sessionStatusChanged(final SessionID sessionID) {
+	    Log.d(TAG, "OTR Status changed for " + sessionID + " : " + mOtrEngine.getSessionStatus(sessionID));
+	    if (mOtrKeyManager.loadRemotePublicKey(sessionID) == null) {
+		mOtrKeyManager.savePublicKey(sessionID, mOtrEngine.getRemotePublicKey(sessionID));
+	    }
+	    mChats.get(sessionID).otrStateChanged(mOtrEngine.getSessionStatus(sessionID).toString());
+	    if(mOtrEngine.getSessionStatus(sessionID) == SessionStatus.FINISHED) {
+		try {
+		    mChats.get(sessionID).localEndOtrSession();
+		} catch (OtrException e) {
+		    e.printStackTrace();
+		}
+	    }
 	}
-
-	@Override
-	public KeyPair getKeyPair(SessionID sessionID) {	
-		KeyPair key = mKeys.get(sessionID);
-
-		if (key == null) {
-			KeyPairGenerator kg;
-			try {
-				kg = KeyPairGenerator.getInstance("DSA");
-				key = kg.genKeyPair();
-				mKeys.put(sessionID, key);
-			} catch (NoSuchAlgorithmException e) {
-				e.printStackTrace();
-				return null;
-			}
-		}
-
-		return key;
-	}
-
-	private class BeemOtrListener implements OtrEngineListener {
-
-		@Override
-		public void sessionStatusChanged(final SessionID sessionID) {
-			Log.d(TAG, "OTR Status changed for " + sessionID + " : " + mOtrEngine.getSessionStatus(sessionID));
-			mChats.get(sessionID).otrStateChanged(mOtrEngine.getSessionStatus(sessionID).toString());	
-		}
-	}
+    }
 }
--- a/src/com/beem/project/beem/service/ChatAdapter.java	Fri Apr 15 23:58:06 2011 +0200
+++ b/src/com/beem/project/beem/service/ChatAdapter.java	Sat Apr 16 19:43:53 2011 +0200
@@ -58,11 +58,11 @@
 import org.jivesoftware.smack.util.StringUtils;
 import org.jivesoftware.smackx.ChatState;
 import org.jivesoftware.smackx.ChatStateListener;
-import org.jivesoftware.smackx.ChatState;
 
 import android.os.Environment;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.util.AndroidException;
 import android.util.Log;
 
 import com.beem.project.beem.otr.BeemOtrManager;
@@ -74,19 +74,19 @@
  * @author darisk
  */
 public class ChatAdapter extends IChat.Stub {
-	private static final int HISTORY_MAX_SIZE = 50;
-	private static final String TAG = "ChatAdapter";
-	private static final String PROTOCOL = "XMPP";
+    private static final int HISTORY_MAX_SIZE = 50;
+    private static final String TAG = "ChatAdapter";
+    private static final String PROTOCOL = "XMPP";
 
-	private final Chat mAdaptee;
-	private final Contact mParticipant;
-	private String mState;
-	private boolean mIsOpen;
-	private final List<Message> mMessages;
-	private final RemoteCallbackList<IMessageListener> mRemoteListeners = new RemoteCallbackList<IMessageListener>();
-	private final MsgListener mMsgListener = new MsgListener();
-	private SessionID mOtrSessionId;
-	private boolean mIsHistory;
+    private final Chat mAdaptee;
+    private final Contact mParticipant;
+    private String mState;
+    private boolean mIsOpen;
+    private final List<Message> mMessages;
+    private final RemoteCallbackList<IMessageListener> mRemoteListeners = new RemoteCallbackList<IMessageListener>();
+    private final MsgListener mMsgListener = new MsgListener();
+    private SessionID mOtrSessionId;
+    private boolean mIsHistory;
     private File mHistoryPath;
     private String mAccountUser;
 
@@ -119,15 +119,15 @@
 	send.setTo(message.getTo());
 	Log.w(TAG, "message to " + message.getTo());
 
-		if (mOtrSessionId != null) {
-			String body;
-			try {
-				body = BeemOtrManager.getInstance().getOtrManager().transformSending(mOtrSessionId, msgBody);
-				msgBody = body;
-			} catch (OtrException e) {
-				e.printStackTrace();
-			}
-		}
+	if (mOtrSessionId != null) {
+	    String body;
+	    try {
+		body = BeemOtrManager.getInstance().getOtrManager().transformSending(mOtrSessionId, msgBody);
+		msgBody = body;
+	    } catch (OtrException e) {
+		e.printStackTrace();
+	    }
+	}
 
 	send.setBody(msgBody);
 	send.setThread(message.getThread());
@@ -148,17 +148,17 @@
 
     /**
      * send message.
-     * @param msg
+     * @param msg to send.
      */
-	public void sendMessage(String msg) {
-		Message msgToSend = new Message(mParticipant.getJIDWithRes(), Message.MSG_TYPE_CHAT);
-		msgToSend.setBody(msg);
-		try {
-			sendMessage(msgToSend);
-		} catch (RemoteException e) {
-			e.printStackTrace();
-		}
+    public void sendMessage(String msg) {
+	Message msgToSend = new Message(mParticipant.getJIDWithRes(), Message.MSG_TYPE_CHAT);
+	msgToSend.setBody(msg);
+	try {
+	    sendMessage(msgToSend);
+	} catch (RemoteException e) {
+	    e.printStackTrace();
 	}
+    }
 
     /**
      * {@inheritDoc}
@@ -250,16 +250,16 @@
      */
     public void saveHistory(Message msg, String contactName) {
 	File path = getHistoryPath();
-    	File filepath;
-    	if (contactName.equals(msg.getFrom()))
-    	    filepath = new File(path, StringUtils.parseBareAddress(contactName));
-    	else
-    	    filepath = new File(path, StringUtils.parseBareAddress(msg.getTo()));
-    	path.mkdirs();
+	File filepath;
+	if (contactName.equals(msg.getFrom()))
+	    filepath = new File(path, StringUtils.parseBareAddress(contactName));
+	else
+	    filepath = new File(path, StringUtils.parseBareAddress(msg.getTo()));
+	path.mkdirs();
 	try {
 	    FileWriter file = new FileWriter(filepath, true);
 	    String log = msg.getTimestamp() + " " + contactName + " " + msg.getBody()
-		+ System.getProperty("line.separator");
+	    + System.getProperty("line.separator");
 	    file.write(log);
 	    file.close();
 	} catch (IOException e) {
@@ -324,121 +324,142 @@
 	 */
 	public MsgListener() { }
 
-		@Override
-		public void processMessage(Chat chat, org.jivesoftware.smack.packet.Message message) {
-			Message  msg = new Message(message);
-			Log.d(TAG, "new msg " + msg.getBody());
-
-			if (mOtrSessionId != null) {
-				String body;
-				try {
-					body = BeemOtrManager.getInstance().getOtrManager().transformReceiving(mOtrSessionId, msg.getBody());
-					msg.setBody(body);
-				} catch (OtrException e) {
-					e.printStackTrace();
-				}
-			}
+	@Override
+	public void processMessage(Chat chat, org.jivesoftware.smack.packet.Message message) {
+	    Message  msg = new Message(message);
+	    Log.d(TAG, "new msg " + msg.getBody());
 
-			//TODO add que les message pas de type errors
-			ChatAdapter.this.addMessage(msg);
-			final int n = mRemoteListeners.beginBroadcast();
-			for (int i = 0; i < n; i++) {
-				IMessageListener listener = mRemoteListeners.getBroadcastItem(i);
-				try {
-					if (listener != null)
-						listener.processMessage(ChatAdapter.this, msg);
-				} catch (RemoteException e) {
-					Log.w(TAG, "Error while diffusing message to listener", e);
-				}
-			}
-			mRemoteListeners.finishBroadcast();
+	    if (mOtrSessionId != null) {
+		String body;
+		try {
+		    body = BeemOtrManager.getInstance().getOtrManager().transformReceiving(mOtrSessionId, msg.getBody());
+		    msg.setBody(body);
+		} catch (OtrException e) {
+		    e.printStackTrace();
 		}
+	    }
 
-		/**
-		 * {@inheritDoc}
-		 */
-		@Override
-		public void stateChanged(Chat chat, ChatState state) {
-			mState = state.name();
-			final int n = mRemoteListeners.beginBroadcast();
-
-			for (int i = 0; i < n; i++) {
-				IMessageListener listener = mRemoteListeners.getBroadcastItem(i);
-				try {
-					listener.stateChanged(ChatAdapter.this);
-				} catch (RemoteException e) {
-					Log.w(TAG, e.getMessage());
-				}
-			}
-			mRemoteListeners.finishBroadcast();
+	    //TODO add que les message pas de type errors
+	    ChatAdapter.this.addMessage(msg);
+	    final int n = mRemoteListeners.beginBroadcast();
+	    for (int i = 0; i < n; i++) {
+		IMessageListener listener = mRemoteListeners.getBroadcastItem(i);
+		try {
+		    if (listener != null)
+			listener.processMessage(ChatAdapter.this, msg);
+		} catch (RemoteException e) {
+		    Log.w(TAG, "Error while diffusing message to listener", e);
 		}
-
-
+	    }
+	    mRemoteListeners.finishBroadcast();
 	}
+
 	/**
-	 * This method is executed when the otr session status change.
-	 * @param otrState the new state of otr session.
+	 * {@inheritDoc}
 	 */
-	public	void otrStateChanged(final String otrState) {
-		final int n = mRemoteListeners.beginBroadcast();
+	@Override
+	public void stateChanged(Chat chat, ChatState state) {
+	    mState = state.name();
+	    final int n = mRemoteListeners.beginBroadcast();
 
-		if ("FINISHED".equals(otrState)) {
-			BeemOtrManager.getInstance().removeChat(mOtrSessionId);
-			mOtrSessionId = null;
+	    for (int i = 0; i < n; i++) {
+		IMessageListener listener = mRemoteListeners.getBroadcastItem(i);
+		try {
+		    listener.stateChanged(ChatAdapter.this);
+		} catch (RemoteException e) {
+		    Log.w(TAG, e.getMessage());
 		}
-		for (int i = 0; i < n; i++) {
-			IMessageListener listener = mRemoteListeners.getBroadcastItem(i);
-			try {
-				listener.otrStateChanged(otrState);
-			} catch (RemoteException e) {
-				Log.w(TAG, e.getMessage());
-			}
-		}
-		mRemoteListeners.finishBroadcast();
+	    }
+	    mRemoteListeners.finishBroadcast();
 	}
 
 
-	@Override
-	public void startOtrSession() throws RemoteException {
-		if (mOtrSessionId != null)
-			return ;
+    }
+    /**
+     * This method is executed when the otr session status change.
+     * @param otrState the new state of otr session.
+     */
+    public	void otrStateChanged(final String otrState) {
+	final int n = mRemoteListeners.beginBroadcast();
 
-		mOtrSessionId = new SessionID(mParticipant.getJIDWithRes(), mParticipant.getJID(), PROTOCOL);
-		try {
-			BeemOtrManager.getInstance().addChat(mOtrSessionId, this);
-			BeemOtrManager.getInstance().getOtrManager().startSession(mOtrSessionId);
-		} catch (OtrException e) {
-			mOtrSessionId = null;
-			e.printStackTrace();
-			throw new RemoteException();
-		}
+	for (int i = 0; i < n; i++) {
+	    IMessageListener listener = mRemoteListeners.getBroadcastItem(i);
+	    try {
+		listener.otrStateChanged(otrState);
+	    } catch (RemoteException e) {
+		Log.w(TAG, e.getMessage());
+	    }
 	}
+	mRemoteListeners.finishBroadcast();
+    }
 
-	@Override
-	public void endOtrSession() throws RemoteException {
-		if (mOtrSessionId == null)
-			return;
+
+    @Override
+    public void startOtrSession() throws RemoteException {
+	if (mOtrSessionId != null)
+	    return;
+
+	mOtrSessionId = new SessionID(mParticipant.getJIDWithRes(), mParticipant.getJID(), PROTOCOL);
+	try {
+	    BeemOtrManager.getInstance().addChat(mOtrSessionId, this);
+	    BeemOtrManager.getInstance().getOtrManager().startSession(mOtrSessionId);
+	} catch (OtrException e) {
+	    mOtrSessionId = null;
+	    e.printStackTrace();
+	    throw new RemoteException();
+	}
+    }
 
-		try {
-			BeemOtrManager.getInstance().getOtrManager().endSession(mOtrSessionId);
-		} catch (OtrException e) {
-			e.printStackTrace();
-			throw new RemoteException();
-		}
-		BeemOtrManager.getInstance().removeChat(mOtrSessionId);
-		mOtrSessionId = null;
+    @Override
+    public void endOtrSession() throws RemoteException {
+	try {
+	   localEndOtrSession();	        
+	} catch (OtrException e) {
+	    e.printStackTrace();
+	    throw new RemoteException();
 	}
+    }
+    
+    /**
+     * end an Otr session.
+     * @return false if something bad happened.
+     */
+    public boolean localEndOtrSession() throws OtrException {
+	if (mOtrSessionId == null)
+	    return true;
+	
+	BeemOtrManager.getInstance().getOtrManager().endSession(mOtrSessionId);
+	BeemOtrManager.getInstance().removeChat(mOtrSessionId);
+	mOtrSessionId = null;
+	return true;
+    }
 
-	@Override
-	public void listenOtrSession() throws RemoteException {
-		if (mOtrSessionId != null)
-			return;
+    @Override
+    public void listenOtrSession() throws RemoteException {
+	if (mOtrSessionId != null)
+	    return;
+
+	mOtrSessionId = new SessionID(mParticipant.getJIDWithRes(), mParticipant.getJID(), PROTOCOL);
+	BeemOtrManager.getInstance().addChat(mOtrSessionId, this);
+	//OtrEngineImpl will make a call to "this.getSession(sessionID)" which will instantiate our session.
+	BeemOtrManager.getInstance().getOtrManager().getSessionStatus(mOtrSessionId);
+
+    }
 
-		mOtrSessionId = new SessionID(mParticipant.getJIDWithRes(), mParticipant.getJID(), PROTOCOL);
-		BeemOtrManager.getInstance().addChat(mOtrSessionId, this);
-		//OtrEngineImpl will make a call to "this.getSession(sessionID)" which will instantiate our session.
-		BeemOtrManager.getInstance().getOtrManager().getSessionStatus(mOtrSessionId);
+    @Override
+    public String getLocalOtrFingerprint() throws RemoteException {
+	if (mOtrSessionId == null)
+	    return null;
+	
+	return BeemOtrManager.getInstance().getLocalFingerprint(mOtrSessionId);
+    }
 
-	}
+    @Override
+    public String getRemoteOtrFingerprint() throws RemoteException {
+	if (mOtrSessionId == null)
+	    return null;
+	
+	return BeemOtrManager.getInstance().getRemoteFingerprint(mOtrSessionId);
+    }
 }
 
--- a/src/com/beem/project/beem/service/aidl/IChat.aidl	Fri Apr 15 23:58:06 2011 +0200
+++ b/src/com/beem/project/beem/service/aidl/IChat.aidl	Sat Apr 16 19:43:53 2011 +0200
@@ -100,5 +100,17 @@
 	 * Listen for an incoming OTR session.
 	 */
 	void listenOtrSession();
+	
+	/**
+	 * get local OTR key fingerprints.
+	 */
+	String getLocalOtrFingerprint();
+	
+	
+	/**
+	 * get remote OTR key fingerprints.
+	 */
+	String getRemoteOtrFingerprint();
+	
 
 }
--- a/src/com/beem/project/beem/ui/Chat.java	Fri Apr 15 23:58:06 2011 +0200
+++ b/src/com/beem/project/beem/ui/Chat.java	Sat Apr 16 19:43:53 2011 +0200
@@ -43,14 +43,14 @@
 */
 package com.beem.project.beem.ui;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.text.DateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.io.InputStream;
-import java.io.IOException;
 
 import org.jivesoftware.smack.packet.Presence.Mode;
 import org.jivesoftware.smack.util.StringUtils;
@@ -62,11 +62,11 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -84,7 +84,6 @@
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
 import android.view.View.OnKeyListener;
-import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.EditText;
@@ -92,7 +91,6 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-
 import com.beem.project.beem.R;
 import com.beem.project.beem.providers.AvatarProvider;
 import com.beem.project.beem.service.Contact;
@@ -106,6 +104,7 @@
 import com.beem.project.beem.service.aidl.IRoster;
 import com.beem.project.beem.service.aidl.IXmppFacade;
 import com.beem.project.beem.ui.dialogs.builders.ChatList;
+import com.beem.project.beem.ui.dialogs.builders.DisplayOtrFingerprint;
 import com.beem.project.beem.utils.BeemBroadcastReceiver;
 import com.beem.project.beem.utils.Status;
 
@@ -176,8 +175,8 @@
 	    mContactChatState = (TextView) findViewById(R.id.chat_contact_chat_state);
 	    mContactStatusIcon = (ImageView) findViewById(R.id.chat_contact_status_icon);
 	    mAvatarStatusDrawable = (LayerDrawable) mContactStatusIcon.getDrawable();
-		mContactOtrState = (TextView) findViewById(R.id.chat_contact_otr_state);	    
-		mAvatarStatusDrawable.setLayerInset(1, 36, 36, 0, 0);
+	    mContactOtrState = (TextView) findViewById(R.id.chat_contact_otr_state);
+	    mAvatarStatusDrawable.setLayerInset(1, 36, 36, 0, 0);
 	} else {
 	    setContentView(R.layout.chat_compact);
 	}
@@ -308,11 +307,10 @@
 		    Log.e(TAG, e.getMessage());
 		}
 		this.finish();
-		this.finish();
 		break;
 	    case R.id.chat_menu_start_otr_session:
 		try {
-		    Log.d(TAG, "opened otr chats = " + mChat + " for "+mContact);
+		    Log.d(TAG, "opened otr chats = " + mChat + " for " + mContact);
 		    if (mChat == null) {
 			mChat = mChatManager.createChat(mContact, mMessageListener);
 			if (mChat != null) {
@@ -321,12 +319,12 @@
 		    }
 		    mChat.startOtrSession();
 		} catch (RemoteException e) {
-		    Log.e(TAG, e.getMessage());
+		    Log.e(TAG, "start otr chats failed " + mChat , e);
 		}
 		break;
 	    case R.id.chat_menu_listen_otr_session:
 		try {
-		    Log.d(TAG, "listen otr chats = " + mChat + " for "+mContact);
+		    Log.d(TAG, "listen otr chats = " + mChat + " for " + mContact);
 		    if (mChat == null) {
 			mChat = mChatManager.createChat(mContact, mMessageListener);
 			if (mChat != null) {
@@ -335,12 +333,12 @@
 		    }
 		    mChat.listenOtrSession();
 		} catch (RemoteException e) {
-		    Log.e(TAG, e.getMessage());
+		    Log.e(TAG, "listen for otr chats failed " + mChat , e);
 		}
 		break;
 	    case R.id.chat_menu_stop_otr_session:
 		try {
-		    Log.d(TAG, "close otr chats = " + mChat + " for "+mContact);
+		    Log.d(TAG, "close otr chats = " + mChat + " for " + mContact);
 		    if (mChat == null) {
 			mChat = mChatManager.createChat(mContact, mMessageListener);
 			if (mChat != null) {
@@ -349,7 +347,39 @@
 		    }
 		    mChat.endOtrSession();
 		} catch (RemoteException e) {
-		    Log.e(TAG, e.getMessage());
+		    Log.e(TAG, "close otr chats failed " + mChat , e);
+		}
+		break;
+	    case R.id.chat_menu_otr_local_key:
+		try {
+		    if (mChat == null) {
+			mChat = mChatManager.createChat(mContact, mMessageListener);
+			if (mChat != null) {
+			    mChat.setOpen(true);
+			}
+		    }
+		    String fk = mChat.getLocalOtrFingerprint();
+		    Log.d(TAG, "otr chats = " + mChat + " for " + mContact + " fk " + fk);
+		    Dialog otrDialog = new DisplayOtrFingerprint(this, fk, true).create();
+		    otrDialog.show();
+		} catch (RemoteException e) {
+		    Log.e(TAG, "getting local otr key failed " + mChat , e);
+		}
+		break;
+	    case R.id.chat_menu_otr_remote_key:
+		try {
+		    if (mChat == null) {
+			mChat = mChatManager.createChat(mContact, mMessageListener);
+			if (mChat != null) {
+			    mChat.setOpen(true);
+			}
+		    }
+		    String fk = mChat.getRemoteOtrFingerprint();
+		    Log.d(TAG, "otr chats = " + mChat + " for " + mContact + " fk " + fk);
+		    Dialog otrDialog = new DisplayOtrFingerprint(this, fk, false).create();
+		    otrDialog.show();
+		} catch (RemoteException e) {
+		    Log.e(TAG, "getting remote otr key failed " + mChat , e);
 		}
 		break;
 	    default:
@@ -689,7 +719,7 @@
 	    try {
 		try {
 		    in = getContentResolver().openInputStream(uri);
-	    avatarDrawable = Drawable.createFromStream(in, avatarId);
+		    avatarDrawable = Drawable.createFromStream(in, avatarId);
 		} finally {
 		    if (in != null)
 			in.close();
@@ -772,7 +802,7 @@
 	    View sv;
 	    if (convertView == null) {
 		LayoutInflater inflater = Chat.this.getLayoutInflater();
-		    sv = inflater.inflate(R.layout.chat_msg_row, null);
+		sv = inflater.inflate(R.layout.chat_msg_row, null);
 	    } else {
 		sv = convertView;
 	    }
--- a/src/net/java/otr4j/OtrKeyManagerImpl.java	Fri Apr 15 23:58:06 2011 +0200
+++ b/src/net/java/otr4j/OtrKeyManagerImpl.java	Sat Apr 16 19:43:53 2011 +0200
@@ -92,6 +92,8 @@
 
 		public byte[] getPropertyBytes(String id) {
 			String value = properties.getProperty(id);
+			if (value == null)
+			    return null;
 			return Base64.decode(value);
 		}