aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarin <m.dzhigarov@gmail.com>2013-12-20 13:29:16 +0200
committerMarin <m.dzhigarov@gmail.com>2014-01-10 12:35:17 +0200
commitc164b0aa0a2315d9b0c0f32a0fdb4826ebb7ff9d (patch)
tree6d32c02006a10a8f180b9fd7dbe7b35357a22d3b
parent8ac902456870615486df0fbc4bb073695d93a35b (diff)
downloadjitsi-c164b0aa0a2315d9b0c0f32a0fdb4826ebb7ff9d.zip
jitsi-c164b0aa0a2315d9b0c0f32a0fdb4826ebb7ff9d.tar.gz
jitsi-c164b0aa0a2315d9b0c0f32a0fdb4826ebb7ff9d.tar.bz2
Updates the otr plugin to use the latest version of the OTR protocol.
-rw-r--r--lib/installer-exclude/otr4j.jarbin86200 -> 94169 bytes
-rw-r--r--resources/languages/resources.properties4
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java2
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java104
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrActivator.java20
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/otr/OtrConfigurator.java29
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java18
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java25
-rw-r--r--src/net/java/sip/communicator/plugin/otr/OtrWeakListener.java24
-rw-r--r--src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java42
-rw-r--r--src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java140
-rw-r--r--src/net/java/sip/communicator/plugin/otr/ScOtrEngineListener.java4
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java13
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java111
-rw-r--r--src/net/java/sip/communicator/plugin/otr/authdialog/FingerprintAuthenticationPanel.java18
-rw-r--r--src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsPanel.java46
-rw-r--r--src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsTableModel.java94
-rw-r--r--src/net/java/sip/communicator/plugin/otr/authdialog/OtrBuddyAuthenticationDialog.java14
-rw-r--r--src/net/java/sip/communicator/plugin/otr/authdialog/OtrConfigurationPanel.java (renamed from src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java)3
-rw-r--r--src/net/java/sip/communicator/plugin/otr/authdialog/OtrV3OutgoingSessionSwitcher.java319
-rw-r--r--src/net/java/sip/communicator/service/gui/Container.java5
21 files changed, 955 insertions, 80 deletions
diff --git a/lib/installer-exclude/otr4j.jar b/lib/installer-exclude/otr4j.jar
index fc22915..f755a6a 100644
--- a/lib/installer-exclude/otr4j.jar
+++ b/lib/installer-exclude/otr4j.jar
Binary files differ
diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties
index 9a4252d..00bb3b9 100644
--- a/resources/languages/resources.properties
+++ b/resources/languages/resources.properties
@@ -1611,6 +1611,10 @@ plugin.otr.activator.fallbackmessage=<span style="font-weight: bold;">{0} is try
<a href="http://en.wikipedia.org/wiki/Off-the-Record_Messaging">Off-The-Record conversation</a> with you. However, your software does not support \
Off-The-Record messaging. For more information see <a href="http://en.wikipedia.org/wiki/Off-the-Record_Messaging">\
http://en.wikipedia.org/wiki/Off-the-Record_Messaging</a></span>
+plugin.otr.activator.multipleinstancesdetected=Your buddy {0} is logged in multiple times and OTR has established multiple sessions. You can select \
+an outgoing session from the menu above.
+plugin.otr.activator.msgfromanotherinstance={0} sent you a message that was intended for another session. If you are logged in multiple times \
+another session may have received this message.
# global proxy plugin
plugin.globalproxy.GLOBAL_PROXY_CONFIG=Global Proxy
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
index 4853797..9a80325 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
@@ -323,6 +323,7 @@ public class ChatPanel
topSplitPane.setRightComponent(rightPanel);
topPanel.add(topSplitPane);
+
}
else
{
@@ -354,6 +355,7 @@ public class ChatPanel
this.repaint();
}
+ writeMessagePanel.initPluginComponents();
writeMessagePanel.setTransportSelectorBoxVisible(true);
//Enables to change the protocol provider by simply pressing the
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
index 8470596..14afdc8 100755
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
@@ -6,6 +6,7 @@
package net.java.sip.communicator.impl.gui.main.chat;
import java.awt.*;
+import java.awt.Container;
import java.awt.event.*;
import java.io.*;
import java.util.*;
@@ -18,10 +19,13 @@ import javax.swing.text.html.*;
import javax.swing.undo.*;
import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.event.*;
import net.java.sip.communicator.impl.gui.main.chat.conference.*;
import net.java.sip.communicator.impl.gui.main.chat.menus.*;
import net.java.sip.communicator.impl.gui.utils.*;
import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.contactlist.*;
+import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.event.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
@@ -29,6 +33,7 @@ import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.skin.*;
import org.jitsi.service.configuration.*;
+import org.osgi.framework.*;
/**
* The <tt>ChatWritePanel</tt> is the panel, where user writes her messages.
@@ -46,6 +51,7 @@ public class ChatWritePanel
MouseListener,
UndoableEditListener,
DocumentListener,
+ PluginComponentListener,
Skinnable
{
/**
@@ -1518,4 +1524,102 @@ public class ChatWritePanel
isOutdatedResource = true;
}
}
+
+ /**
+ * Initializes plug-in components for this container.
+ */
+ void initPluginComponents()
+ {
+ // Search for plugin components registered through the OSGI bundle
+ // context.
+ ServiceReference[] serRefs = null;
+
+ String osgiFilter = "("
+ + net.java.sip.communicator.service.gui.Container.CONTAINER_ID
+ + "="+net.java.sip.communicator.service.gui.Container.
+ CONTAINER_CHAT_WRITE_PANEL.getID()+")";
+
+ try
+ {
+ serRefs = GuiActivator.bundleContext.getServiceReferences(
+ PluginComponentFactory.class.getName(),
+ osgiFilter);
+ }
+ catch (InvalidSyntaxException exc)
+ {
+ logger.error("Could not obtain plugin reference.", exc);
+ }
+ if (serRefs != null)
+ {
+ for (int i = 0; i < serRefs.length; i ++)
+ {
+ PluginComponentFactory factory =
+ (PluginComponentFactory) GuiActivator
+ .bundleContext.getService(serRefs[i]);
+
+ PluginComponent component =
+ factory.getPluginComponentInstance(this);
+ ChatSession chatSession = chatPanel.getChatSession();
+ if (chatSession instanceof MetaContactChatSession)
+ {
+ MetaContact metaContact =
+ (MetaContact) chatSession.getDescriptor();
+ component.setCurrentContact(metaContact);
+ }
+ if (component.getComponent() == null)
+ continue;
+
+ centerPanel.add((Component)component.getComponent());
+ }
+ }
+ GuiActivator.getUIService().addPluginComponentListener(this);
+ this.centerPanel.repaint();
+ }
+
+ /**
+ * Indicates that a new plugin component has been added. Adds it to this
+ * container if it belongs to it.
+ *
+ * @param event the <tt>PluginComponentEvent</tt> that notified us
+ */
+ public void pluginComponentAdded(PluginComponentEvent event)
+ {
+ PluginComponentFactory factory = event.getPluginComponentFactory();
+ if (!factory.getContainer().equals(
+ net.java.sip.communicator.service.
+ gui.Container.CONTAINER_CHAT_WRITE_PANEL))
+ return;
+ PluginComponent c = factory.getPluginComponentInstance(this);
+ ChatSession chatSession = chatPanel.getChatSession();
+ if (chatSession instanceof MetaContactChatSession)
+ {
+ MetaContact metaContact = (MetaContact) chatSession.getDescriptor();
+ c.setCurrentContact(metaContact);
+ }
+ centerPanel.add((Component) c.getComponent());
+
+ this.centerPanel.repaint();
+ }
+
+ /**
+ * Removes the according plug-in component from this container.
+ *
+ * @param event the <tt>PluginComponentEvent</tt> that notified us
+ */
+ public void pluginComponentRemoved(PluginComponentEvent event)
+ {
+ PluginComponentFactory factory = event.getPluginComponentFactory();
+
+ if (!factory.getContainer().equals(
+ net.java.sip.communicator.service.
+ gui.Container.CONTAINER_CHAT_WRITE_PANEL))
+ return;
+
+ Component c =
+ (Component)factory.getPluginComponentInstance(this)
+ .getComponent();
+
+ this.centerPanel.remove(c);
+ this.centerPanel.repaint();
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrActivator.java b/src/net/java/sip/communicator/plugin/otr/OtrActivator.java
index ae56e39..5e35942 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrActivator.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrActivator.java
@@ -8,13 +8,14 @@ package net.java.sip.communicator.plugin.otr;
import java.util.*;
+import net.java.sip.communicator.plugin.otr.authdialog.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
-
import net.java.sip.communicator.util.Logger;
+
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
import org.jitsi.util.*;
@@ -370,6 +371,20 @@ public class OtrActivator
bundleContext.registerService(
OtrActionHandler.class.getName(),
new SwingOtrActionHandler(), null);
+
+ containerFilter.put(Container.CONTAINER_ID,
+ Container.CONTAINER_CHAT_WRITE_PANEL.getID());
+ bundleContext.registerService(
+ PluginComponentFactory.class.getName(),
+ new PluginComponentFactory( Container.CONTAINER_CHAT_WRITE_PANEL)
+ {
+ protected PluginComponent getPluginInstance()
+ {
+ return new OtrV3OutgoingSessionSwitcher(
+ getContainer(), this);
+ }
+ },
+ containerFilter);
}
// If the general configuration form is disabled don't register it.
@@ -384,7 +399,8 @@ public class OtrActivator
// Register the configuration form.
bundleContext.registerService(ConfigurationForm.class.getName(),
new LazyConfigurationForm(
- "net.java.sip.communicator.plugin.otr.OtrConfigurationPanel",
+ "net.java.sip.communicator.plugin.otr.authdialog." +
+ "OtrConfigurationPanel",
getClass().getClassLoader(),
"plugin.otr.configform.ICON",
"service.gui.CHAT", 1),
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrConfigurator.java b/src/net/java/sip/communicator/plugin/otr/OtrConfigurator.java
index dbd9c87..a4c47e4 100755
--- a/src/net/java/sip/communicator/plugin/otr/OtrConfigurator.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrConfigurator.java
@@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.plugin.otr;
+import java.util.*;
+
import org.bouncycastle.util.encoders.*;
import org.jitsi.service.configuration.*;
@@ -142,4 +144,31 @@ public class OtrConfigurator
{
return OtrActivator.configService.getInt(getID(id), defaultValue);
}
+
+ /**
+ * Appends <tt>value</tt> to the old value of the property with the
+ * specified name. The two values will be comma separated.
+ *
+ * @param id the name of the property to append to
+ * @param value the value to append
+ */
+ public void appendProperty(String id, Object value)
+ {
+ Object oldValue = OtrActivator.configService.getProperty(getID(id));
+
+ String newValue =
+ oldValue == null ? value.toString() : oldValue + "," + value;
+
+ setProperty(id, newValue);
+ }
+
+ public List<String> getAppendedProperties(String id)
+ {
+ String listProperties =
+ (String) OtrActivator.configService.getProperty(getID(id));
+
+ if (listProperties == null) return new ArrayList<String>();
+
+ return Arrays.asList(listProperties.split(","));
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java b/src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java
index 040f932..613b0f8 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrContactMenu.java
@@ -7,6 +7,7 @@
package net.java.sip.communicator.plugin.otr;
import java.awt.event.*;
+import java.security.*;
import javax.swing.*;
@@ -470,8 +471,13 @@ class OtrContactMenu
switch (sessionStatus)
{
case ENCRYPTED:
+ PublicKey pubKey =
+ OtrActivator.scOtrEngine.getRemotePublicKey(contact);
+ String fingerprint =
+ OtrActivator.scOtrKeyManager.
+ getFingerprintFromPublicKey(pubKey);
imageID
- = OtrActivator.scOtrKeyManager.isVerified(contact)
+ = OtrActivator.scOtrKeyManager.isVerified(contact, fingerprint)
? "plugin.otr.ENCRYPTED_ICON_16x16"
: "plugin.otr.ENCRYPTED_UNVERIFIED_ICON_16x16";
break;
@@ -490,4 +496,14 @@ class OtrContactMenu
separateMenu.setIcon(OtrActivator.resourceService.getImage(imageID));
}
+
+ @Override
+ public void multipleInstancesDetected(Contact contact) {}
+
+ @Override
+ public void outgoingSessionChanged(Contact contact)
+ {
+ if (contact.equals(OtrContactMenu.this.contact))
+ setSessionStatus(OtrActivator.scOtrEngine.getSessionStatus(contact));
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java b/src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java
index 2984fb7..40810ce 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrMetaContactButton.java
@@ -9,6 +9,7 @@ package net.java.sip.communicator.plugin.otr;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
+import java.security.*;
import javax.imageio.*;
@@ -272,12 +273,17 @@ public class OtrMetaContactButton
switch (status)
{
case ENCRYPTED:
+ PublicKey pubKey =
+ OtrActivator.scOtrEngine.getRemotePublicKey(contact);
+ String fingerprint =
+ OtrActivator.scOtrKeyManager.
+ getFingerprintFromPublicKey(pubKey);
image
- = OtrActivator.scOtrKeyManager.isVerified(contact)
+ = OtrActivator.scOtrKeyManager.isVerified(contact, fingerprint)
? verifiedLockedPadlockImage
: unverifiedLockedPadlockImage;
tipKey =
- OtrActivator.scOtrKeyManager.isVerified(contact)
+ OtrActivator.scOtrKeyManager.isVerified(contact, fingerprint)
? "plugin.otr.menu.VERIFIED"
: "plugin.otr.menu.UNVERIFIED";
break;
@@ -308,4 +314,19 @@ public class OtrMetaContactButton
.getI18NString(tipKey));
button.repaint();
}
+
+ @Override
+ public void multipleInstancesDetected(Contact contact)
+ {}
+
+ @Override
+ public void outgoingSessionChanged(Contact contact)
+ {
+ // OtrMetaContactButton.this.contact can be null.
+ if (contact.equals(OtrMetaContactButton.this.contact))
+ {
+ setStatus(
+ OtrActivator.scOtrEngine.getSessionStatus(contact));
+ }
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrWeakListener.java b/src/net/java/sip/communicator/plugin/otr/OtrWeakListener.java
index 423cf23..b94a9bf 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrWeakListener.java
+++ b/src/net/java/sip/communicator/plugin/otr/OtrWeakListener.java
@@ -152,4 +152,28 @@ public class OtrWeakListener
if (l != null)
l.sessionStatusChanged(contact);
}
+
+ /**
+ * Forwards the event/notification to the associated
+ * <tt>T</tt> if it is still needed by the application.
+ */
+ public void multipleInstancesDetected(Contact contact)
+ {
+ ScOtrEngineListener l = getListener();
+
+ if (l != null)
+ l.multipleInstancesDetected(contact);
+ }
+
+ /**
+ * Forwards the event/notification to the associated
+ * <tt>T</tt> if it is still needed by the application.
+ */
+ public void outgoingSessionChanged(Contact contact)
+ {
+ ScOtrEngineListener l = getListener();
+
+ if (l != null)
+ l.outgoingSessionChanged(contact);
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java b/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java
index 853c5fc..cade910 100644
--- a/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java
+++ b/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java
@@ -6,7 +6,11 @@
*/
package net.java.sip.communicator.plugin.otr;
+import java.security.*;
+import java.util.*;
+
import net.java.otr4j.*;
+import net.java.otr4j.session.*;
import net.java.sip.communicator.service.protocol.*;
/**
@@ -100,6 +104,42 @@ public interface ScOtrEngine
public abstract void refreshSession(Contact contact);
/**
+ * Some IM networks always relay all messages to all sessions of a client
+ * who is logged in multiple times. OTR version 3 deals with this problem
+ * with introducing instance tags.
+ * <a href="https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html">
+ * https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html</a>
+ * <p>
+ * Returns a list containing all instances of a session. The 'master'
+ * session is always first in the list.
+ *
+ * @param contact the {@link Contact} for whom we want to get the instances
+ *
+ * @return A list of all instances of the session for the specified contact.
+ */
+ public abstract List<Session> getSessionInstances(Contact contact);
+
+ /**
+ * Some IM networks always relay all messages to all sessions of a client
+ * who is logged in multiple times. OTR version 3 deals with this problem
+ * with introducing instance tags.
+ * <a href="https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html">
+ * https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html</a>
+ * <p>
+ * When the client wishes to start sending OTRv3 encrypted messages to a
+ * specific session of his buddy who is logged in multiple times, he can set
+ * the outgoing instance of his buddy by specifying his <tt>InstanceTag</tt>.
+ *
+ * @param contact the {@link Contact} to whom we want to set the outgoing
+ * instance tag.
+ * @param tag the outgoing {@link InstanceTag}
+ *
+ * @return true if an outgoing session with such {@link InstanceTag} exists
+ * . Otherwise false
+ */
+ public abstract boolean setOutgoingSession(Contact contact, InstanceTag tag);
+
+ /**
* Gets the {@link ScSessionStatus} for the given {@link Contact}.
*
* @param contact the {@link Contact} whose {@link ScSessionStatus} we are
@@ -135,6 +175,8 @@ public interface ScOtrEngine
*/
public abstract void removeListener(ScOtrEngineListener listener);
+ public abstract PublicKey getRemotePublicKey(Contact contact);
+
// New Methods (Policy management)
/**
* Gets the global {@link OtrPolicy}.
diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java b/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java
index b3765fa..137122c 100644
--- a/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java
+++ b/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java
@@ -12,6 +12,7 @@ import java.util.*;
import java.util.concurrent.*;
import net.java.otr4j.*;
+import net.java.otr4j.crypto.*;
import net.java.otr4j.session.*;
import net.java.sip.communicator.plugin.otr.authdialog.*;
import net.java.sip.communicator.service.browserlauncher.*;
@@ -265,19 +266,20 @@ public class ScOtrEngineImpl
progressDialog = new SmpProgressDialog(contact);
progressDialogMap.put(contact, progressDialog);
}
-
+
progressDialog.init();
progressDialog.setVisible(true);
}
@Override
- public void verify(SessionID sessionID, boolean approved)
+ public void verify(
+ SessionID sessionID, String fingerprint, boolean approved)
{
Contact contact = getContact(sessionID);
if (contact == null)
return;
- OtrActivator.scOtrKeyManager.verify(contact);
+ OtrActivator.scOtrKeyManager.verify(contact, fingerprint);
SmpProgressDialog progressDialog = progressDialogMap.get(contact);
if (progressDialog == null)
@@ -285,20 +287,20 @@ public class ScOtrEngineImpl
progressDialog = new SmpProgressDialog(contact);
progressDialogMap.put(contact, progressDialog);
}
-
+
progressDialog.setProgressSuccess();
progressDialog.setVisible(true);
}
@Override
- public void unverify(SessionID sessionID)
+ public void unverify(SessionID sessionID, String fingerprint)
{
Contact contact = getContact(sessionID);
if (contact == null)
return;
- OtrActivator.scOtrKeyManager.unverify(contact);
-
+ OtrActivator.scOtrKeyManager.unverify(contact, fingerprint);
+
SmpProgressDialog progressDialog = progressDialogMap.get(contact);
if (progressDialog == null)
{
@@ -332,6 +334,42 @@ public class ScOtrEngineImpl
"plugin.otr.activator.fallbackmessage",
new String[] {accountID.getDisplayName()});
}
+
+ @Override
+ public void multipleInstancesDetected(SessionID sessionID)
+ {
+ Contact contact = getContact(sessionID);
+ if (contact == null)
+ return;
+
+ String message =
+ OtrActivator.resourceService.getI18NString(
+ "plugin.otr.activator.multipleinstancesdetected",
+ new String[] {contact.getDisplayName()});
+ OtrActivator.uiService.getChat(contact).addMessage(
+ contact.getDisplayName(),
+ new Date(), Chat.SYSTEM_MESSAGE,
+ message,
+ OperationSetBasicInstantMessaging.HTML_MIME_TYPE);
+ }
+
+ @Override
+ public void messageFromAnotherInstanceReceived(SessionID sessionID)
+ {
+ Contact contact = getContact(sessionID);
+ if (contact == null)
+ return;
+
+ String message =
+ OtrActivator.resourceService.getI18NString(
+ "plugin.otr.activator.msgfromanotherinstance",
+ new String[] {contact.getDisplayName()});
+ OtrActivator.uiService.getChat(contact).addMessage(
+ contact.getDisplayName(),
+ new Date(), Chat.SYSTEM_MESSAGE,
+ message,
+ OperationSetBasicInstantMessaging.HTML_MIME_TYPE);
+ }
}
/**
@@ -453,15 +491,38 @@ public class ScOtrEngineImpl
PublicKey remotePubKey =
otrEngine.getRemotePublicKey(sessionID);
- PublicKey storedPubKey =
- OtrActivator.scOtrKeyManager.loadPublicKey(contact);
+ String remoteFingerprint = null;
+ try
+ {
+ remoteFingerprint =
+ new OtrCryptoEngineImpl().
+ getFingerprint(remotePubKey);
+ }
+ catch (OtrCryptoException e)
+ {
+ logger.debug(
+ "Could not get the fingerprint from the "
+ + "public key of contact: " + contact);
+ }
- if (!remotePubKey.equals(storedPubKey))
- OtrActivator.scOtrKeyManager.savePublicKey(contact,
- remotePubKey);
+ List<String> allFingerprintsOfContact =
+ OtrActivator.scOtrKeyManager.
+ getAllRemoteFingerprints(contact);
+ if (allFingerprintsOfContact != null)
+ {
+ if (!allFingerprintsOfContact.contains(
+ remoteFingerprint))
+ {
+ OtrActivator.scOtrKeyManager.saveFingerprint(
+ contact, remoteFingerprint);
+ }
+ }
- if (!OtrActivator.scOtrKeyManager.isVerified(contact))
+ if (!OtrActivator.scOtrKeyManager.isVerified(
+ contact, remoteFingerprint))
{
+ OtrActivator.scOtrKeyManager.unverify(
+ contact, remoteFingerprint);
UUID sessionGuid = null;
for(ScSessionID scSessionID : contactsMap.keySet())
{
@@ -531,7 +592,8 @@ public class ScOtrEngineImpl
message
= OtrActivator.resourceService.getI18NString(
- OtrActivator.scOtrKeyManager.isVerified(contact)
+ OtrActivator.scOtrKeyManager.isVerified(
+ contact, remoteFingerprint)
? "plugin.otr.activator.sessionstared"
: "plugin.otr.activator"
+ ".unverifiedsessionstared",
@@ -565,6 +627,26 @@ public class ScOtrEngineImpl
for (ScOtrEngineListener l : getListeners())
l.sessionStatusChanged(contact);
}
+
+ public void multipleInstancesDetected(SessionID sessionID)
+ {
+ Contact contact = getContact(sessionID);
+ if (contact == null)
+ return;
+
+ for (ScOtrEngineListener l : getListeners())
+ l.multipleInstancesDetected(contact);
+ }
+
+ public void outgoingSessionChanged(SessionID sessionID)
+ {
+ Contact contact = getContact(sessionID);
+ if (contact == null)
+ return;
+
+ for (ScOtrEngineListener l : getListeners())
+ l.outgoingSessionChanged(contact);
+ }
});
}
@@ -1036,6 +1118,34 @@ public class ScOtrEngineImpl
+ contact.getDisplayName(), e);
showError(session.getSessionID(), e.getMessage());
}
-
+ }
+
+ public PublicKey getRemotePublicKey(Contact contact)
+ {
+ if (contact == null)
+ return null;
+
+ Session session = getSession(contact);
+
+ return session.getRemotePublicKey();
+ }
+
+ public List<Session> getSessionInstances(Contact contact)
+ {
+ if (contact == null)
+ return null;
+
+ return getSession(contact).getInstances();
+ }
+
+ public boolean setOutgoingSession(Contact contact, InstanceTag tag)
+ {
+ if (contact == null)
+ return false;
+
+ Session session = getSession(contact);
+
+ scSessionStatusMap.remove(session.getSessionID());
+ return session.setOutgoingInstance(tag);
}
}
diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrEngineListener.java b/src/net/java/sip/communicator/plugin/otr/ScOtrEngineListener.java
index 790fc16..8ab95b8 100644
--- a/src/net/java/sip/communicator/plugin/otr/ScOtrEngineListener.java
+++ b/src/net/java/sip/communicator/plugin/otr/ScOtrEngineListener.java
@@ -19,4 +19,8 @@ public interface ScOtrEngineListener
public void globalPolicyChanged();
public void sessionStatusChanged(Contact contact);
+
+ public void multipleInstancesDetected(Contact contact);
+
+ public void outgoingSessionChanged(Contact contact);
}
diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java
index bc83cd7..47ca22d 100755
--- a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java
+++ b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java
@@ -7,6 +7,7 @@
package net.java.sip.communicator.plugin.otr;
import java.security.*;
+import java.util.*;
import net.java.sip.communicator.service.protocol.*;
@@ -22,19 +23,21 @@ public interface ScOtrKeyManager
public abstract void removeListener(ScOtrKeyManagerListener l);
- public abstract void verify(Contact contact);
+ public abstract void verify(Contact contact, String fingerprint);
- public abstract void unverify(Contact contact);
+ public abstract void unverify(Contact contact, String fingerprint);
- public abstract boolean isVerified(Contact contact);
+ public abstract boolean isVerified(Contact contact, String fingerprint);
- public abstract String getRemoteFingerprint(Contact contact);
+ public abstract String getFingerprintFromPublicKey(PublicKey pubKey);
+
+ public abstract List<String> getAllRemoteFingerprints(Contact contact);
public abstract String getLocalFingerprint(AccountID account);
public abstract byte[] getLocalFingerprintRaw(AccountID account);
- public abstract void savePublicKey(Contact contact, PublicKey pubKey);
+ public abstract void saveFingerprint(Contact contact, String fingerprint);
public abstract PublicKey loadPublicKey(Contact contact);
diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java
index 37adc63..8933530 100755
--- a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java
+++ b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java
@@ -62,47 +62,113 @@ public class ScOtrKeyManagerImpl
}
}
- public void verify(Contact contact)
+ public void verify(Contact contact, String fingerprint)
{
- if ((contact == null) || isVerified(contact))
+ if ((fingerprint == null) || contact == null)
return;
- this.configurator.setProperty(contact.getAddress()
- + ".publicKey.verified", true);
+ this.configurator.setProperty(contact.getAddress() + fingerprint
+ + ".fingerprint.verified", true);
for (ScOtrKeyManagerListener l : getListeners())
l.contactVerificationStatusChanged(contact);
}
- public void unverify(Contact contact)
+ public void unverify(Contact contact, String fingerprint)
{
- if ((contact == null) || !isVerified(contact))
+ if ((fingerprint == null) || contact == null)
return;
- this.configurator.removeProperty(contact.getAddress()
- + ".publicKey.verified");
+ this.configurator.setProperty(contact.getAddress() + fingerprint
+ + ".fingerprint.verified", false);
for (ScOtrKeyManagerListener l : getListeners())
l.contactVerificationStatusChanged(contact);
}
- public boolean isVerified(Contact contact)
+ public boolean isVerified(Contact contact, String fingerprint)
{
- if (contact == null)
+ if (fingerprint == null || contact == null)
return false;
- return this.configurator.getPropertyBoolean(contact.getAddress()
- + ".publicKey.verified", false);
+ return this.configurator.getPropertyBoolean(
+ contact.getAddress() + fingerprint
+ + ".fingerprint.verified", false);
}
- public String getRemoteFingerprint(Contact contact)
+ public List<String> getAllRemoteFingerprints(Contact contact)
{
- PublicKey remotePublicKey = loadPublicKey(contact);
- if (remotePublicKey == null)
+ if (contact == null)
return null;
+
+ /*
+ * The following lines are needed for backward compatibility with old
+ * versions of the otr plugin. Instead of lists of fingerprints the otr
+ * plugin used to store one public key for every contact in the form of
+ * "userID.publicKey=..." and one boolean property in the form of
+ * "userID.publicKey.verified=...". In order not to loose these old
+ * properties we have to convert them to match the new format.
+ */
+ String userID = contact.getAddress();
+
+ byte[] b64PubKey =
+ this.configurator.getPropertyBytes(userID + ".publicKey");
+ if (b64PubKey != null)
+ {
+ // We delete the old format property because we are going to convert
+ // it in the new format
+ this.configurator.removeProperty(userID + ".publicKey");
+
+ X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(b64PubKey);
+
+ KeyFactory keyFactory;
+ try
+ {
+ keyFactory = KeyFactory.getInstance("DSA");
+ PublicKey pubKey = keyFactory.generatePublic(publicKeySpec);
+
+ boolean isVerified =
+ this.configurator.getPropertyBoolean(userID
+ + ".publicKey.verified", false);
+
+ // We also make sure to delete this old format property if it
+ // exists.
+ this.configurator.removeProperty(userID + ".publicKey.verified");
+
+ String fingerprint = getFingerprintFromPublicKey(pubKey);
+
+ // Now we can store the old properties in the new format.
+ if (isVerified)
+ verify(contact, fingerprint);
+ else
+ unverify(contact, fingerprint);
+
+ // Finally we append the new fingerprint to out stored list of
+ // fingerprints.
+ this.configurator.appendProperty(
+ userID + ".fingerprints", fingerprint);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InvalidKeySpecException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ // Now we can safely return our list of fingerprints for this contact
+ // without worrying that we missed an old format property.
+ return this.configurator.getAppendedProperties(
+ contact.getAddress() + ".fingerprints");
+ }
+
+ public String getFingerprintFromPublicKey(PublicKey pubKey)
+ {
try
{
- return new OtrCryptoEngineImpl().getFingerprint(remotePublicKey);
+ return new OtrCryptoEngineImpl().getFingerprint(pubKey);
}
catch (OtrCryptoException e)
{
@@ -151,19 +217,16 @@ public class ScOtrKeyManagerImpl
}
}
- public void savePublicKey(Contact contact, PublicKey pubKey)
+ public void saveFingerprint(Contact contact, String fingerprint)
{
if (contact == null)
return;
- X509EncodedKeySpec x509EncodedKeySpec =
- new X509EncodedKeySpec(pubKey.getEncoded());
-
- this.configurator.setProperty(contact.getAddress() + ".publicKey",
- x509EncodedKeySpec.getEncoded());
+ this.configurator.appendProperty(contact.getAddress() + ".fingerprints",
+ fingerprint);
- this.configurator.removeProperty(contact.getAddress()
- + ".publicKey.verified");
+ this.configurator.setProperty(contact.getAddress() + fingerprint
+ + ".fingerprint.verified", false);
}
public PublicKey loadPublicKey(Contact contact)
diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/FingerprintAuthenticationPanel.java b/src/net/java/sip/communicator/plugin/otr/authdialog/FingerprintAuthenticationPanel.java
index 26f8866..31d6848 100644
--- a/src/net/java/sip/communicator/plugin/otr/authdialog/FingerprintAuthenticationPanel.java
+++ b/src/net/java/sip/communicator/plugin/otr/authdialog/FingerprintAuthenticationPanel.java
@@ -7,6 +7,7 @@
package net.java.sip.communicator.plugin.otr.authdialog;
import java.awt.*;
+import java.security.*;
import javax.swing.*;
import javax.swing.event.*;
@@ -107,8 +108,13 @@ public class FingerprintAuthenticationPanel
cbAction = new JComboBox();
cbAction.addItem(actionIHave);
cbAction.addItem(actionIHaveNot);
+
+ PublicKey pubKey = OtrActivator.scOtrEngine.getRemotePublicKey(contact);
+ String remoteFingerprint =
+ OtrActivator.scOtrKeyManager.getFingerprintFromPublicKey(pubKey);
cbAction.setSelectedItem(OtrActivator.scOtrKeyManager
- .isVerified(contact) ? actionIHave : actionIHaveNot);
+ .isVerified(contact, remoteFingerprint)
+ ? actionIHave : actionIHaveNot);
pnlAction.add(cbAction, c);
@@ -152,8 +158,9 @@ public class FingerprintAuthenticationPanel
// Remote fingerprint.
String user = contact.getDisplayName();
+ PublicKey pubKey = OtrActivator.scOtrEngine.getRemotePublicKey(contact);
String remoteFingerprint =
- OtrActivator.scOtrKeyManager.getRemoteFingerprint(contact);
+ OtrActivator.scOtrKeyManager.getFingerprintFromPublicKey(pubKey);
txtRemoteFingerprint.setText(OtrActivator.resourceService
.getI18NString("plugin.otr.authbuddydialog.REMOTE_FINGERPRINT",
new String[]
@@ -182,6 +189,10 @@ public class FingerprintAuthenticationPanel
public void compareFingerprints()
{
+ PublicKey pubKey = OtrActivator.scOtrEngine.getRemotePublicKey(contact);
+ String remoteFingerprint =
+ OtrActivator.scOtrKeyManager.getFingerprintFromPublicKey(pubKey);
+
if(txtRemoteFingerprintComparison.getText() == null
|| txtRemoteFingerprintComparison.getText().length() == 0)
{
@@ -189,8 +200,7 @@ public class FingerprintAuthenticationPanel
return;
}
if(txtRemoteFingerprintComparison.getText().toLowerCase().contains(
- OtrActivator.scOtrKeyManager
- .getRemoteFingerprint(contact).toLowerCase()))
+ remoteFingerprint.toLowerCase()))
{
txtRemoteFingerprintComparison.setBackground(Color.green);
cbAction.setSelectedItem(actionIHave);
diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsPanel.java b/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsPanel.java
index 256814a..099bb67 100644
--- a/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsPanel.java
+++ b/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsPanel.java
@@ -13,9 +13,9 @@ import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
-import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.otr.*;
+import net.java.sip.communicator.service.protocol.*;
/**
* @author @George Politis
@@ -44,7 +44,7 @@ public class KnownFingerprintsPanel
this.setPreferredSize(new Dimension(400, 200));
- openContact(getSelectedContact());
+ openContact(getSelectedContact(), getSelectedFingerprint());
}
/**
@@ -74,7 +74,7 @@ public class KnownFingerprintsPanel
if (e.getValueIsAdjusting())
return;
- openContact(getSelectedContact());
+ openContact(getSelectedContact(), getSelectedFingerprint());
}
});
@@ -88,14 +88,15 @@ public class KnownFingerprintsPanel
btnVerifyFingerprint = new JButton();
btnVerifyFingerprint.setText(OtrActivator.resourceService
.getI18NString("plugin.otr.configform.VERIFY_FINGERPRINT"));
+ btnVerifyFingerprint.setEnabled(false);
btnVerifyFingerprint.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
OtrActivator.scOtrKeyManager
- .verify(getSelectedContact());
- openContact(getSelectedContact());
+ .verify(getSelectedContact(), getSelectedFingerprint());
+ openContact(getSelectedContact(), getSelectedFingerprint());
contactsTable.updateUI();
}
});
@@ -105,13 +106,15 @@ public class KnownFingerprintsPanel
btnForgetFingerprint = new JButton();
btnForgetFingerprint.setText(OtrActivator.resourceService
.getI18NString("plugin.otr.configform.FORGET_FINGERPRINT"));
+ btnForgetFingerprint.setEnabled(false);
+
btnForgetFingerprint.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
OtrActivator.scOtrKeyManager
- .unverify(getSelectedContact());
- openContact(getSelectedContact());
+ .unverify(getSelectedContact(), getSelectedFingerprint());
+ openContact(getSelectedContact(), getSelectedFingerprint());
contactsTable.updateUI();
}
});
@@ -129,10 +132,27 @@ public class KnownFingerprintsPanel
KnownFingerprintsTableModel model =
(KnownFingerprintsTableModel) contactsTable.getModel();
int index = contactsTable.getSelectedRow();
- if (index < 0 || index > model.allContacts.size())
+ if (index < 0 || index > model.getRowCount())
+ return null;
+
+ return model.getContactFromRow(index);
+ }
+
+ /**
+ * Gets the selected fingerprint for this
+ * {@link KnownFingerprintsTableModel}
+ *
+ * return the selected fingerprint
+ */
+ private String getSelectedFingerprint()
+ {
+ KnownFingerprintsTableModel model =
+ (KnownFingerprintsTableModel) contactsTable.getModel();
+ int index = contactsTable.getSelectedRow();
+ if (index < 0 || index > model.getRowCount())
return null;
- return model.allContacts.get(index);
+ return model.getFingerprintFromRow(index);
}
/**
@@ -140,11 +160,11 @@ public class KnownFingerprintsPanel
* reflect the {@link Contact} param.
*
* @param contact the {@link Contact} to setup the components for.
+ * @param fingerprint the fingerprint to setup the components for.
*/
- private void openContact(Contact contact)
+ private void openContact(Contact contact, String fingerprint)
{
- if (contact == null
- || OtrActivator.scOtrKeyManager.getRemoteFingerprint(contact) == null)
+ if (contact == null || fingerprint == null)
{
btnForgetFingerprint.setEnabled(false);
btnVerifyFingerprint.setEnabled(false);
@@ -153,7 +173,7 @@ public class KnownFingerprintsPanel
{
boolean verified
= OtrActivator.scOtrKeyManager
- .isVerified(contact);
+ .isVerified(contact, fingerprint);
btnForgetFingerprint.setEnabled(verified);
btnVerifyFingerprint.setEnabled(!verified);
diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsTableModel.java b/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsTableModel.java
index 1b32f26..41dbbfb 100644
--- a/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsTableModel.java
+++ b/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsTableModel.java
@@ -8,6 +8,7 @@ package net.java.sip.communicator.plugin.otr.authdialog;
import java.awt.*;
import java.util.*;
+import java.util.List;
import javax.swing.table.*;
@@ -25,6 +26,7 @@ import org.osgi.framework.*;
*/
public class KnownFingerprintsTableModel
extends AbstractTableModel
+ implements ScOtrKeyManagerListener
{
/**
* Serial version UID.
@@ -37,7 +39,8 @@ public class KnownFingerprintsTableModel
public static final int FINGERPRINT_INDEX = 2;
- public final java.util.List<Contact> allContacts = new Vector<Contact>();
+ public final LinkedHashMap<Contact, List<String>> allContactsFingerprints =
+ new LinkedHashMap<Contact, List<String>>();
public KnownFingerprintsTableModel()
{
@@ -76,10 +79,15 @@ public class KnownFingerprintsTableModel
Iterator<Contact> contacts = metaContact.getContacts();
while (contacts.hasNext())
{
- allContacts.add(contacts.next());
+ Contact contact = contacts.next();
+ allContactsFingerprints.put(
+ contact,
+ OtrActivator.scOtrKeyManager.getAllRemoteFingerprints(
+ contact));
}
}
}
+ OtrActivator.scOtrKeyManager.addListener(this);
}
/**
@@ -112,10 +120,8 @@ public class KnownFingerprintsTableModel
*/
public Object getValueAt(int row, int column)
{
- if (row < 0)
- return null;
-
- Contact contact = allContacts.get(row);
+ Contact contact = getContactFromRow(row);
+ String fingerprint = getFingerprintFromRow(row);
switch (column)
{
case CONTACTNAME_INDEX:
@@ -123,25 +129,84 @@ public class KnownFingerprintsTableModel
case VERIFIED_INDEX:
// TODO: Maybe use a CheckBoxColumn?
return (OtrActivator.scOtrKeyManager
- .isVerified(contact))
+ .isVerified(contact, fingerprint))
? OtrActivator.resourceService.getI18NString(
"plugin.otr.configform.COLUMN_VALUE_VERIFIED_TRUE")
: OtrActivator.resourceService.getI18NString(
"plugin.otr.configform.COLUMN_VALUE_VERIFIED_FALSE");
case FINGERPRINT_INDEX:
- return OtrActivator.scOtrKeyManager
- .getRemoteFingerprint(contact);
+ return fingerprint;
default:
return null;
}
}
+ Contact getContactFromRow(int row)
+ {
+ if (row < 0 || row >= getRowCount())
+ return null;
+
+ int index = -1;
+ Contact contact = null;
+ for (Map.Entry<Contact, List<String>> entry :
+ allContactsFingerprints.entrySet())
+ {
+ boolean found = false;
+ contact = entry.getKey();
+ List<String> fingerprints = entry.getValue();
+ for (String f : fingerprints)
+ {
+ index++;
+ if (index == row)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found) break;
+ }
+
+ return contact;
+ }
+
+ String getFingerprintFromRow(int row)
+ {
+ if (row < 0 || row >= getRowCount())
+ return null;
+
+ int index = -1;
+ String fingerprint = null;
+ for (Map.Entry<Contact, List<String>> entry :
+ allContactsFingerprints.entrySet())
+ {
+ boolean found = false;
+ List<String> fingerprints = entry.getValue();
+ for (String f : fingerprints)
+ {
+ index++;
+ fingerprint = f;
+ if (index == row)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found) break;
+ }
+
+ return fingerprint;
+ }
+
/**
* Implements AbstractTableModel#getRowCount().
*/
public int getRowCount()
{
- return allContacts.size();
+ int rowCount = 0;
+ for (Map.Entry<Contact, List<String>> entry :
+ allContactsFingerprints.entrySet())
+ rowCount += entry.getValue().size();
+ return rowCount;
}
/**
@@ -151,4 +216,13 @@ public class KnownFingerprintsTableModel
{
return 3;
}
+
+ @Override
+ public void contactVerificationStatusChanged(Contact contact)
+ {
+ allContactsFingerprints.put(
+ contact,
+ OtrActivator.scOtrKeyManager.getAllRemoteFingerprints(contact));
+ this.fireTableDataChanged();
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/OtrBuddyAuthenticationDialog.java b/src/net/java/sip/communicator/plugin/otr/authdialog/OtrBuddyAuthenticationDialog.java
index b67ce81..f82c01d 100644
--- a/src/net/java/sip/communicator/plugin/otr/authdialog/OtrBuddyAuthenticationDialog.java
+++ b/src/net/java/sip/communicator/plugin/otr/authdialog/OtrBuddyAuthenticationDialog.java
@@ -8,12 +8,13 @@ package net.java.sip.communicator.plugin.otr.authdialog;
import java.awt.*;
import java.awt.event.*;
+import java.security.*;
import javax.swing.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.otr.*;
-import net.java.sip.communicator.plugin.otr.authdialog.FingerprintAuthenticationPanel.*;
+import net.java.sip.communicator.plugin.otr.authdialog.FingerprintAuthenticationPanel.ActionComboBoxItem;
import net.java.sip.communicator.service.protocol.*;
/**
@@ -178,13 +179,20 @@ public class OtrBuddyAuthenticationDialog
ActionComboBoxItem actionItem =
(ActionComboBoxItem) fingerprintPanel.
getCbAction().getSelectedItem();
+ PublicKey pubKey =
+ OtrActivator.scOtrEngine.getRemotePublicKey(contact);
+ String fingerprint =
+ OtrActivator.scOtrKeyManager.
+ getFingerprintFromPublicKey(pubKey);
switch (actionItem.action)
{
case I_HAVE:
- OtrActivator.scOtrKeyManager.verify(contact);
+ OtrActivator.scOtrKeyManager.verify(
+ contact, fingerprint);
break;
case I_HAVE_NOT:
- OtrActivator.scOtrKeyManager.unverify(contact);
+ OtrActivator.scOtrKeyManager.unverify(
+ contact, fingerprint);
break;
}
dispose();
diff --git a/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java b/src/net/java/sip/communicator/plugin/otr/authdialog/OtrConfigurationPanel.java
index 79ce6bc..9435f23 100644
--- a/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java
+++ b/src/net/java/sip/communicator/plugin/otr/authdialog/OtrConfigurationPanel.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.plugin.otr;
+package net.java.sip.communicator.plugin.otr.authdialog;
import java.awt.*;
import java.awt.event.*;
@@ -16,6 +16,7 @@ import javax.swing.border.*;
import net.java.otr4j.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.otr.*;
import net.java.sip.communicator.plugin.otr.authdialog.*;
/**
diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/OtrV3OutgoingSessionSwitcher.java b/src/net/java/sip/communicator/plugin/otr/authdialog/OtrV3OutgoingSessionSwitcher.java
new file mode 100644
index 0000000..4ced8c1
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/otr/authdialog/OtrV3OutgoingSessionSwitcher.java
@@ -0,0 +1,319 @@
+package net.java.sip.communicator.plugin.otr.authdialog;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.security.*;
+import java.util.*;
+
+import javax.imageio.*;
+import javax.swing.*;
+import javax.swing.Timer;
+
+import net.java.otr4j.session.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.otr.*;
+import net.java.sip.communicator.service.contactlist.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.gui.Container;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+public class OtrV3OutgoingSessionSwitcher
+ extends SIPCommMenuBar
+ implements PluginComponent,
+ ActionListener,
+ ScOtrEngineListener,
+ ScOtrKeyManagerListener
+{
+
+ private static final Logger logger
+ = Logger.getLogger(OtrV3OutgoingSessionSwitcher.class);
+
+ private static final long serialVersionUID = 0L;
+
+ private final SelectorMenu menu = new SelectorMenu();
+
+ private ButtonGroup buttonGroup = new ButtonGroup();
+
+ Contact contact;
+
+ private final Map<Session, JMenuItem> outgoingSessions
+ = new HashMap<Session, JMenuItem>();
+ private static class SelectorMenu
+ extends SIPCommMenu
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ Image image = OtrActivator.resourceService.getImage(
+ "service.gui.icons.DOWN_ARROW_ICON").getImage();
+
+ private static float alpha = 0.95f;
+
+ private final Timer alphaChanger = new Timer(20, new ActionListener() {
+
+ private float incrementer = -.03f;
+
+ private int fadeCycles = 0;
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ float newAlpha = alpha + incrementer;
+ if (newAlpha < 0.2f)
+ {
+ newAlpha = 0.2f;
+ incrementer = -incrementer;
+ } else if (newAlpha > 0.85f)
+ {
+ newAlpha = 0.85f;
+ incrementer = -incrementer;
+ fadeCycles++;
+ }
+ alpha = newAlpha;
+ if (fadeCycles == 3)
+ {
+ alphaChanger.stop();
+ alpha = 1f;
+ }
+ SelectorMenu.this.repaint();
+ }
+ });
+
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.setComposite(
+ AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
+ g.drawImage(image, getWidth() - image.getWidth(this) - 1,
+ (getHeight() - image.getHeight(this) - 1) / 2, this);
+
+ super.paintComponent(g2d);
+ }
+
+ public void fadeAnimation()
+ {
+ alphaChanger.stop();
+ alpha = 0.85f;
+ repaint();
+ alphaChanger.start();
+ }
+ };
+
+ private final PluginComponentFactory parentFactory;
+
+ public OtrV3OutgoingSessionSwitcher(Container container,
+ PluginComponentFactory parentFactory)
+ {
+ this.parentFactory = parentFactory;
+
+ setPreferredSize(new Dimension(30, 28));
+ setMaximumSize(new Dimension(30, 28));
+ setMinimumSize(new Dimension(30, 28));
+
+ this.menu.setPreferredSize(new Dimension(30, 45));
+ this.menu.setMaximumSize(new Dimension(30, 45));
+
+ this.add(menu);
+
+ this.setBorder(null);
+ this.menu.setBorder(null);
+ this.menu.setOpaque(false);
+ this.setOpaque(false);
+ this.menu.setVisible(false);
+
+ buildMenu(contact);
+
+ /*
+ * XXX This OtrV3OutgoingSessionSwitcher instance cannot be added as a
+ * listener to scOtrEngine and scOtrKeyManager without being removed
+ * later on because the latter live forever. Unfortunately, the
+ * dispose() method of this instance is never executed. OtrWeakListener
+ * will keep this instance as a listener of scOtrEngine and
+ * scOtrKeyManager for as long as this instance is necessary. And this
+ * instance will be strongly referenced by the JMenuItems which depict
+ * it. So when the JMenuItems are gone, this instance will become
+ * obsolete and OtrWeakListener will remove it as a listener of
+ * scOtrEngine and scOtrKeyManager.
+ */
+ new OtrWeakListener<OtrV3OutgoingSessionSwitcher>(
+ this,
+ OtrActivator.scOtrEngine, OtrActivator.scOtrKeyManager);
+
+ try
+ {
+ finishedPadlockImage = new ImageIcon(ImageIO.read(
+ OtrActivator.resourceService.getImageURL(
+ "plugin.otr.FINISHED_ICON_16x16")));
+ verifiedLockedPadlockImage = new ImageIcon(ImageIO.read(
+ OtrActivator.resourceService.getImageURL(
+ "plugin.otr.ENCRYPTED_ICON_16x16")));
+ unverifiedLockedPadlockImage = new ImageIcon(ImageIO.read(
+ OtrActivator.resourceService.getImageURL(
+ "plugin.otr.ENCRYPTED_UNVERIFIED_ICON_16x16")));
+ unlockedPadlockImage = new ImageIcon(ImageIO.read(
+ OtrActivator.resourceService.getImageURL(
+ "plugin.otr.PLAINTEXT_ICON_16x16")));
+ } catch (IOException e)
+ {
+ logger.debug("Failed to load padlock image");
+ }
+ }
+
+ @Override
+ public int getPositionIndex()
+ {
+ return -1;
+ }
+
+ @Override
+ public void setCurrentContact(Contact contact)
+ {
+ if (this.contact == contact)
+ return;
+
+ this.contact = contact;
+ System.out.println("ot tuk1");
+ buildMenu(contact);
+ }
+
+ @Override
+ public void setCurrentContact(MetaContact metaContact)
+ {
+ setCurrentContact((metaContact == null) ? null : metaContact
+ .getDefaultContact());
+ }
+
+ @Override
+ public void setCurrentContactGroup(MetaContactGroup metaGroup) {}
+
+ @Override
+ public void setCurrentAccountID(AccountID accountID) {}
+
+ @Override
+ public PluginComponentFactory getParentFactory()
+ {
+ return parentFactory;
+ }
+
+ @Override
+ public void contactVerificationStatusChanged(Contact contact)
+ {
+ if (contact == null || this.contact != contact) return;
+ }
+
+ @Override
+ public void contactPolicyChanged(Contact contact) {}
+
+ @Override
+ public void globalPolicyChanged() {}
+
+ @Override
+ public void sessionStatusChanged(Contact contact)
+ {
+ System.out.println("ot tuk2");
+ buildMenu(contact);
+ }
+
+ @Override
+ public void multipleInstancesDetected(Contact contact)
+ {
+ System.out.println("ot tuk3");
+ buildMenu(contact);
+ }
+
+ private ImageIcon verifiedLockedPadlockImage;
+ private ImageIcon unverifiedLockedPadlockImage;
+ private ImageIcon finishedPadlockImage;
+ private ImageIcon unlockedPadlockImage;
+ void buildMenu(Contact contact)
+ {
+ if (contact == null || this.contact != contact) {
+ return;
+ }
+ menu.removeAll();
+
+ java.util.List<Session> multipleInstances =
+ OtrActivator.scOtrEngine.getSessionInstances(contact);
+
+ int index = 0;
+ for (Session session : multipleInstances)
+ {
+ index++;
+ if (!outgoingSessions.containsKey(session))
+ outgoingSessions.put(session, new JRadioButtonMenuItem());
+
+ JMenuItem menuItem = outgoingSessions.get(session);
+ menuItem.setText("Session " + index);
+
+ ImageIcon imageIcon = null;
+ switch (session.getSessionStatus(session.getReceiverInstanceTag()))
+ {
+ case ENCRYPTED:
+ PublicKey pubKey =
+ session.getRemotePublicKey(session.getReceiverInstanceTag());
+ String fingerprint =
+ OtrActivator.scOtrKeyManager.
+ getFingerprintFromPublicKey(pubKey);
+ imageIcon
+ = OtrActivator.scOtrKeyManager.isVerified(contact, fingerprint)
+ ? verifiedLockedPadlockImage
+ : unverifiedLockedPadlockImage;
+ break;
+ case FINISHED:
+ imageIcon = finishedPadlockImage;
+ break;
+ case PLAINTEXT:
+ imageIcon = unlockedPadlockImage;
+ break;
+ }
+ menuItem.setIcon(imageIcon);
+
+ menu.add(menuItem);
+ SelectedObject selectedObject =
+ new SelectedObject(imageIcon, session);
+ this.menu.setSelected(selectedObject);
+
+ buttonGroup.add(menuItem);
+ menuItem.addActionListener(this);
+ setSelected(menu.getItem(0));
+ }
+ System.out.println("da");
+ updateEnableStatus();
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ for (Map.Entry<Session, JMenuItem> entry : outgoingSessions.entrySet())
+ {
+ JMenuItem menuItem = (JRadioButtonMenuItem) e.getSource();
+ if (menuItem.equals(entry.getValue()))
+ {
+ OtrActivator.scOtrEngine.setOutgoingSession(
+ contact, entry.getKey().getReceiverInstanceTag());
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void outgoingSessionChanged(Contact contact)
+ {
+ buildMenu(contact);
+ }
+
+ /**
+ * Sets the menu to enabled or disabled. The menu is enabled, as soon as it
+ * contains two or more items. If it is empty, it is disabled.
+ */
+ private void updateEnableStatus()
+ {
+ this.menu.setVisible(this.menu.getItemCount() > 1);
+ this.menu.fadeAnimation();
+ }
+}
diff --git a/src/net/java/sip/communicator/service/gui/Container.java b/src/net/java/sip/communicator/service/gui/Container.java
index a493d86..36810a4 100644
--- a/src/net/java/sip/communicator/service/gui/Container.java
+++ b/src/net/java/sip/communicator/service/gui/Container.java
@@ -84,6 +84,11 @@ public class Container
= new Container("CONTAINER_GROUP_RIGHT_BUTTON_MENU");
/**
+ * Chat write panel container.
+ */
+ public static final Container CONTAINER_CHAT_WRITE_PANEL
+ = new Container("CONTAINER_CHAT_WRITE_PANEL");
+ /**
* Chat window "menu bar" container.
*/
public static final Container CONTAINER_CHAT_MENU_BAR