diff --git a/build.xml b/build.xml index 3eee3f9d3..7436b45ff 100644 --- a/build.xml +++ b/build.xml @@ -810,7 +810,8 @@ bundle-plugin-googletalkaccregwizz,bundle-argdelegation-service, bundle-argdelegation,bundle-zrtp4j, bundle-filehistory,bundle-metahistory,bundle-metahistory-slick, - bundle-facebook,bundle-plugin-facebookaccregwizz"/> + bundle-facebook,bundle-plugin-facebookaccregwizz, + bundle-bouncycastle,bundle-plugin-otr"/> @@ -2025,11 +2026,17 @@ org.apache.http.util"/> - + + @@ -2059,6 +2066,37 @@ org.apache.http.util"/> + + + + + + + + + + + + + + + + + + + + + @@ -2068,6 +2106,4 @@ org.apache.http.util"/> prefix="net/java/sip/communicator/slick/metahistory"/> - - diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties index 94ca43481..5aa139e48 100644 --- a/lib/felix.client.run.properties +++ b/lib/felix.client.run.properties @@ -50,7 +50,14 @@ org.osgi.framework.system.packages.extra= org.osgi.framework; version=1.3.0, \ javax.crypto; \ javax.crypto.spec; \ javax.crypto.interfaces; \ - sun.awt.shell; + sun.awt.shell; \ + java.io; \ + java.math; \ + java.nio; \ + java.security; \ + java.security.interfaces; \ + java.security.spec; + felix.auto.start.10= \ reference:file:lib/bundle/org.apache.felix.bundlerepository-1.0.0.jar @@ -83,6 +90,7 @@ felix.auto.start.45= \ reference:file:sc-bundles/branding.jar felix.auto.start.49= \ + reference:file:sc-bundles/bouncycastle.jar \ reference:file:sc-bundles/zrtp4j.jar \ reference:file:sc-bundles/protocol.jar \ reference:file:lib/bundle/httpcore.jar @@ -157,6 +165,7 @@ felix.auto.start.67= \ reference:file:sc-bundles/keybindingChooser.jar \ reference:file:sc-bundles/generalconfig.jar \ reference:file:sc-bundles/dictaccregwizz.jar \ + reference:file:sc-bundles/otr.jar \ reference:file:sc-bundles/facebookaccregwizz.jar #level 68 is for profiler, don't use it or change the build.xml file accordingly diff --git a/lib/felix.unit.test.properties b/lib/felix.unit.test.properties index adb589474..75c97d599 100644 --- a/lib/felix.unit.test.properties +++ b/lib/felix.unit.test.properties @@ -49,7 +49,13 @@ org.osgi.framework.system.packages.extra= org.osgi.framework; ; version=1.3.0, \ javax.crypto; \ javax.crypto.spec; \ javax.crypto.interfaces; \ - sun.awt.shell; + sun.awt.shell; \ + java.io; \ + java.math; \ + java.nio; \ + java.security; \ + java.security.interfaces; \ + java.security.spec; # @@ -88,6 +94,7 @@ felix.auto.start.4= \ reference:file:sc-bundles/netaddr.jar felix.auto.start.5= \ + reference:file:sc-bundles/bouncycastle.jar \ reference:file:sc-bundles/zrtp4j.jar \ reference:file:sc-bundles/protocol.jar \ reference:file:lib/bundle/httpcore.jar diff --git a/lib/installer-exclude/lcrypto-jdk16-143.jar b/lib/installer-exclude/lcrypto-jdk16-143.jar new file mode 100755 index 000000000..1153ea9a8 Binary files /dev/null and b/lib/installer-exclude/lcrypto-jdk16-143.jar differ diff --git a/lib/installer-exclude/otr4j.jar b/lib/installer-exclude/otr4j.jar new file mode 100755 index 000000000..52ee97e85 Binary files /dev/null and b/lib/installer-exclude/otr4j.jar differ diff --git a/lib/installer-exclude/zrtp4j-light.jar b/lib/installer-exclude/zrtp4j-light.jar index ef162243a..455218709 100755 Binary files a/lib/installer-exclude/zrtp4j-light.jar and b/lib/installer-exclude/zrtp4j-light.jar differ diff --git a/resources/images/images.properties b/resources/images/images.properties index 0ec8e45c9..ae1223b4d 100644 --- a/resources/images/images.properties +++ b/resources/images/images.properties @@ -407,3 +407,7 @@ plugin.notificationconfig.FOLDER_ICON=resources/images/plugin/notificationconfig # media configuration form plugin.mediaconfig.PLUGIN_ICON=resources/images/impl/media/media.png + +# otr plugin icons +plugin.otr.ENCRYPTED_ICON=resources/images/plugin/otr/encrypted.png +plugin.otr.DECRYPTED_ICON=resources/images/plugin/otr/decrypted.png \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetBasicInstantMessagingIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetBasicInstantMessagingIcqImpl.java index d9dd612a5..b77482e3a 100644 --- a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetBasicInstantMessagingIcqImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetBasicInstantMessagingIcqImpl.java @@ -169,6 +169,27 @@ public void sendInstantMessage(Contact to, Message message) else messageContent = message.getContent(); + MessageDeliveredEvent msgDeliveryPendingEvt = new MessageDeliveredEvent( + message, to, System.currentTimeMillis()); + + OperationSetInstantMessageTransformIcqImpl messageTransform = + (OperationSetInstantMessageTransformIcqImpl)icqProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgDeliveryPendingEvt != null) + msgDeliveryPendingEvt = transformLayer.messageDeliveryPending(msgDeliveryPendingEvt); + } + } + + if (msgDeliveryPendingEvt == null) + return; + if (to.getPresenceStatus().isOnline()) { //do not add the conversation listener in here. we'll add it @@ -178,10 +199,23 @@ public void sendInstantMessage(Contact to, Message message) else imConversation.sendMessage(new SimpleMessage(messageContent), true); - MessageDeliveredEvent msgDeliveredEvt - = new MessageDeliveredEvent(message, to, System.currentTimeMillis()); + MessageDeliveredEvent msgDeliveredEvt = new MessageDeliveredEvent( + message, to, System.currentTimeMillis()); - fireMessageEvent(msgDeliveredEvt); + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgDeliveredEvt != null) + msgDeliveredEvt = transformLayer.messageDelivered(msgDeliveredEvt); + } + } + + if (msgDeliveredEvt != null) + fireMessageEvent(msgDeliveredEvt); } @@ -258,9 +292,28 @@ public void handleResponse(SnacResponseEvent evt) createMessage(offlineMsgCmd.getContents()), sourceContact, msgDate); - logger.debug("fire msg received for : " + - offlineMsgCmd.getContents()); - fireMessageEvent(msgReceivedEvt); + + OperationSetInstantMessageTransformIcqImpl messageTransform = + (OperationSetInstantMessageTransformIcqImpl)icqProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgReceivedEvt != null) + msgReceivedEvt = transformLayer.messageReceived(msgReceivedEvt); + } + } + + if (msgReceivedEvt != null) + { + logger.debug("fire msg received for : " + + offlineMsgCmd.getContents()); + fireMessageEvent(msgReceivedEvt); + } } else if (snac instanceof OfflineMsgDoneCmd) { @@ -527,11 +580,30 @@ public void gotMessage(Conversation conversation, MessageInfo minfo) msgDate = current; - MessageReceivedEvent msgReceivedEvt - = new MessageReceivedEvent( - newMessage, sourceContact , msgDate ); + MessageReceivedEvent msgReceivedEvt = + new MessageReceivedEvent(newMessage, sourceContact, msgDate); - fireMessageEvent(msgReceivedEvt); + OperationSetInstantMessageTransformIcqImpl messageTransform = + (OperationSetInstantMessageTransformIcqImpl)icqProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgReceivedEvt != null) + msgReceivedEvt = transformLayer.messageReceived(msgReceivedEvt); + } + } + + if (msgReceivedEvt != null) + { + logger.debug("fire msg received for : " + + newMessage); + fireMessageEvent(msgReceivedEvt); + } } public void sentOtherEvent(Conversation conversation, diff --git a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetInstantMessageTransformIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetInstantMessageTransformIcqImpl.java new file mode 100644 index 000000000..43e2821e6 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetInstantMessageTransformIcqImpl.java @@ -0,0 +1,62 @@ +package net.java.sip.communicator.impl.protocol.icq; + +import java.util.*; +import net.java.sip.communicator.service.protocol.*; + +public class OperationSetInstantMessageTransformIcqImpl + implements OperationSetInstantMessageTransform +{ + public final Map> transformLayers = + new Hashtable>(); + + private final int defaultPriority = 1; + + @Override + public void addTransformLayer(TransformLayer transformLayer) + { + this.addTransformLayer(defaultPriority, transformLayer); + } + + @Override + public void addTransformLayer(int priority, TransformLayer transformLayer) + { + synchronized (transformLayers) + { + if (!transformLayers.containsKey(defaultPriority)) + transformLayers.put(defaultPriority, + new Vector()); + + transformLayers.get(defaultPriority).add(transformLayer); + } + } + + @Override + public boolean containsLayer(TransformLayer layer) + { + synchronized (transformLayers) + { + for (Map.Entry> entry : transformLayers + .entrySet()) + { + if (entry.getValue().contains(layer)) + return true; + } + + } + return false; + } + + @Override + public void removeTransformLayer(TransformLayer transformLayer) + { + synchronized (transformLayers) + { + for (Map.Entry> entry : transformLayers + .entrySet()) + { + entry.getValue().remove(transformLayer); + } + + } + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java index 0a35392a0..a172eff75 100644 --- a/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java @@ -455,6 +455,9 @@ protected void initialize(String screenname, if(IcqAccountID.isAIM(accountID.getAccountProperties())) USING_ICQ = false; + supportedOperationSets.put(OperationSetInstantMessageTransform.class.getName(), + new OperationSetInstantMessageTransformIcqImpl()); + //initialize the presence operationset OperationSetPersistentPresence persistentPresence = new OperationSetPersistentPresenceIcqImpl(this, screenname); diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java index 2d401f88c..259f829b4 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java @@ -195,7 +195,29 @@ public void processMessage( org.jivesoftware.smack.packet.Message msg = new org.jivesoftware.smack.packet.Message(); - String content = message.getContent(); + MessageDeliveredEvent msgDeliveryPendingEvt + = new MessageDeliveredEvent( + message, to, System.currentTimeMillis()); + + OperationSetInstantMessageTransformJabberImpl messageTransform = + (OperationSetInstantMessageTransformJabberImpl)jabberProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgDeliveryPendingEvt != null) + msgDeliveryPendingEvt = transformLayer.messageDeliveryPending(msgDeliveryPendingEvt); + } + } + + if (msgDeliveryPendingEvt == null) + return; + + String content = msgDeliveryPendingEvt.getSourceMessage().getContent(); if(message.getContentType().equals(HTML_MIME_TYPE)) { @@ -220,14 +242,27 @@ public void processMessage( MessageEventManager. addNotificationsRequests(msg, true, false, false, true); - + chat.sendMessage(msg); - + MessageDeliveredEvent msgDeliveredEvt = new MessageDeliveredEvent( message, to, System.currentTimeMillis()); - fireMessageEvent(msgDeliveredEvt); + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgDeliveredEvt != null) + msgDeliveredEvt = transformLayer.messageDelivered(msgDeliveredEvt); + } + } + + if (msgDeliveredEvt != null) + fireMessageEvent(msgDeliveredEvt); } catch (XMPPException ex) { @@ -392,7 +427,24 @@ public void processPacket(Packet packet) new MessageDeliveryFailedEvent(newMessage, sourceContact, errorResultCode); - fireMessageEvent(ev); + + OperationSetInstantMessageTransformJabberImpl messageTransform = + (OperationSetInstantMessageTransformJabberImpl)jabberProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (ev != null) + ev = transformLayer.messageDeliveryFailed(ev); + } + } + + if (ev != null) + fireMessageEvent(ev); return; } @@ -411,7 +463,23 @@ public void processPacket(Packet packet) = new MessageReceivedEvent( newMessage, sourceContact , System.currentTimeMillis() ); - fireMessageEvent(msgReceivedEvt); + OperationSetInstantMessageTransformJabberImpl messageTransform = + (OperationSetInstantMessageTransformJabberImpl)jabberProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgReceivedEvt != null) + msgReceivedEvt = transformLayer.messageReceived(msgReceivedEvt); + } + } + + if (msgReceivedEvt != null) + fireMessageEvent(msgReceivedEvt); } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetInstantMessageTransformJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetInstantMessageTransformJabberImpl.java new file mode 100644 index 000000000..02f60e02e --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetInstantMessageTransformJabberImpl.java @@ -0,0 +1,62 @@ +package net.java.sip.communicator.impl.protocol.jabber; + +import java.util.*; +import net.java.sip.communicator.service.protocol.*; + +public class OperationSetInstantMessageTransformJabberImpl + implements OperationSetInstantMessageTransform +{ + public final Map> transformLayers = + new Hashtable>(); + + private final int defaultPriority = 1; + + @Override + public void addTransformLayer(TransformLayer transformLayer) + { + this.addTransformLayer(defaultPriority, transformLayer); + } + + @Override + public void addTransformLayer(int priority, TransformLayer transformLayer) + { + synchronized (transformLayers) + { + if (!transformLayers.containsKey(defaultPriority)) + transformLayers.put(defaultPriority, + new Vector()); + + transformLayers.get(defaultPriority).add(transformLayer); + } + } + + @Override + public boolean containsLayer(TransformLayer layer) + { + synchronized (transformLayers) + { + for (Map.Entry> entry : transformLayers + .entrySet()) + { + if (entry.getValue().contains(layer)) + return true; + } + + } + return false; + } + + @Override + public void removeTransformLayer(TransformLayer transformLayer) + { + synchronized (transformLayers) + { + for (Map.Entry> entry : transformLayers + .entrySet()) + { + entry.getValue().remove(transformLayer); + } + + } + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index 13df3e73a..6cdb119c8 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -642,6 +642,13 @@ protected void initialize(String screenname, OperationSetFileTransfer.class.getName(), fileTransfer); + OperationSetInstantMessageTransform messageTransform + = new OperationSetInstantMessageTransformJabberImpl(); + + supportedOperationSets.put( + OperationSetInstantMessageTransform.class.getName(), + messageTransform); + // Include features we're supporting in plus of the four that // included by smack itself: // http://jabber.org/protocol/si/profile/file-transfer diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java index 08b929cc0..9698bdfd0 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java @@ -7,6 +7,7 @@ package net.java.sip.communicator.impl.protocol.msn; import java.text.*; +import java.util.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; @@ -116,15 +117,51 @@ public void sendInstantMessage(Contact to, Message message) "The specified contact is not an MSN contact." + to); + MessageDeliveredEvent msgDeliveryPendingEvt + = new MessageDeliveredEvent( + message, to, System.currentTimeMillis()); + + OperationSetInstantMessageTransformMsnImpl messageTransform = + (OperationSetInstantMessageTransformMsnImpl)msnProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgDeliveryPendingEvt != null) + msgDeliveryPendingEvt = transformLayer.messageDeliveryPending(msgDeliveryPendingEvt); + } + } + + if (msgDeliveryPendingEvt == null) + return; + msnProvider.getMessenger(). sendText( ((ContactMsnImpl)to).getSourceContact().getEmail(), - message.getContent() + msgDeliveryPendingEvt.getSourceMessage().getContent() ); MessageDeliveredEvent msgDeliveredEvt = new MessageDeliveredEvent(message, to, System.currentTimeMillis()); - fireMessageEvent(msgDeliveredEvt); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgDeliveredEvt != null) + msgDeliveredEvt = transformLayer.messageDelivered(msgDeliveredEvt); + } + } + + if (msgDeliveredEvt != null) + fireMessageEvent(msgDeliveredEvt); } /** @@ -206,8 +243,24 @@ public void instantMessageReceived(MsnSwitchboard switchboard, MessageReceivedEvent msgReceivedEvt = new MessageReceivedEvent( newMessage, sourceContact , System.currentTimeMillis() ); - - fireMessageEvent(msgReceivedEvt); + + OperationSetInstantMessageTransformMsnImpl messageTransform = + (OperationSetInstantMessageTransformMsnImpl)msnProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgReceivedEvt != null) + msgReceivedEvt = transformLayer.messageReceived(msgReceivedEvt); + } + } + + if (msgReceivedEvt != null) + fireMessageEvent(msgReceivedEvt); } /** diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetInstantMessageTransformMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetInstantMessageTransformMsnImpl.java new file mode 100644 index 000000000..b66797173 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetInstantMessageTransformMsnImpl.java @@ -0,0 +1,62 @@ +package net.java.sip.communicator.impl.protocol.msn; + +import java.util.*; +import net.java.sip.communicator.service.protocol.*; + +public class OperationSetInstantMessageTransformMsnImpl + implements OperationSetInstantMessageTransform +{ + public final Map> transformLayers = + new Hashtable>(); + + private final int defaultPriority = 1; + + @Override + public void addTransformLayer(TransformLayer transformLayer) + { + this.addTransformLayer(defaultPriority, transformLayer); + } + + @Override + public void addTransformLayer(int priority, TransformLayer transformLayer) + { + synchronized (transformLayers) + { + if (!transformLayers.containsKey(defaultPriority)) + transformLayers.put(defaultPriority, + new Vector()); + + transformLayers.get(defaultPriority).add(transformLayer); + } + } + + @Override + public boolean containsLayer(TransformLayer layer) + { + synchronized (transformLayers) + { + for (Map.Entry> entry : transformLayers + .entrySet()) + { + if (entry.getValue().contains(layer)) + return true; + } + + } + return false; + } + + @Override + public void removeTransformLayer(TransformLayer transformLayer) + { + synchronized (transformLayers) + { + for (Map.Entry> entry : transformLayers + .entrySet()) + { + entry.getValue().remove(transformLayer); + } + + } + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java index 984d37398..f98ea8d66 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java @@ -261,9 +261,12 @@ protected void initialize(String screenname, { this.accountID = accountID; + supportedOperationSets.put(OperationSetInstantMessageTransform.class.getName(), + new OperationSetInstantMessageTransformMsnImpl()); + //initialize the presence operationset persistentPresence = new OperationSetPersistentPresenceMsnImpl(this); - + supportedOperationSets.put( OperationSetPersistentPresence.class.getName(), persistentPresence); diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetBasicInstantMessagingYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetBasicInstantMessagingYahooImpl.java index b92a8abd1..f21567525 100644 --- a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetBasicInstantMessagingYahooImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetBasicInstantMessagingYahooImpl.java @@ -142,7 +142,30 @@ public void sendInstantMessage(Contact to, Message message) { String toUserID = ((ContactYahooImpl) to).getID(); - byte[] msgBytesToBeSent = message.getContent().trim().getBytes(); + MessageDeliveredEvent msgDeliveryPendingEvt + = new MessageDeliveredEvent( + message, to, System.currentTimeMillis()); + + OperationSetInstantMessageTransformYahooImpl messageTransform = + (OperationSetInstantMessageTransformYahooImpl)yahooProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgDeliveryPendingEvt != null) + msgDeliveryPendingEvt = transformLayer.messageDeliveryPending(msgDeliveryPendingEvt); + } + } + + if (msgDeliveryPendingEvt == null) + return; + + byte[] msgBytesToBeSent = msgDeliveryPendingEvt.getSourceMessage(). + getContent().trim().getBytes(); // split the message in parts with max allowed length // and send them all @@ -173,10 +196,23 @@ public void sendInstantMessage(Contact to, Message message) } MessageDeliveredEvent msgDeliveredEvt - = new MessageDeliveredEvent( - message, to, System.currentTimeMillis()); - - fireMessageEvent(msgDeliveredEvt); + = new MessageDeliveredEvent( + message, to, System.currentTimeMillis()); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgDeliveredEvt != null) + msgDeliveredEvt = transformLayer.messageDelivered(msgDeliveredEvt); + } + } + + if (msgDeliveredEvt != null) + fireMessageEvent(msgDeliveredEvt); } while(msgBytesToBeSent.length > MAX_MESSAGE_LENGTH); } @@ -188,7 +224,24 @@ public void sendInstantMessage(Contact to, Message message) message, to, MessageDeliveryFailedEvent.NETWORK_FAILURE); - fireMessageEvent(evt); + + OperationSetInstantMessageTransformYahooImpl messageTransform = + (OperationSetInstantMessageTransformYahooImpl)yahooProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (evt != null) + evt = transformLayer.messageDeliveryFailed(evt); + } + } + + if (evt != null) + fireMessageEvent(evt); return; } } @@ -430,11 +483,27 @@ private void handleNewMessage(SessionEvent ev) .createVolatileContact(ev.getFrom()); } - MessageReceivedEvent msgReceivedEvt - = new MessageReceivedEvent( - newMessage, sourceContact , System.currentTimeMillis() ); - - fireMessageEvent(msgReceivedEvt); + MessageReceivedEvent msgReceivedEvt + = new MessageReceivedEvent( + newMessage, sourceContact , System.currentTimeMillis() ); + + OperationSetInstantMessageTransformYahooImpl messageTransform = + (OperationSetInstantMessageTransformYahooImpl)yahooProvider.getOperationSet(OperationSetInstantMessageTransform.class); + + for (Map.Entry> entry : messageTransform.transformLayers + .entrySet()) + { + for (Iterator iterator = entry.getValue().iterator(); iterator + .hasNext();) + { + TransformLayer transformLayer = (TransformLayer) iterator.next(); + if (msgReceivedEvt != null) + msgReceivedEvt = transformLayer.messageReceived(msgReceivedEvt); + } + } + + if (msgReceivedEvt != null) + fireMessageEvent(msgReceivedEvt); } } diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetInstantMessageTransformYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetInstantMessageTransformYahooImpl.java new file mode 100644 index 000000000..7117c8239 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetInstantMessageTransformYahooImpl.java @@ -0,0 +1,62 @@ +package net.java.sip.communicator.impl.protocol.yahoo; + +import java.util.*; +import net.java.sip.communicator.service.protocol.*; + +public class OperationSetInstantMessageTransformYahooImpl + implements OperationSetInstantMessageTransform +{ + public final Map> transformLayers = + new Hashtable>(); + + private final int defaultPriority = 1; + + @Override + public void addTransformLayer(TransformLayer transformLayer) + { + this.addTransformLayer(defaultPriority, transformLayer); + } + + @Override + public void addTransformLayer(int priority, TransformLayer transformLayer) + { + synchronized (transformLayers) + { + if (!transformLayers.containsKey(defaultPriority)) + transformLayers.put(defaultPriority, + new Vector()); + + transformLayers.get(defaultPriority).add(transformLayer); + } + } + + @Override + public boolean containsLayer(TransformLayer layer) + { + synchronized (transformLayers) + { + for (Map.Entry> entry : transformLayers + .entrySet()) + { + if (entry.getValue().contains(layer)) + return true; + } + + } + return false; + } + + @Override + public void removeTransformLayer(TransformLayer transformLayer) + { + synchronized (transformLayers) + { + for (Map.Entry> entry : transformLayers + .entrySet()) + { + entry.getValue().remove(transformLayer); + } + + } + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java index 45baf65dc..a2e9a3a4b 100644 --- a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java @@ -318,6 +318,10 @@ protected void initialize(String screenname, { this.accountID = accountID; + supportedOperationSets.put( + OperationSetInstantMessageTransform.class.getName(), + new OperationSetInstantMessageTransformYahooImpl()); + //initialize the presence operationset persistentPresence = new OperationSetPersistentPresenceYahooImpl(this); diff --git a/src/net/java/sip/communicator/plugin/otr/OtrActivator.java b/src/net/java/sip/communicator/plugin/otr/OtrActivator.java new file mode 100644 index 000000000..a60612c2c --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/OtrActivator.java @@ -0,0 +1,159 @@ +package net.java.sip.communicator.plugin.otr; + +import java.util.*; + +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 org.osgi.framework.*; + +public class OtrActivator + implements BundleActivator, ServiceListener +{ + + private BundleContext bundleContext = null; + + private OtrTransformLayer transformLayer = new OtrTransformLayer(); + + private static Logger logger = Logger.getLogger(OtrActivator.class); + + @Override + public void start(BundleContext bc) throws Exception + { + this.bundleContext = bc; + bc.addServiceListener(this); + + ServiceReference[] protocolProviderRefs = null; + try + { + protocolProviderRefs = + bc.getServiceReferences( + ProtocolProviderService.class.getName(), null); + } + catch (InvalidSyntaxException ex) + { + logger.error("Error while retrieving service refs", ex); + return; + } + + if (protocolProviderRefs != null) + { + logger.debug("Found " + protocolProviderRefs.length + + " already installed providers."); + for (int i = 0; i < protocolProviderRefs.length; i++) + { + ProtocolProviderService provider = + (ProtocolProviderService) bc + .getService(protocolProviderRefs[i]); + + this.handleProviderAdded(provider); + } + } + + Hashtable containerFilter = + new Hashtable(); + containerFilter.put(Container.CONTAINER_ID, + Container.CONTAINER_CONTACT_RIGHT_BUTTON_MENU.getID()); + + bundleContext.registerService(PluginComponent.class.getName(), + new OtrMenu(ResourceManagementServiceUtils + .getService(bc)), containerFilter); + } + + private void handleProviderAdded(ProtocolProviderService provider) + { + OperationSetInstantMessageTransform opSetMessageTransform = + (OperationSetInstantMessageTransform) provider + .getOperationSet(OperationSetInstantMessageTransform.class); + + if (opSetMessageTransform != null) + { + opSetMessageTransform.addTransformLayer(transformLayer); + } + else + { + logger.trace("Service did not have a transform op. set."); + } + + } + + @Override + public void stop(BundleContext bc) throws Exception + { + // start listening for newly register or removed protocol providers + bc.removeServiceListener(this); + + ServiceReference[] protocolProviderRefs = null; + try + { + protocolProviderRefs = + bc.getServiceReferences( + ProtocolProviderService.class.getName(), null); + } + catch (InvalidSyntaxException ex) + { + // this shouldn't happen since we're providing no parameter string + // but let's log just in case. + logger.error("Error while retrieving service refs", ex); + return; + } + + // in case we found any + if (protocolProviderRefs != null) + { + for (int i = 0; i < protocolProviderRefs.length; i++) + { + ProtocolProviderService provider = + (ProtocolProviderService) bc + .getService(protocolProviderRefs[i]); + + this.handleProviderRemoved(provider); + } + } + } + + private void handleProviderRemoved(ProtocolProviderService provider) + { + // check whether the provider has a basic im operation set + OperationSetInstantMessageTransform opSetMessageTransform = + (OperationSetInstantMessageTransform) provider + .getOperationSet(OperationSetInstantMessageTransform.class); + + if (opSetMessageTransform != null) + { + opSetMessageTransform.removeTransformLayer(transformLayer); + } + } + + @Override + public void serviceChanged(ServiceEvent serviceEvent) + { + Object sService = + bundleContext.getService(serviceEvent.getServiceReference()); + + logger.trace("Received a service event for: " + + sService.getClass().getName()); + + // we don't care if the source service is not a protocol provider + if (!(sService instanceof ProtocolProviderService)) + { + return; + } + + logger.debug("Service is a protocol provider."); + if (serviceEvent.getType() == ServiceEvent.REGISTERED) + { + logger.debug("Handling registration of a new Protocol Provider."); + + this.handleProviderAdded((ProtocolProviderService) sService); + } + else if (serviceEvent.getType() == ServiceEvent.UNREGISTERING) + { + this.handleProviderRemoved((ProtocolProviderService) sService); + } + + } + +} diff --git a/src/net/java/sip/communicator/plugin/otr/OtrMenu.java b/src/net/java/sip/communicator/plugin/otr/OtrMenu.java new file mode 100644 index 000000000..0ddaa79a1 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/OtrMenu.java @@ -0,0 +1,93 @@ +package net.java.sip.communicator.plugin.otr; + +import java.awt.Component; +import java.awt.event.*; + +import javax.swing.*; + +import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.resources.*; + +@SuppressWarnings("serial") +public class OtrMenu + extends JMenu + implements PluginComponent, ActionListener +{ + private static final String imageID = "plugin.otr.DECRYPTED_ICON"; + + private ResourceManagementService resourceService; + + public OtrMenu(ResourceManagementService resourceService) + { + super("Encryption"); + this.setToolTipText("Options for OTR Encryption"); + + if (resourceService != null) + this.setIcon(resourceService.getImage(imageID)); + + // TODO Internationalize Strings... + JMenuItem mitmStartOtr = new JMenuItem("Start Private Conversation"); + JMenuItem mitmEndOtr = new JMenuItem("End Private Conversation"); + JMenuItem mitmRefreshOtr = + new JMenuItem("Refresh Private Conversation"); + JMenuItem mitmAuthenticateBuddy = new JMenuItem("Authenticate Buddy"); + JMenuItem mitmWhatsThis = new JMenuItem("What's this?"); + + // Shown if we don't have an OTR session. + this.add(mitmStartOtr); + // Shown if we have an OTR session. + this.add(mitmEndOtr); + this.add(mitmRefreshOtr); + this.add(mitmAuthenticateBuddy); + this.add(mitmWhatsThis); + } + + @Override + public String getConstraints() + { + return null; + } + + public Component getComponent() + { + return this; + } + + @Override + public Container getContainer() + { + return Container.CONTAINER_CONTACT_RIGHT_BUTTON_MENU; + } + + @Override + public int getPositionIndex() + { + return -1; + } + + @Override + public boolean isNativeComponent() + { + return false; + } + + private MetaContact metaContact; + + @Override + public void setCurrentContact(MetaContact metaContact) + { + this.metaContact = metaContact; + } + + @Override + public void setCurrentContactGroup(MetaContactGroup metaGroup) + { + } + + @Override + public void actionPerformed(ActionEvent e) + { + } + +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/plugin/otr/OtrTransformLayer.java b/src/net/java/sip/communicator/plugin/otr/OtrTransformLayer.java new file mode 100644 index 000000000..3cd39bb3f --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/OtrTransformLayer.java @@ -0,0 +1,201 @@ +package net.java.sip.communicator.plugin.otr; + +import java.security.*; +import java.util.*; + +import net.java.otr4j.*; +import net.java.otr4j.message.MessageConstants; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +public class OtrTransformLayer + implements TransformLayer +{ + private static Logger logger = Logger.getLogger(TransformLayer.class); + + private UserState us = new UserState(new OTR4jListener() + { + @Override + public void showWarning(String warn) + { + logger.warn(warn); + } + + @Override + public void showError(String err) + { + logger.error(err); + } + + @Override + public void injectMessage(String messageText, String account, + String user, String protocol) + { + Contact contact = getContact(account, user, protocol); + OperationSetBasicInstantMessaging imOpSet = + (OperationSetBasicInstantMessaging) contact + .getProtocolProvider().getOperationSet( + OperationSetBasicInstantMessaging.class); + + Message message = imOpSet.createMessage(messageText); + imOpSet.sendInstantMessage(contact, message); + } + + @Override + public int getPolicy(ConnContext arg0) + { + return PolicyConstants.ALLOW_V2; + } + + @Override + public KeyPair getKeyPair(String arg0, String arg1) + throws NoSuchAlgorithmException + { + try + { + return CryptoUtils.generateDsaKeyPair(); + } + catch (Exception e) + { + return null; + } + } + }); + + private List contacts = new Vector(); + + private Contact getContact(String account, String user, String protocol) + { + for (Contact c : contacts) + { + String cuser = c.getAddress(); + ProtocolProviderService cprotoProvider = c.getProtocolProvider(); + String caccount = cprotoProvider.getAccountID().toString(); + String cprotocol = cprotoProvider.getProtocolName(); + + if (user.equals(cuser) && account.equals(caccount) + && protocol.equals(cprotocol)) + return c; + } + return null; + } + + private void addContact(Contact contact) + { + if (contact == null) + return; + + String user = contact.getAddress(); + ProtocolProviderService protoProvider = contact.getProtocolProvider(); + String account = protoProvider.getAccountID().toString(); + String protocol = protoProvider.getProtocolName(); + + for (Contact c : contacts) + { + String cuser = c.getAddress(); + ProtocolProviderService cprotoProvider = c.getProtocolProvider(); + String caccount = cprotoProvider.getAccountID().toString(); + String cprotocol = cprotoProvider.getProtocolName(); + + if (user.equals(cuser) && account.equals(caccount) + && protocol.equals(cprotocol)) + return; + } + + contacts.add(contact); + } + + @Override + public MessageDeliveredEvent messageDelivered(MessageDeliveredEvent evt) + { + if (evt.getSourceMessage().getContent().contains(MessageConstants.BASE_HEAD)) + return null; + else + return evt; + } + + @Override + public MessageDeliveryFailedEvent messageDeliveryFailed( + MessageDeliveryFailedEvent evt) + { + return evt; + } + + @Override + public MessageDeliveredEvent messageDeliveryPending( + MessageDeliveredEvent evt) + { + Contact contact = evt.getDestinationContact(); + addContact(contact); + String user = contact.getAddress(); + + ProtocolProviderService protoProvider = contact.getProtocolProvider(); + String account = protoProvider.getAccountID().toString(); + String protocol = protoProvider.getProtocolName(); + + Message msg = evt.getSourceMessage(); + String msgContent = msg.getContent(); + + OperationSetBasicInstantMessaging imOpSet = + (OperationSetBasicInstantMessaging) contact.getProtocolProvider() + .getOperationSet(OperationSetBasicInstantMessaging.class); + + String processedMessageContent = + us.handleSendingMessage(user, account, protocol, msgContent); + + if (processedMessageContent == null + || processedMessageContent.length() < 1) + return null; + + if (processedMessageContent.equals(msgContent)) + return evt; + + Message processedMessage = + imOpSet.createMessage(processedMessageContent); + + MessageDeliveredEvent processedEvent = + new MessageDeliveredEvent(processedMessage, contact, evt + .getTimestamp()); + + return processedEvent; + } + + @Override + public MessageReceivedEvent messageReceived(MessageReceivedEvent evt) + { + Contact contact = evt.getSourceContact(); + addContact(contact); + String user = contact.getAddress(); + + ProtocolProviderService protoProvider = contact.getProtocolProvider(); + String account = protoProvider.getAccountID().toString(); + String protocol = protoProvider.getProtocolName(); + + Message msg = evt.getSourceMessage(); + String msgContent = msg.getContent(); + + OperationSetBasicInstantMessaging imOpSet = + (OperationSetBasicInstantMessaging) contact.getProtocolProvider() + .getOperationSet(OperationSetBasicInstantMessaging.class); + + String processedMessageContent = + us.handleReceivingMessage(user, account, protocol, msgContent); + + if (processedMessageContent == null + || processedMessageContent.length() < 1) + return null; + + if (processedMessageContent.equals(msgContent)) + return evt; + + Message processedMessage = + imOpSet.createMessage(processedMessageContent); + + MessageReceivedEvent processedEvent = + new MessageReceivedEvent(processedMessage, contact, evt + .getTimestamp()); + + return processedEvent; + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf b/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf new file mode 100644 index 000000000..14960f990 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf @@ -0,0 +1,25 @@ +Bundle-Activator: net.java.sip.communicator.plugin.otr.OtrActivator +Bundle-Name: OTR (Off-the-Record) Messaging +Bundle-Description: Support for secure, Off The Record messaging in SIP Communicator +Bundle-Vendor: sip-communicator.org +Bundle-Version: 0.0.1 +System-Bundle: yes +Import-Package: org.osgi.framework, + net.java.sip.communicator.util, + net.java.sip.communicator.service.gui, + net.java.sip.communicator.service.protocol, + net.java.sip.communicator.service.protocol.event, + net.java.sip.communicator.service.contactlist, + net.java.sip.communicator.service.resources, + javax.swing, + javax.crypto, + javax.crypto.interfaces, + javax.crypto.spec, + org.bouncycastle.crypto, + org.bouncycastle.crypto.generators, + org.bouncycastle.crypto.params, + org.bouncycastle.crypto.signers, + org.bouncycastle.crypto.engines, + org.bouncycastle.crypto.modes, + org.bouncycastle.util, + org.bouncycastle.util.encoders \ No newline at end of file diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetInstantMessageTransform.java b/src/net/java/sip/communicator/service/protocol/OperationSetInstantMessageTransform.java index 2ab9c1a20..460cbd6ad 100644 --- a/src/net/java/sip/communicator/service/protocol/OperationSetInstantMessageTransform.java +++ b/src/net/java/sip/communicator/service/protocol/OperationSetInstantMessageTransform.java @@ -23,6 +23,7 @@ * */ public interface OperationSetInstantMessageTransform + extends OperationSet { /** * Adds a transformation layer to this protocol provider using a default