From c164b0aa0a2315d9b0c0f32a0fdb4826ebb7ff9d Mon Sep 17 00:00:00 2001 From: Marin Date: Fri, 20 Dec 2013 13:29:16 +0200 Subject: [PATCH] Updates the otr plugin to use the latest version of the OTR protocol. --- lib/installer-exclude/otr4j.jar | Bin 86200 -> 94169 bytes resources/languages/resources.properties | 4 + .../impl/gui/main/chat/ChatPanel.java | 2 + .../impl/gui/main/chat/ChatWritePanel.java | 104 ++++++ .../communicator/plugin/otr/OtrActivator.java | 20 +- .../plugin/otr/OtrConfigurator.java | 29 ++ .../plugin/otr/OtrContactMenu.java | 18 +- .../plugin/otr/OtrMetaContactButton.java | 25 +- .../plugin/otr/OtrWeakListener.java | 24 ++ .../communicator/plugin/otr/ScOtrEngine.java | 42 +++ .../plugin/otr/ScOtrEngineImpl.java | 140 +++++++- .../plugin/otr/ScOtrEngineListener.java | 4 + .../plugin/otr/ScOtrKeyManager.java | 13 +- .../plugin/otr/ScOtrKeyManagerImpl.java | 111 ++++-- .../FingerprintAuthenticationPanel.java | 18 +- .../authdialog/KnownFingerprintsPanel.java | 46 ++- .../KnownFingerprintsTableModel.java | 94 +++++- .../OtrBuddyAuthenticationDialog.java | 14 +- .../OtrConfigurationPanel.java | 3 +- .../OtrV3OutgoingSessionSwitcher.java | 319 ++++++++++++++++++ .../communicator/service/gui/Container.java | 5 + 21 files changed, 955 insertions(+), 80 deletions(-) rename src/net/java/sip/communicator/plugin/otr/{ => authdialog}/OtrConfigurationPanel.java (99%) create mode 100644 src/net/java/sip/communicator/plugin/otr/authdialog/OtrV3OutgoingSessionSwitcher.java diff --git a/lib/installer-exclude/otr4j.jar b/lib/installer-exclude/otr4j.jar index fc229151d708df24d7da3207e46ef1145d196396..f755a6a3f9623e8033915d1714af33be35f35b64 100644 GIT binary patch delta 51028 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�z@ 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 W08CT~C_^>$Nxpd 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 diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index 9a4252d56..00bb3b9a8 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -1611,6 +1611,10 @@ plugin.otr.activator.fallbackmessage={0} is try Off-The-Record conversation with you. However, your software does not support \ Off-The-Record messaging. For more information see \ http://en.wikipedia.org/wiki/Off-the-Record_Messaging +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 4853797e2..9a8032590 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 void actionPerformed(ActionEvent arg0) topSplitPane.setRightComponent(rightPanel); topPanel.add(topSplitPane); + } else { @@ -354,6 +355,7 @@ public void actionPerformed(ActionEvent arg0) 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 84705969c..14afdc8d7 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.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.skin.*; import org.jitsi.service.configuration.*; +import org.osgi.framework.*; /** * The ChatWritePanel 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 void run() 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 PluginComponentEvent 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 PluginComponentEvent 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 ae56e3907..5e359429c 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 @@ 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 void start(Object dependentService) 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 void start(Object dependentService) // 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 dbd9c870a..a4c47e4cf 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 int getPropertyInt(String id, int defaultValue) { return OtrActivator.configService.getInt(getID(id), defaultValue); } + + /** + * Appends value 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 getAppendedProperties(String id) + { + String listProperties = + (String) OtrActivator.configService.getProperty(getID(id)); + + if (listProperties == null) return new ArrayList(); + + 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 040f93215..613b0f874 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 @@ private void updateIcon() 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 @@ private void updateIcon() 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 2984fb75f..40810ce2e 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 @@ import java.awt.*; import java.awt.event.*; import java.io.*; +import java.security.*; import javax.imageio.*; @@ -272,12 +273,17 @@ private void setStatus(ScSessionStatus status) 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 @@ private void setStatus(ScSessionStatus status) .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 423cf23f2..b94a9bf49 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 void sessionStatusChanged(Contact contact) if (l != null) l.sessionStatusChanged(contact); } + + /** + * Forwards the event/notification to the associated + * T 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 + * T 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 853c5fc5b..cade91025 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.*; /** @@ -99,6 +103,42 @@ public abstract void respondSmp( */ 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. + * + * https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html + *

+ * 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 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. + * + * https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html + *

+ * 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 InstanceTag. + * + * @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}. * @@ -135,6 +175,8 @@ public abstract void respondSmp( */ 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 b3765face..137122c80 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.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 void askForSecret(SessionID sessionID, String question) 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 void verify(SessionID sessionID, boolean approved) 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 String getFallbackMessage(SessionID sessionID) "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 void sessionStatusChanged(SessionID sessionID) 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 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 void sessionStatusChanged(SessionID sessionID) 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 void sessionStatusChanged(SessionID sessionID) 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 void abortSmp(Contact contact) + 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 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 790fc160a..8ab95b892 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 bc83cd7a5..47ca22d0e 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 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 37adc6325..893353032 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 void removeListener(ScOtrKeyManagerListener l) } } - 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 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 byte[] getLocalFingerprintRaw(AccountID account) } } - 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 26f88662f..31d6848ca 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 @@ private void initComponents() 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 @@ private void loadContact() // 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 void changedUpdate(DocumentEvent e) 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 void compareFingerprints() 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 256814a81..099bb67a9 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.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 KnownFingerprintsPanel() this.setPreferredSize(new Dimension(400, 200)); - openContact(getSelectedContact()); + openContact(getSelectedContact(), getSelectedFingerprint()); } /** @@ -74,7 +74,7 @@ public void valueChanged(ListSelectionEvent e) if (e.getValueIsAdjusting()) return; - openContact(getSelectedContact()); + openContact(getSelectedContact(), getSelectedFingerprint()); } }); @@ -88,14 +88,15 @@ public void valueChanged(ListSelectionEvent e) 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 void actionPerformed(ActionEvent arg0) 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 @@ private Contact getSelectedContact() 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 @@ private Contact getSelectedContact() * 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 @@ private void openContact(Contact contact) { 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 1b32f26dd..41dbbfbb3 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 @@ import java.awt.*; import java.util.*; +import java.util.List; import javax.swing.table.*; @@ -25,6 +26,7 @@ */ 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 allContacts = new Vector(); + public final LinkedHashMap> allContactsFingerprints = + new LinkedHashMap>(); public KnownFingerprintsTableModel() { @@ -76,10 +79,15 @@ public KnownFingerprintsTableModel() Iterator 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 String getColumnName(int column) */ 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 Object getValueAt(int row, int column) 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> entry : + allContactsFingerprints.entrySet()) + { + boolean found = false; + contact = entry.getKey(); + List 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> entry : + allContactsFingerprints.entrySet()) + { + boolean found = false; + List 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> entry : + allContactsFingerprints.entrySet()) + rowCount += entry.getValue().size(); + return rowCount; } /** @@ -151,4 +216,13 @@ public int getColumnCount() { 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 b67ce810c..f82c01d5a 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 @@ 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 @@ else if (authenticationMethod.equals(am[2])) 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 similarity index 99% rename from src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java rename to src/net/java/sip/communicator/plugin/otr/authdialog/OtrConfigurationPanel.java index 79ce6bcf6..9435f2395 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 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 000000000..4ced8c15e --- /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 outgoingSessions + = new HashMap(); + 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( + 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 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 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 a493d86f4..36810a400 100644 --- a/src/net/java/sip/communicator/service/gui/Container.java +++ b/src/net/java/sip/communicator/service/gui/Container.java @@ -83,6 +83,11 @@ public class Container public static final Container CONTAINER_GROUP_RIGHT_BUTTON_MENU = 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. */