aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/impl/protocol
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-03-11 22:15:03 +0100
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-03-11 22:15:03 +0100
commit85901329b0794b136b96bf745f4ab1572806fc89 (patch)
treef23da7e97cae727f39d825f0fef8348cffb238e4 /src/net/java/sip/communicator/impl/protocol
parent3db2e44f186c59429901b2c899e139ea60117a55 (diff)
parentcf5da997da8820b4050f5b87ee9440a0ede36d1f (diff)
downloadjitsi-85901329b0794b136b96bf745f4ab1572806fc89.zip
jitsi-85901329b0794b136b96bf745f4ab1572806fc89.tar.gz
jitsi-85901329b0794b136b96bf745f4ab1572806fc89.tar.bz2
Merge commit 'cf5da99'HEADmaster
Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
Diffstat (limited to 'src/net/java/sip/communicator/impl/protocol')
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ContactDictImpl.java343
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ContactGroupDictImpl.java588
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictAccountID.java70
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictActivator.java146
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictStatusEnum.java88
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/MessageDictImpl.java46
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/OperationSetBasicInstantMessagingDictImpl.java412
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/OperationSetPersistentPresenceDictImpl.java988
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ProtocolIconDictImpl.java133
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderFactoryDictImpl.java200
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderServiceDictImpl.java364
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/dict.provider.manifest.mf15
-rw-r--r--src/net/java/sip/communicator/impl/protocol/gibberish/ContactGroupGibberishImpl.java25
-rw-r--r--src/net/java/sip/communicator/impl/protocol/icq/icq.provider.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/impl/protocol/irc/OperationSetMultiUserChatIrcImpl.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/AnonymousLoginStrategy.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java3287
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java44
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java21
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java141
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/JabberLoginStrategy.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesCandidate.java4
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesHarvester.java21
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/LoginByClientCertificateStrategy.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/MobileIndicator.java8
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java13
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java7
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java223
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetJitsiMeetToolsJabberImpl.java10
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java4
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java17
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java1166
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java560
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderFactoryJabberImpl.java10
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java229
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java1054
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ScServiceDiscoveryManager.java13
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/SmackV3InteroperabilityLayer.java91
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java1922
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/DefaultPacketExtensionProvider.java11
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java113
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/UserCapsNodeListener.java10
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriBuilder.java629
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriConferenceIQ.java69
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriIQProvider.java131
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriStreamConnector.java144
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ShutdownIQ.java134
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/health/HealthCheckIQ.java (renamed from src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/GracefulShutdownIQ.java)21
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/health/HealthCheckIQProvider.java94
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriIq.java413
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriIqProvider.java112
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriStatusPacketExt.java121
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/RecordingStatus.java126
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/XMPPErrorPE.java93
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CandidatePacketExtension.java878
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java12
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java21
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQ.java25
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java196
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/ComponentVersionsExtension.java135
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/SSRCInfoPacketExtension.java15
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/VideoMutedExtension.java70
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java9
-rw-r--r--src/net/java/sip/communicator/impl/protocol/mock/MockContactGroup.java25
-rw-r--r--src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java9
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/AddressResolverImpl.java12
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java48
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java121
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java26
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java43
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java15
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetJitsiMeetToolsSipImpl.java10
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetMessageWaitingSipImpl.java4
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java34
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyBLFSipImpl.java72
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java182
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ProxyRouter.java26
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java5
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java3
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/UriHandlerSipImpl.java33
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/net/ManualProxyConnection.java226
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/net/ProxyConnection.java360
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/net/RFC5922Matcher.java418
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/net/SslNetworkLayer.java6
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java31
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf18
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ContactGroupSSHImpl.java580
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ContactSSH.java370
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ContactSSHImpl.java918
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ContactTimerSSHImpl.java116
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/FileTransferSSHImpl.java96
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/MessageSSHImpl.java63
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/OperationSetBasicInstantMessagingSSHImpl.java312
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java161
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/OperationSetPersistentPresenceSSHImpl.java980
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ProtocolIconSSHImpl.java159
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderFactorySSH.java49
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderFactorySSHImpl.java179
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderServiceSSHImpl.java662
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/Resources.java53
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/SSHAccountID.java45
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/SSHActivator.java145
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/SSHContactInfo.java352
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/SSHFileTransferDaemon.java468
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/SSHReaderDaemon.java211
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/SSHStatusEnum.java138
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/SSHUserInfo.java164
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/ssh.provider.manifest.mf20
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/AbstractContactGroupYahooImpl.java40
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/AdHocChatRoomInvitationYahooImpl.java90
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/AdHocChatRoomYahooImpl.java581
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/ContactGroupYahooImpl.java445
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/ContactYahooImpl.java397
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/FileTransferImpl.java117
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/IncomingFileTransferRequestYahooImpl.java190
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/MessageYahooImpl.java48
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetAdHocMultiUserChatYahooImpl.java714
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetBasicInstantMessagingYahooImpl.java649
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetFileTransferYahooImpl.java466
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetPersistentPresenceYahooImpl.java954
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetTypingNotificationsYahooImpl.java153
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolIconYahooImpl.java173
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderFactoryYahooImpl.java172
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java574
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/RootContactGroupYahooImpl.java280
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/ServerStoredContactListYahooImpl.java1274
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/VolatileContactGroupYahooImpl.java97
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/YahooAccountID.java42
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/YahooActivator.java145
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/YahooSession.java76
-rw-r--r--src/net/java/sip/communicator/impl/protocol/yahoo/yahoo.provider.manifest.mf22
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/BonjourService.java706
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java499
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ContactGroupZeroconfImpl.java595
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ContactZeroconfImpl.java468
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/MessageZeroconfImpl.java234
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetBasicInstantMessagingZeroconfImpl.java192
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetPersistentPresenceZeroconfImpl.java852
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetTypingNotificationsZeroconfImpl.java83
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolIconZeroconfImpl.java189
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderFactoryZeroconfImpl.java120
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderServiceZeroconfImpl.java302
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfAccountID.java96
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfActivator.java132
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfStatusEnum.java136
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSCache.java294
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSConstants.java160
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSEntry.java183
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSIncoming.java524
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSListener.java39
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSOutgoing.java405
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSQuestion.java68
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSRecord.java796
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSState.java139
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/HostInfo.java173
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/JmDNS.java3048
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceEvent.java124
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceInfo.java785
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceListener.java57
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceTypeListener.java37
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/zeroconf.provider.manifest.mf12
165 files changed, 8453 insertions, 34524 deletions
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ContactDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ContactDictImpl.java
deleted file mode 100644
index 924c0f7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/ContactDictImpl.java
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import net.java.dict4j.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * An implementation of a Dict contact
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class ContactDictImpl
- extends AbstractContact
-{
- private Logger logger = Logger.getLogger(ContactDictImpl.class);
-
- /**
- * Icon
- */
- private static byte[] icon = DictActivator.getResources()
- .getImageInBytes("service.protocol.dict.DICT_64x64");
-
- /**
- * The id of the contact.
- */
- private String contactID = null;
-
- /**
- * The provider that created us.
- */
- private ProtocolProviderServiceDictImpl parentProvider = null;
-
- /**
- * The group that belong to.
- */
- private ContactGroupDictImpl parentGroup = null;
-
- /**
- * The presence status of the contact.
- */
- private PresenceStatus presenceStatus = DictStatusEnum.ONLINE;
-
- /**
- * Determines whether this contact is persistent, i.e. member of the contact
- * list or whether it is here only temporarily.
- */
- private boolean isPersistent = true;
-
- /**
- * Determines whether the contact has been resolved (i.e. we have a
- * confirmation that it is still on the server contact list).
- */
- private boolean isResolved = true;
-
- /**
- * The string in a "humain readable and understandable representation" of
- * the dictionnaire. In brief this is a short description of the dictionary.
- */
- private String dictName = null;
-
- /**
- * Creates an instance of a meta contact with the specified string used
- * as a name and identifier.
- *
- * @param databaseCode The identifier of this contact (also used as a name).
- * @param parentProvider The provider that created us.
- */
- public ContactDictImpl(
- String databaseCode,
- ProtocolProviderServiceDictImpl parentProvider)
- {
- this.contactID = databaseCode;
- this.parentProvider = parentProvider;
- }
-
- /**
- * This method is only called when the contact is added to a new
- * <tt>ContactGroupDictImpl</tt> by the
- * <tt>ContactGroupDictImpl</tt> itself.
- *
- * @param newParentGroup the <tt>ContactGroupDictImpl</tt> that is now
- * parent of this <tt>ContactDictImpl</tt>
- */
- void setParentGroup(ContactGroupDictImpl newParentGroup)
- {
- this.parentGroup = newParentGroup;
- }
-
- /**
- * Returns a String that can be used for identifying the contact.
- *
- * @return a String id representing and uniquely identifying the contact.
- */
- public String getContactID()
- {
- return contactID;
- }
-
- /**
- * Returns a String that can be used for identifying the contact.
- *
- * @return a String id representing and uniquely identifying the contact.
- */
- public String getAddress()
- {
- return contactID;
- }
-
- /**
- * Returns a String that could be used by any user interacting modules
- * for referring to this contact.
- *
- * @return a String that can be used for referring to this contact when
- * interacting with the user.
- */
- public String getDisplayName()
- {
- if (dictName == null)
- {
- if (this.contactID.equals("*"))
- {
- this.dictName = DictActivator.getResources()
- .getI18NString("plugin.dictaccregwizz.ANY_DICTIONARY");
- }
- else if (this.contactID.equals("!"))
- {
- this.dictName = DictActivator.getResources()
- .getI18NString("plugin.dictaccregwizz.FIRST_MATCH");
- }
- else
- {
- try
- {
- this.dictName = this.parentProvider.getConnection()
- .getDictionaryName(this.contactID);
- }
- catch (DictException dx)
- {
- logger.error("Error while getting dictionary long name", dx);
- }
-
- if (this.dictName == null)
- this.dictName = this.contactID;
- }
- }
-
- return dictName;
- }
-
- /**
- * Returns a byte array containing an image (most often a photo or an
- * avatar) that the contact uses as a representation.
- *
- * @return byte[] an image representing the contact.
- */
- public byte[] getImage()
- {
- return icon;
- }
-
- /**
- * Returns the status of the contact.
- *
- * @return always DictStatusEnum.ONLINE.
- */
- public PresenceStatus getPresenceStatus()
- {
- return this.presenceStatus;
- }
-
- /**
- * Sets <tt>dictPresenceStatus</tt> as the PresenceStatus that this
- * contact is currently in.
- * @param dictPresenceStatus the <tt>DictPresenceStatus</tt>
- * currently valid for this contact.
- */
- public void setPresenceStatus(PresenceStatus dictPresenceStatus)
- {
- this.presenceStatus = dictPresenceStatus;
- }
-
- /**
- * Returns a reference to the protocol provider that created the contact.
- *
- * @return a refererence to an instance of the ProtocolProviderService
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return parentProvider;
- }
-
- /**
- * Determines whether or not this contact represents our own identity.
- *
- * @return true in case this is a contact that represents ourselves and
- * false otherwise.
- */
- public boolean isLocal()
- {
- return false;
- }
-
- /**
- * Returns the group that contains this contact.
- * @return a reference to the <tt>ContactGroupDictImpl</tt> that
- * contains this contact.
- */
- public ContactGroup getParentContactGroup()
- {
- return this.parentGroup;
- }
-
- /**
- * Returns a string representation of this contact, containing most of its
- * representative details.
- *
- * @return a string representation of this contact.
- */
- @Override
- public String toString()
- {
- StringBuffer buff
- = new StringBuffer("ContactDictImpl[ DisplayName=")
- .append(getDisplayName()).append("]");
-
- return buff.toString();
- }
-
- /**
- * Determines whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @return true if the contact is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Specifies whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @param isPersistent true if the contact is persistent and false
- * otherwise.
- */
- public void setPersistent(boolean isPersistent)
- {
- this.isPersistent = isPersistent;
- }
-
-
- /**
- * Returns null as no persistent data is required and the contact address is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- *
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Return the current status message of this contact.
- *
- * @return null as the protocol has currently no support of status messages
- */
- public String getStatusMessage()
- {
- return null;
- }
-
- /**
- * Makes the contact resolved or unresolved.
- *
- * @param resolved true to make the contact resolved; false to
- * make it unresolved
- */
- public void setResolved(boolean resolved)
- {
- this.isResolved = resolved;
- }
-
- /**
- * Returns the persistent presence operation set that this contact belongs
- * to.
- *
- * @return the <tt>OperationSetPersistentPresenceGibberishImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetPersistentPresenceDictImpl
- getParentPresenceOperationSet()
- {
- return (OperationSetPersistentPresenceDictImpl) parentProvider
- .getOperationSet(OperationSetPersistentPresence.class);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ContactGroupDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ContactGroupDictImpl.java
deleted file mode 100644
index e52ce96..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/ContactGroupDictImpl.java
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * A simple, straightforward implementation of a dict ContactGroup. Since
- * the Dict protocol is not a real one, we simply store all group details
- * in class fields. You should know that when implementing a real protocol,
- * the contact group implementation would rather encapsulate group objects from
- * the protocol stack and group property values should be returned by consulting
- * the encapsulated object.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class ContactGroupDictImpl
- implements ContactGroup
-{
-
- /**
- * The name of this Dict contact group.
- */
- private String groupName = null;
-
- /**
- * The list of this group's members.
- */
- private List<Contact> contacts = new ArrayList<Contact>();
-
- /**
- * The list of sub groups belonging to this group.
- */
- private List<ContactGroup> subGroups = new ArrayList<ContactGroup>();
-
- /**
- * The group that this group belongs to (or null if this is the root group).
- */
- private ContactGroupDictImpl parentGroup = null;
-
- /**
- * Determines whether this group is really in the contact list or whether
- * it is here only temporarily and will be gone next time we restart.
- */
- private boolean isPersistent = true;
-
- /**
- * The protocol provider that created us.
- */
- private ProtocolProviderServiceDictImpl parentProvider = null;
-
- /**
- * Determines whether this group has been resolved on the server.
- * Unresolved groups are groups that were available on previous runs and
- * that the meta contact list has stored. During all next runs, when
- * bootstrapping, the meta contact list would create these groups as
- * unresolved. Once a protocol provider implementation confirms that the
- * groups are still on the server, it would issue an event indicating that
- * the groups are now resolved.
- */
- private boolean isResolved = true;
-
- /**
- * An id uniquely identifying the group. For many protocols this could be
- * the group name itself.
- */
- private String uid = null;
- private static final String UID_SUFFIX = ".uid";
-
- /**
- * Creates a ContactGroupDictImpl with the specified name.
- *
- * @param groupName the name of the group.
- * @param parentProvider the protocol provider that created this group.
- */
- public ContactGroupDictImpl(
- String groupName,
- ProtocolProviderServiceDictImpl parentProvider)
- {
- this.groupName = groupName;
- this.uid = groupName + UID_SUFFIX;
- this.parentProvider = parentProvider;
- }
-
- /**
- * Determines whether the group may contain subgroups or not.
- *
- * @return always true in this implementation.
- */
- public boolean canContainSubgroups()
- {
- return true;
- }
-
- /**
- * Returns the protocol provider that this group belongs to.
- * @return a regerence to the ProtocolProviderService instance that this
- * ContactGroup belongs to.
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return parentProvider;
- }
-
- /**
- * Returns an Iterator over all contacts, member of this
- * <tt>ContactGroup</tt>.
- *
- * @return a java.util.Iterator over all contacts inside this
- * <tt>ContactGroup</tt>
- */
- public Iterator<Contact> contacts()
- {
- return contacts.iterator();
- }
-
- /**
- * Adds the specified contact to this group.
- * @param contactToAdd the ContactDictImpl to add to this group.
- */
- public void addContact(ContactDictImpl contactToAdd)
- {
- this.contacts.add(contactToAdd);
- contactToAdd.setParentGroup(this);
- }
-
- /**
- * Returns the number of <tt>Contact</tt> members of this
- * <tt>ContactGroup</tt>
- *
- * @return an int indicating the number of <tt>Contact</tt>s, members of
- * this <tt>ContactGroup</tt>.
- */
- public int countContacts()
- {
- return contacts.size();
- }
-
- /**
- * Returns the number of subgroups contained by this
- * <tt>ContactGroup</tt>.
- *
- * @return the number of subGroups currently added to this group.
- */
- public int countSubgroups()
- {
- return subGroups.size();
- }
-
- /**
- * Adds the specified contact group to the contained by this group.
- * @param subgroup the ContactGroupDictImpl to add as a subgroup to this group.
- */
- public void addSubgroup(ContactGroupDictImpl subgroup)
- {
- this.subGroups.add(subgroup);
- subgroup.setParentGroup(this);
- }
-
- /**
- * Sets the group that is the new parent of this group
- * @param parent ContactGroupDictImpl
- */
- void setParentGroup(ContactGroupDictImpl parent)
- {
- this.parentGroup = parent;
- }
-
- /**
- * Returns the contact group that currently contains this group or null if
- * this is the root contact group.
- * @return the contact group that currently contains this group or null if
- * this is the root contact group.
- */
- public ContactGroup getParentContactGroup()
- {
- return this.parentGroup;
- }
-
- /**
- * Removes the specified contact group from the this group's subgroups.
- * @param subgroup the ContactGroupDictImpl subgroup to remove.
- */
- public void removeSubGroup(ContactGroupDictImpl subgroup)
- {
- this.subGroups.remove(subgroup);
- subgroup.setParentGroup(null);
- }
-
- /**
- * Returns the group that is parent of the specified dictGroup or null
- * if no parent was found.
- * @param dictGroup the group whose parent we're looking for.
- * @return the ContactGroupDictImpl instance that dictGroup
- * belongs to or null if no parent was found.
- */
- public ContactGroupDictImpl findGroupParent(ContactGroupDictImpl dictGroup)
- {
- if ( subGroups.contains(dictGroup) )
- return this;
-
- Iterator<ContactGroup> subGroupsIter = subgroups();
- while (subGroupsIter.hasNext())
- {
- ContactGroupDictImpl subgroup
- = (ContactGroupDictImpl) subGroupsIter.next();
-
- ContactGroupDictImpl parent
- = subgroup.findGroupParent(dictGroup);
-
- if(parent != null)
- return parent;
- }
- return null;
- }
-
- /**
- * Returns the group that is parent of the specified dictContact or
- * null if no parent was found.
- *
- * @param dictContact the contact whose parent we're looking for.
- * @return the ContactGroupDictImpl instance that dictContact
- * belongs to or <tt>null</tt> if no parent was found.
- */
- public ContactGroupDictImpl findContactParent(
- ContactDictImpl dictContact)
- {
- if ( contacts.contains(dictContact) )
- return this;
-
- Iterator<ContactGroup> subGroupsIter = subgroups();
- while (subGroupsIter.hasNext())
- {
- ContactGroupDictImpl subgroup
- = (ContactGroupDictImpl) subGroupsIter.next();
-
- ContactGroupDictImpl parent
- = subgroup.findContactParent(dictContact);
-
- if(parent != null)
- return parent;
- }
- return null;
- }
-
-
-
- /**
- * Returns the <tt>Contact</tt> with the specified address or identifier.
- *
- * @param id the addres or identifier of the <tt>Contact</tt> we are
- * looking for.
- * @return the <tt>Contact</tt> with the specified id or address.
- */
- public Contact getContact(String id)
- {
- Iterator<Contact> contactsIter = contacts();
- while (contactsIter.hasNext())
- {
- ContactDictImpl contact = (ContactDictImpl) contactsIter.next();
- if (contact.getAddress().equals(id))
- return contact;
-
- }
- return null;
- }
-
- /**
- * Returns the subgroup with the specified index.
- *
- * @param index the index of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(int index)
- {
- return subGroups.get(index);
- }
-
- /**
- * Returns the subgroup with the specified name.
- *
- * @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(String groupName)
- {
- Iterator<ContactGroup> groupsIter = subgroups();
- while (groupsIter.hasNext())
- {
- ContactGroupDictImpl contactGroup
- = (ContactGroupDictImpl) groupsIter.next();
- if (contactGroup.getGroupName().equals(groupName))
- return contactGroup;
-
- }
- return null;
-
- }
-
- /**
- * Returns the name of this group.
- *
- * @return a String containing the name of this group.
- */
- public String getGroupName()
- {
- return this.groupName;
- }
-
- /**
- * Sets this group a new name.
- * @param newGrpName a String containing the new name of this group.
- */
- public void setGroupName(String newGrpName)
- {
- this.groupName = newGrpName;
- }
-
- /**
- * Returns an iterator over the sub groups that this
- * <tt>ContactGroup</tt> contains.
- *
- * @return a java.util.Iterator over the <tt>ContactGroup</tt> children
- * of this group (i.e. subgroups).
- */
- public Iterator<ContactGroup> subgroups()
- {
- return subGroups.iterator();
- }
-
- /**
- * Removes the specified contact from this group.
- * @param contact the ContactDictImpl to remove from this group
- */
- public void removeContact(ContactDictImpl contact)
- {
- this.contacts.remove(contact);
- }
-
- /**
- * Returns the contact with the specified id or null if no such contact
- * exists.
- * @param id the id of the contact we're looking for.
- * @return ContactDictImpl
- */
- public ContactDictImpl findContactByID(String id)
- {
- //first go through the contacts that are direct children.
- Iterator<Contact> contactsIter = contacts();
-
- while(contactsIter.hasNext())
- {
- ContactDictImpl mContact = (ContactDictImpl)contactsIter.next();
-
- if( mContact.getAddress().equals(id) )
- return mContact;
- }
-
- //if we didn't find it here, let's try in the subougroups
- Iterator<ContactGroup> groupsIter = subgroups();
-
- while( groupsIter.hasNext() )
- {
- ContactGroupDictImpl mGroup = (ContactGroupDictImpl)groupsIter.next();
-
- ContactDictImpl mContact = mGroup.findContactByID(id);
-
- if (mContact != null)
- return mContact;
- }
-
- return null;
- }
-
-
- /**
- * Returns a String representation of this group and the contacts it
- * contains (may turn out to be a relatively long string).
- * @return a String representing this group and its child contacts.
- */
- @Override
- public String toString()
- {
-
- StringBuffer buff = new StringBuffer(getGroupName());
- buff.append(".subGroups=" + countSubgroups() + ":\n");
-
- Iterator<ContactGroup> subGroups = subgroups();
- while (subGroups.hasNext())
- {
- ContactGroupDictImpl group = (ContactGroupDictImpl)subGroups.next();
- buff.append(group.toString());
- if (subGroups.hasNext())
- buff.append("\n");
- }
-
- buff.append("\nChildContacts="+countContacts()+":[");
-
- Iterator<Contact> contacts = contacts();
- while (contacts.hasNext())
- {
- ContactDictImpl contact = (ContactDictImpl) contacts.next();
- buff.append(contact.toString());
- if(contacts.hasNext())
- buff.append(", ");
- }
- return buff.append("]").toString();
- }
-
- /**
- * Specifies whether or not this contact group is being stored by the server.
- * Non persistent contact groups are common in the case of simple,
- * non-persistent presence operation sets. They could however also be seen
- * in persistent presence operation sets when for example we have received
- * an event from someone not on our contact list and the contact that we
- * associated with that user is placed in a non persistent group. Non
- * persistent contact groups are volatile even when coming from a persistent
- * presence op. set. They would only exist until the application is closed
- * and will not be there next time it is loaded.
- *
- * @param isPersistent true if the contact group is to be persistent and
- * false otherwise.
- */
- public void setPersistent(boolean isPersistent)
- {
- this.isPersistent = isPersistent;
- }
-
- /**
- * Determines whether or not this contact group is being stored by the
- * server. Non persistent contact groups exist for the sole purpose of
- * containing non persistent contacts.
- * @return true if the contact group is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Returns null as no persistent data is required and the contact address is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Makes the group resolved or unresolved.
- *
- * @param resolved true to make the group resolved; false to
- * make it unresolved
- */
- public void setResolved(boolean resolved)
- {
- this.isResolved = resolved;
- }
-
- /**
- * Returns a <tt>String</tt> that uniquely represnets the group inside
- * the current protocol. The string MUST be persistent (it must not change
- * across connections or runs of the application). In many cases (Jabber,
- * ICQ) the string may match the name of the group as these protocols
- * only allow a single level of contact groups and there is no danger of
- * having the same name twice in the same contact list. Other protocols
- * (no examples come to mind but that doesn't bother me ;) ) may be
- * supporting mutilple levels of grooups so it might be possible for group
- * A and group B to both contain groups named C. In such cases the
- * implementation must find a way to return a unique identifier in this
- * method and this UID should never change for a given group.
- *
- * @return a String representing this group in a unique and persistent
- * way.
- */
- public String getUID()
- {
- return uid;
- }
-
- /**
- * Ugly but tricky conversion method.
- * @param uid the uid we'd like to get a name from
- * @return the name of the group with the specified <tt>uid</tt>.
- */
- static String createNameFromUID(String uid)
- {
- return uid.substring(0, uid.length() - (UID_SUFFIX.length()));
- }
-
- /**
- * Indicates whether some other object is "equal to" this one which in terms
- * of contact groups translates to having the equal names and matching
- * subgroups and child contacts. The resolved status of contactgroups and
- * contacts is deliberately ignored so that groups and/or contacts would
- * be assumed equal even if it differs.
- * <p>
- * @param obj the reference object with which to compare.
- * @return <code>true</code> if this contact group has the equal child
- * contacts and subgroups to those of the <code>obj</code> argument.
- */
- @Override
- public boolean equals(Object obj)
- {
- if(obj == null
- || !(obj instanceof ContactGroupDictImpl))
- return false;
-
- ContactGroupDictImpl dictGroup
- = (ContactGroupDictImpl)obj;
-
- if( ! dictGroup.getGroupName().equals(getGroupName())
- || ! dictGroup.getUID().equals(getUID())
- || dictGroup.countContacts() != countContacts()
- || dictGroup.countSubgroups() != countSubgroups())
- return false;
-
- //traverse child contacts
- Iterator<Contact> theirContacts = dictGroup.contacts();
-
- while(theirContacts.hasNext())
- {
- ContactDictImpl theirContact
- = (ContactDictImpl)theirContacts.next();
-
- ContactDictImpl ourContact
- = (ContactDictImpl)getContact(theirContact.getAddress());
-
- if(ourContact == null
- || !ourContact.equals(theirContact))
- return false;
- }
-
- //traverse subgroups
- Iterator<ContactGroup> theirSubgroups = dictGroup.subgroups();
-
- while(theirSubgroups.hasNext())
- {
- ContactGroupDictImpl theirSubgroup
- = (ContactGroupDictImpl)theirSubgroups.next();
-
- ContactGroupDictImpl ourSubgroup
- = (ContactGroupDictImpl)getGroup(
- theirSubgroup.getGroupName());
-
- if(ourSubgroup == null
- || !ourSubgroup.equals(theirSubgroup))
- return false;
- }
-
- return true;
- }
-}
-
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictAccountID.java b/src/net/java/sip/communicator/impl/protocol/dict/DictAccountID.java
deleted file mode 100644
index 538ae71..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/DictAccountID.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The Dict implementation of a sip-communicator account id.
- * @author LITZELMANN Cedric
- * @author ROTH Damien
- */
-public class DictAccountID
- extends AccountID
-{
- /**
- * Creates an account id from the specified id and account properties.
- *
- * @param userID the user identifier correspnding to the account
- * @param accountProperties any other properties necessary for the account.
- */
- DictAccountID(String userID, Map<String, String> accountProperties)
- {
- super(userID, accountProperties, ProtocolNames.DICT, "dict.org");
- }
-
- /**
- * Returns the dict server adress
- * @return the dict server adress
- */
- public String getHost()
- {
- return getAccountPropertyString(ProtocolProviderFactory.SERVER_ADDRESS);
- }
-
- /**
- * Returns the dict server port
- * @return the dict server port
- */
- public int getPort()
- {
- return Integer
- .parseInt(getAccountPropertyString(ProtocolProviderFactory.SERVER_PORT));
- }
-
- /**
- * Returns the selected strategy
- * @return the selected strategy
- */
- public String getStrategy()
- {
- return getAccountPropertyString(ProtocolProviderFactory.STRATEGY);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictActivator.java b/src/net/java/sip/communicator/impl/protocol/dict/DictActivator.java
deleted file mode 100644
index b5976c7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/DictActivator.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.resources.*;
-import org.osgi.framework.*;
-
-/**
- * Loads the Dict provider factory and registers its services in the OSGI
- * bundle context.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class DictActivator
- implements BundleActivator
-{
- private static final Logger logger = Logger.getLogger(DictActivator.class);
-
- /**
- * The currently valid bundle context.
- */
- private static BundleContext bundleContext = null;
-
- private ServiceRegistration dictPpFactoryServReg = null;
- private static ProtocolProviderFactoryDictImpl
- dictProviderFactory = null;
-
- private static ResourceManagementService resourceService;
-
- /**
- * Called when this bundle is started. In here we'll export the
- * dict ProtocolProviderFactory implementation so that it could be
- * possible to register accounts with it in SIP Communicator.
- *
- * @param context The execution context of the bundle being started.
- * @throws Exception If this method throws an exception, this bundle is
- * marked as stopped and the Framework will remove this bundle's
- * listeners, unregister all services registered by this bundle, and
- * release all services used by this bundle.
- */
- public void start(BundleContext context)
- throws Exception
- {
- bundleContext = context;
-
- Hashtable<String,String> hashtable = new Hashtable<String,String>();
- hashtable.put(ProtocolProviderFactory.PROTOCOL, ProtocolNames.DICT);
-
- dictProviderFactory = new ProtocolProviderFactoryDictImpl();
-
- //reg the dict provider factory.
- dictPpFactoryServReg = context.registerService(
- ProtocolProviderFactory.class.getName(),
- dictProviderFactory,
- hashtable);
-
- if (logger.isInfoEnabled())
- logger.info("DICT protocol implementation [STARTED].");
- }
-
- /**
- * Returns a reference to the bundle context that we were started with.
- * @return a reference to the BundleContext instance that we were started
- * witn.
- */
- public static BundleContext getBundleContext()
- {
- return bundleContext;
- }
-
- /**
- * Called when this bundle is stopped so the Framework can perform the
- * bundle-specific activities necessary to stop the bundle.
- *
- * @param context The execution context of the bundle being stopped.
- * @throws Exception If this method throws an exception, the bundle is
- * still marked as stopped, and the Framework will remove the bundle's
- * listeners, unregister all services registered by the bundle, and
- * release all services used by the bundle.
- */
- public void stop(BundleContext context)
- throws Exception
- {
-
- dictProviderFactory.stop();
- dictPpFactoryServReg.unregister();
-
- if (logger.isInfoEnabled())
- logger.info("DICT protocol implementation [STOPPED].");
- }
-
- /**
- * Returns a reference to the protocol provider factory that we have
- * registered.
- * @return a reference to the <tt>ProtocolProviderFactoryDictImpl</tt>
- * instance that we have registered from this package.
- */
- public static ProtocolProviderFactoryDictImpl getProtocolProviderFactory()
- {
- return dictProviderFactory;
- }
-
-
- /**
- * Returns the <tt>ResourceManagementService</tt>.
- *
- * @return the <tt>ResourceManagementService</tt>.
- */
- public static ResourceManagementService getResources()
- {
- if (resourceService == null)
- {
- ServiceReference serviceReference = bundleContext
- .getServiceReference(ResourceManagementService.class.getName());
-
- if(serviceReference == null)
- return null;
-
- resourceService = (ResourceManagementService) bundleContext
- .getService(serviceReference);
- }
-
- return resourceService;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictStatusEnum.java b/src/net/java/sip/communicator/impl/protocol/dict/DictStatusEnum.java
deleted file mode 100644
index 87086f7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/DictStatusEnum.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * An implementation of <tt>PresenceStatus</tt> that enumerates all states that
- * a Dict contact can fall into.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class DictStatusEnum
- extends PresenceStatus
-{
-
- /**
- * Indicates an Offline status or status with 0 connectivity.
- */
- public static final DictStatusEnum OFFLINE
- = new DictStatusEnum(
- 0, "Offline",
- DictActivator.getResources()
- .getImageInBytes("service.protocol.dict.OFFLINE_STATUS_ICON"));
-
- /**
- * The Online status. Indicate that the user is able and willing to
- * communicate.
- */
- public static final DictStatusEnum ONLINE
- = new DictStatusEnum(
- 65, "Online",
- DictActivator.getResources()
- .getImageInBytes("service.protocol.dict.DICT_16x16"));
-
- /**
- * Initialize the list of supported status states.
- */
- private static List<PresenceStatus> supportedStatusSet = new LinkedList<PresenceStatus>();
- static
- {
- supportedStatusSet.add(OFFLINE);
- supportedStatusSet.add(ONLINE);
- }
-
- /**
- * Creates an instance of <tt>RssPresneceStatus</tt> with the
- * specified parameters.
- * @param status the connectivity level of the new presence status instance
- * @param statusName the name of the presence status.
- * @param statusIcon the icon associated with this status
- */
- private DictStatusEnum(int status,
- String statusName,
- byte[] statusIcon)
- {
- super(status, statusName, statusIcon);
- }
-
- /**
- * Returns an iterator over all status instances supproted by the rss
- * provider.
- * @return an <tt>Iterator</tt> over all status instances supported by the
- * rss provider.
- */
- static Iterator<PresenceStatus> supportedStatusSet()
- {
- return supportedStatusSet.iterator();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/MessageDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/MessageDictImpl.java
deleted file mode 100644
index 5b95dd4..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/MessageDictImpl.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Very simple message implementation for the Dict protocol.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- * @author Lubomir Marinov
- */
-public class MessageDictImpl
- extends AbstractMessage
-{
-
- /**
- * Creates a message instance according to the specified parameters.
- *
- * @param content the message body
- * @param contentType message content type or null for text/plain
- * @param contentEncoding message encoding or null for UTF8
- * @param subject the subject of the message or null for no subject.
- */
- public MessageDictImpl(String content, String contentType,
- String contentEncoding, String subject)
- {
- super(content, contentType, contentEncoding, subject);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/OperationSetBasicInstantMessagingDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/OperationSetBasicInstantMessagingDictImpl.java
deleted file mode 100644
index f1f4973..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/OperationSetBasicInstantMessagingDictImpl.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import java.util.*;
-
-import net.java.dict4j.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Instant messaging functionalities for the Dict protocol.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class OperationSetBasicInstantMessagingDictImpl
- extends AbstractOperationSetBasicInstantMessaging
- implements RegistrationStateChangeListener
-{
- /**
- * The currently valid persistent presence operation set.
- */
- private OperationSetPersistentPresenceDictImpl opSetPersPresence = null;
-
- /**
- * The protocol provider that created us.
- */
- private ProtocolProviderServiceDictImpl parentProvider = null;
-
- private DictAccountID accountID;
-
- /**
- * Creates an instance of this operation set keeping a reference to the
- * parent protocol provider and presence operation set.
- *
- * @param provider The provider instance that creates us.
- * @param opSetPersPresence the currently valid
- * <tt>OperationSetPersistentPresenceDictImpl</tt> instance.
- */
- public OperationSetBasicInstantMessagingDictImpl(
- ProtocolProviderServiceDictImpl provider,
- OperationSetPersistentPresenceDictImpl opSetPersPresence)
- {
- this.opSetPersPresence = opSetPersPresence;
- this.parentProvider = provider;
- this.accountID = (DictAccountID) provider.getAccountID();
-
- parentProvider.addRegistrationStateChangeListener(this);
- }
-
- @Override
- public Message createMessage(String content)
- {
- return new MessageDictImpl(content, HTML_MIME_TYPE,
- DEFAULT_MIME_ENCODING, null);
- }
-
- @Override
- public Message createMessage(String content, String contentType,
- String encoding, String subject)
- {
- return new MessageDictImpl(content, contentType, encoding, subject);
- }
-
- /**
- * Sends the <tt>message</tt> to the destination indicated by the
- * <tt>to</tt> contact.
- *
- * @param to the <tt>Contact</tt> to send <tt>message</tt> to
- * @param message the <tt>Message</tt> to send.
- * @throws IllegalStateException if the underlying ICQ stack is not
- * registered and initialized.
- * @throws IllegalArgumentException if <tt>to</tt> is not an instance
- * belonging to the underlying implementation.
- */
- public void sendInstantMessage(Contact to, Message message)
- throws IllegalStateException,
- IllegalArgumentException
- {
- if( !(to instanceof ContactDictImpl) )
- {
- throw new IllegalArgumentException(
- "The specified contact is not a Dict contact."
- + to);
- }
-
- // Remove all html tags from the message
- message = createMessage(Html2Text.extractText(message.getContent()));
-
- // Display the queried word
- fireMessageDelivered(message, to);
-
- this.submitDictQuery((ContactDictImpl) to, message);
- }
-
- /**
- * Determines whether the protocol provider (or the protocol itself) supports
- * sending and receiving offline messages. Most often this method would
- * return true for protocols that support offline messages and false for
- * those that don't. It is however possible for a protocol to support these
- * messages and yet have a particular account that does not (i.e. feature
- * not enabled on the protocol server). In cases like this it is possible
- * for this method to return true even when offline messaging is not
- * supported, and then have the sendMessage method throw an
- * OperationFailedException with code - OFFLINE_MESSAGES_NOT_SUPPORTED.
- *
- * @return <tt>true</tt> if the protocol supports offline messages and
- * <tt>false</tt> otherwise.
- */
- public boolean isOfflineMessagingSupported()
- {
- return false;
- }
-
- /**
- * Determines whether the protocol supports the supplied content type.
- *
- * @param contentType the type we want to check
- * @return <tt>true</tt> if the protocol supports it and
- * <tt>false</tt> otherwise.
- */
- public boolean isContentTypeSupported(String contentType)
- {
- if(contentType.equals(DEFAULT_MIME_TYPE))
- return true;
- else if(contentType.equals(HTML_MIME_TYPE))
- return true;
- else
- return false;
- }
-
- /**
- * Returns the protocol provider that this operation set belongs to.
- *
- * @return a reference to the <tt>ProtocolProviderServiceDictImpl</tt>
- * instance that this operation set belongs to.
- */
- public ProtocolProviderServiceDictImpl getParentProvider()
- {
- return this.parentProvider;
- }
-
- /**
- * Returns a reference to the presence operation set instance used by our
- * source provider.
- *
- * @return a reference to the <tt>OperationSetPersistentPresenceDictImpl</tt>
- * instance used by this provider.
- */
- public OperationSetPersistentPresenceDictImpl getOpSetPersPresence()
- {
- return this.opSetPersPresence;
- }
-
- /**
- * The method is called by the ProtocolProvider whenever a change in the
- * registration state of the corresponding provider has occurred.
- *
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
-
- }
-
-
- /**
- * Create, execute and display a query to a dictionary (ContactDictImpl)
- *
- * @param dictContact the contact containing the database name
- * @param message the message containing the word
- */
- private void submitDictQuery(ContactDictImpl dictContact, Message message)
- {
- Message msg = this.createMessage("");
-
- String database = dictContact.getContactID();
- DictConnection conn = this.parentProvider.getConnection();
- boolean doMatch = false;
-
- String word;
-
- // Formatting the query message, if the word as one or more spaces we
- // put it between quotes to prevent errors
- word = message.getContent().replace("\"", "").trim();
- if (word.indexOf(' ') > 0)
- {
- word = "\"" + word + "\"";
- }
-
- // Try to get the definition of the work
- try
- {
- List<Definition> definitions = conn.define(database, word);
- msg = this.createMessage(retrieveDefine(definitions, word));
- }
- catch(DictException dx)
- {
- if (dx.getErrorCode() == DictReturnCode.NO_MATCH)
- { // No word found, we are going to try the match command
- doMatch = true;
- }
- else
- { // Otherwise we display the error returned by the server
- msg = this.createMessage(manageException(dx, database));
- }
- }
-
- if (doMatch)
- {
- // Trying the match command
- try
- {
- List<MatchWord> matchWords = conn.match(database, word,
- this.accountID.getStrategy());
- msg = this.createMessage(retrieveMatch(matchWords, word));
- }
- catch(DictException dx)
- {
- msg = this.createMessage(manageException(dx, database));
- }
- }
-
- // Send message
- fireMessageReceived(msg, dictContact);
- }
-
- /**
- * Generate the display of the results of the Define command
- *
- * @param data the result of the Define command
- * @param word the queried word
- * @return the formatted result
- */
- private String retrieveDefine(List<Definition> data, String word)
- {
- StringBuffer res = new StringBuffer();
- Definition def;
-
- for (int i=0; i<data.size(); i++)
- {
- def = data.get(i);
-
- if(i != 0 && data.size() > 0)
- {
- res.append("<hr>");
- }
- res.append(def.getDefinition().replaceAll("\n", "<br>"))
- .append("<div align=\"right\"><font size=\"-2\">-- From ")
- .append(def.getDictionary())
- .append("</font></div>");
- }
-
- String result = res.toString();
- result = formatResult(result, "\\\\", "<em>", "</em>");
- result = formatResult(result, "[\\[\\]]", "<cite>", "</cite>");
- result = formatResult(result, "[\\{\\}]", "<strong>", "</strong>");
- result = formatWordDefined(result, word);
-
- return result;
- }
-
- /**
- * Makes a stronger emphasis for the word defined.
- * @param result The text containing the definition of the word.
- * @param word The word defined to display with bold font. For this we
- * had the strong HTML tag.
- * @return Returns the result text with an strong emphasis of all
- * the occurences of the word defined.
- */
- private String formatWordDefined(String result, String word)
- {
- String tmpWord;
-
- tmpWord = word.toUpperCase();
- result = result.replaceAll("\\b" + tmpWord + "\\b", "<strong>" + tmpWord + "</strong>");
- tmpWord = word.toLowerCase();
- result = result.replaceAll("\\b" + tmpWord + "\\b", "<strong>" + tmpWord + "</strong>");
- if(tmpWord.length() > 1)
- {
- tmpWord = tmpWord.substring(0, 1).toUpperCase() + tmpWord.substring(1);
- result = result.replaceAll("\\b" + tmpWord + "\\b", "<strong>" + tmpWord + "</strong>");
- }
-
- return result;
- }
-
- /**
- * Remplaces special characters into HTML tags to make some emphasis.
- * @param result The text containing the definition of the word.
- * @param regex The special character to replace with HTML tags.
- * @param startTag The start HTML tag to use.
- * @param endTag The end HTML tag to use.
- * @return The result with all special characters replaced by HTML
- * tags.
- */
- private String formatResult(String result, String regex, String startTag, String endTag)
- {
- String[] tmp = result.split(regex);
- String res = "";
-
- for(int i = 0; i < (tmp.length - 1); i += 2)
- {
- res += tmp[i] + startTag + tmp[i+1] + endTag;
- }
- if((tmp.length % 2) != 0)
- {
- res += tmp[tmp.length - 1];
- }
- return res;
- }
-
- /**
- * Generate the display of the results of the Match command
- *
- * @param data the result of the Match command
- * @param word the queried word
- * @return the formatted result
- */
- private String retrieveMatch(List<MatchWord> data, String word)
- {
- StringBuffer result = new StringBuffer();
- boolean isStart = true;
-
- result.append(DictActivator.getResources()
- .getI18NString("plugin.dictaccregwizz.MATCH_RESULT", new String[] {word}));
-
- for (int i=0; i<data.size(); i++)
- {
- if (isStart)
- isStart = false;
- else
- result.append(", ");
-
- result.append(data.get(i).getWord());
- }
-
- return result.toString();
- }
-
- /**
- * Manages the return exception of a dict query.
- *
- * @param dix The exception returned by the adapter
- * @param database The dictionary used
- * @return Exception message
- */
- private String manageException(DictException dix, String database)
- {
- int errorCode = dix.getErrorCode();
-
- // We change the text only for exception 550 (invalid dictionary) and 551 (invalid strategy)
- if (errorCode == DictReturnCode.INVALID_DATABASE)
- {
- return DictActivator.getResources()
- .getI18NString("plugin.dictaccregwizz.INVALID_DATABASE", new String[] {database});
- }
- else if (errorCode == DictReturnCode.INVALID_STRATEGY)
- {
- return DictActivator.getResources()
- .getI18NString("plugin.dictaccregwizz.INVALID_STRATEGY");
- }
- else if (errorCode == DictReturnCode.NO_MATCH)
- {
- return DictActivator.getResources()
- .getI18NString("plugin.dictaccregwizz.NO_MATCH");
- }
-
- return dix.getMessage();
- }
-
- /**
- * Sends the <tt>message</tt> to the destination indicated by the
- * <tt>to</tt>. Resources are not supported by this operation set
- * implementation.
- *
- * @param to the <tt>Contact</tt> to send <tt>message</tt> to
- * @param toResource the resource to which the message should be send
- * @param message the <tt>Message</tt> to send.
- * @throws java.lang.IllegalStateException if the underlying ICQ stack is
- * not registered and initialized.
- * @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an
- * instance belonging to the underlying implementation.
- */
- @Override
- public void sendInstantMessage( Contact to,
- ContactResource toResource,
- Message message)
- throws IllegalStateException,
- IllegalArgumentException
- {
- sendInstantMessage(to, message);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/OperationSetPersistentPresenceDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/OperationSetPersistentPresenceDictImpl.java
deleted file mode 100644
index 8184fe9..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/OperationSetPersistentPresenceDictImpl.java
+++ /dev/null
@@ -1,988 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-import org.osgi.framework.*;
-
-/**
- * A Dict implementation of a persistent presence operation set. In order
- * to simulate server persistence, this operation set would simply accept all
- * unresolved contacts and resolve them immediately. A real world protocol
- * implementation would save it on a server using methods provided by the
- * protocol stack.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class OperationSetPersistentPresenceDictImpl
- extends AbstractOperationSetPersistentPresence<ProtocolProviderServiceDictImpl>
-{
- private static final Logger logger =
- Logger.getLogger(OperationSetPersistentPresenceDictImpl.class);
-
- /**
- * The root of the dict contact list.
- */
- private ContactGroupDictImpl contactListRoot = null;
-
- /**
- * The currently active status message.
- */
- private String statusMessage = "Default Status Message";
-
- /**
- * Our presence status.
- */
- private PresenceStatus presenceStatus = DictStatusEnum.ONLINE;
-
- /**
- * The <tt>AuthorizationHandler</tt> instance that we'd have to transmit
- * authorization requests to for approval.
- */
- private AuthorizationHandler authorizationHandler = null;
-
- /**
- * Creates an instance of this operation set keeping a reference to the
- * specified parent <tt>provider</tt>.
- * @param provider the ProtocolProviderServiceDictImpl instance that
- * created us.
- */
- public OperationSetPersistentPresenceDictImpl(
- ProtocolProviderServiceDictImpl provider)
- {
- super(provider);
-
- contactListRoot = new ContactGroupDictImpl("RootGroup", provider);
-
- //add our unregistration listener
- parentProvider.addRegistrationStateChangeListener(
- new UnregistrationListener());
- }
-
- /**
- * Creates a group with the specified name and parent in the server
- * stored contact list.
- *
- * @param parent the group where the new group should be created
- * @param groupName the name of the new group to create.
- */
- public void createServerStoredContactGroup(ContactGroup parent,
- String groupName)
- {
- ContactGroupDictImpl newGroup
- = new ContactGroupDictImpl(groupName, parentProvider);
-
- ((ContactGroupDictImpl)parent).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
- /**
- * A Dict Provider method to use for fast filling of a contact list.
- *
- * @param contactGroup the group to add
- */
- public void addDictGroup(ContactGroupDictImpl contactGroup)
- {
- contactListRoot.addSubgroup(contactGroup);
- }
-
- /**
- * A Dict Provider method to use for fast filling of a contact list.
- * This method would add both the group and fire an event.
- *
- * @param parent the group where <tt>contactGroup</tt> should be added.
- * @param contactGroup the group to add
- */
- public void addDictGroupAndFireEvent(
- ContactGroupDictImpl parent
- , ContactGroupDictImpl contactGroup)
- {
- parent.addSubgroup(contactGroup);
-
- this.fireServerStoredGroupEvent(
- contactGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
-
- /**
- * Returns a reference to the contact with the specified ID in case we
- * have a subscription for it and null otherwise/
- *
- * @param contactID a String identifier of the contact which we're
- * seeking a reference of.
- * @return a reference to the Contact with the specified
- * <tt>contactID</tt> or null if we don't have a subscription for the
- * that identifier.
- */
- public Contact findContactByID(String contactID)
- {
- return contactListRoot.findContactByID(contactID);
- }
-
- /**
- * Sets the specified status message.
- * @param statusMessage a String containing the new status message.
- */
- public void setStatusMessage(String statusMessage)
- {
- this.statusMessage = statusMessage;
- }
-
- /**
- * Returns the status message that was last set through
- * setCurrentStatusMessage.
- *
- * @return the last status message that we have requested and the aim
- * server has confirmed.
- */
- public String getCurrentStatusMessage()
- {
- return statusMessage;
- }
-
- /**
- * Returns the protocol specific contact instance representing the local
- * user.
- *
- * @return the Contact (address, phone number, or uin) that the Provider
- * implementation is communicating on behalf of.
- */
- public Contact getLocalContact()
- {
- return null;
- }
-
- /**
- * Returns a PresenceStatus instance representing the state this provider
- * is currently in.
- *
- * @return the PresenceStatus last published by this provider.
- */
- public PresenceStatus getPresenceStatus()
- {
- return presenceStatus;
- }
-
- /**
- * Returns the root group of the server stored contact list.
- *
- * @return the root ContactGroup for the ContactList stored by this
- * service.
- */
- public ContactGroup getServerStoredContactListRoot()
- {
- return contactListRoot;
- }
-
- /**
- * Returns the set of PresenceStatus objects that a user of this service
- * may request the provider to enter.
- *
- * @return Iterator a PresenceStatus array containing "enterable" status
- * instances.
- */
- public Iterator<PresenceStatus> getSupportedStatusSet()
- {
- return DictStatusEnum.supportedStatusSet();
- }
-
- /**
- * Removes the specified contact from its current parent and places it
- * under <tt>newParent</tt>.
- *
- * @param contactToMove the <tt>Contact</tt> to move
- * @param newParent the <tt>ContactGroup</tt> where <tt>Contact</tt>
- * would be placed.
- */
- public void moveContactToGroup(Contact contactToMove,
- ContactGroup newParent)
- {
- ContactDictImpl dictContact
- = (ContactDictImpl)contactToMove;
-
- ContactGroupDictImpl parentDictGroup
- = findContactParent(dictContact);
-
- parentDictGroup.removeContact(dictContact);
-
- //if this is a volatile contact then we haven't really subscribed to
- //them so we'd need to do so here
- if(!dictContact.isPersistent())
- {
- //first tell everyone that the volatile contact was removed
- fireSubscriptionEvent(dictContact
- , parentDictGroup
- , SubscriptionEvent.SUBSCRIPTION_REMOVED);
-
- try
- {
- //now subscribe
- this.subscribe(newParent, contactToMove.getAddress());
-
- //now tell everyone that we've added the contact
- fireSubscriptionEvent(dictContact
- , newParent
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
- }
- catch (Exception ex)
- {
- logger.error("Failed to move contact "
- + dictContact.getAddress()
- , ex);
- }
- }
- else
- {
- ( (ContactGroupDictImpl) newParent)
- .addContact(dictContact);
-
- fireSubscriptionMovedEvent(contactToMove
- , parentDictGroup
- , newParent);
- }
- }
-
- /**
- * Requests the provider to enter into a status corresponding to the
- * specified paramters.
- *
- * @param status the PresenceStatus as returned by
- * getRequestableStatusSet
- * @param statusMessage the message that should be set as the reason to
- * enter that status
- * @throws IllegalArgumentException if the status requested is not a
- * valid PresenceStatus supported by this provider.
- * @throws IllegalStateException if the provider is not currently
- * registered.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * publishing the status fails due to a network error.
- */
- public void publishPresenceStatus(PresenceStatus status,
- String statusMessage) throws
- IllegalArgumentException, IllegalStateException,
- OperationFailedException
- {
- PresenceStatus oldPresenceStatus = this.presenceStatus;
- this.presenceStatus = status;
- this.statusMessage = statusMessage;
-
- this.fireProviderStatusChangeEvent(oldPresenceStatus);
-
- //since we are not a real protocol, we set the contact presence status
- //ourselves and make them have the same status as ours.
- changePresenceStatusForAllContacts( getServerStoredContactListRoot()
- , getPresenceStatus());
-
- //now check whether we are in someone else's contact list and modify
- //our status there
- List<Contact> contacts = findContactsPointingToUs();
-
- Iterator<Contact> contactsIter = contacts.iterator();
- while (contactsIter.hasNext())
- {
- ContactDictImpl contact
- = (ContactDictImpl) contactsIter.next();
-
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(status);
- contact.getParentPresenceOperationSet()
- .fireContactPresenceStatusChangeEvent(
- contact
- , contact.getParentContactGroup()
- , oldStatus);
-
- }
- }
-
-
-
- /**
- * Get the PresenceStatus for a particular contact.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * we're interested in.
- * @return PresenceStatus the <tt>PresenceStatus</tt> of the specified
- * <tt>contact</tt>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * retrieving the status fails due to errors experienced during
- * network communication
- */
- public PresenceStatus queryContactStatus(String contactIdentifier) throws
- IllegalArgumentException, IllegalStateException,
- OperationFailedException
- {
- return findContactByID(contactIdentifier).getPresenceStatus();
- }
-
- /**
- * Sets the presence status of <tt>contact</tt> to <tt>newStatus</tt>.
- *
- * @param contact the <tt>ContactDictImpl</tt> whose status we'd like
- * to set.
- * @param newStatus the new status we'd like to set to <tt>contact</tt>.
- */
- private void changePresenceStatusForContact(
- ContactDictImpl contact
- , PresenceStatus newStatus)
- {
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(newStatus);
-
- fireContactPresenceStatusChangeEvent(
- contact, findContactParent(contact), oldStatus);
- }
-
- /**
- * Sets the presence status of all <tt>contact</tt>s in our contact list
- * (except those that correspond to another provider registered with SC)
- * to <tt>newStatus</tt>.
- *
- * @param newStatus the new status we'd like to set to <tt>contact</tt>.
- * @param parent the group in which we'd have to update the status of all
- * direct and indirect child contacts.
- */
- private void changePresenceStatusForAllContacts(ContactGroup parent,
- PresenceStatus newStatus)
- {
- //first set the status for contacts in this group
- Iterator<Contact> childContacts = parent.contacts();
-
- while(childContacts.hasNext())
- {
- ContactDictImpl contact
- = (ContactDictImpl)childContacts.next();
-
- if(findProviderForDictUserID(contact.getAddress()) != null)
- {
- //this is a contact corresponding to another SIP Communicator
- //provider so we won't change it's status here.
- continue;
- }
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(newStatus);
-
- fireContactPresenceStatusChangeEvent(
- contact, parent, oldStatus);
- }
-
- //now call this method recursively for all subgroups
- Iterator<ContactGroup> subgroups = parent.subgroups();
-
- while(subgroups.hasNext())
- {
- ContactGroup subgroup = subgroups.next();
- changePresenceStatusForAllContacts(subgroup, newStatus);
- }
- }
-
- /**
- * Returns the group that is parent of the specified dictGroup or null
- * if no parent was found.
- * @param dictGroup the group whose parent we're looking for.
- * @return the ContactGroupDictImpl instance that dictGroup
- * belongs to or null if no parent was found.
- */
- public ContactGroupDictImpl findGroupParent(
- ContactGroupDictImpl dictGroup)
- {
- return contactListRoot.findGroupParent(dictGroup);
- }
-
- /**
- * Returns the group that is parent of the specified dictContact or
- * null if no parent was found.
- * @param dictContact the contact whose parent we're looking for.
- * @return the ContactGroupDictImpl instance that dictContact
- * belongs to or null if no parent was found.
- */
- public ContactGroupDictImpl findContactParent(
- ContactDictImpl dictContact)
- {
- return (ContactGroupDictImpl)dictContact
- .getParentContactGroup();
- }
-
-
- /**
- * Removes the specified group from the server stored contact list.
- *
- * @param group the group to remove.
- *
- * @throws IllegalArgumentException if <tt>group</tt> was not found in this
- * protocol's contact list.
- */
- public void removeServerStoredContactGroup(ContactGroup group)
- throws IllegalArgumentException
- {
- ContactGroupDictImpl dictGroup
- = (ContactGroupDictImpl)group;
-
- ContactGroupDictImpl parent = findGroupParent(dictGroup);
-
- if(parent == null){
- throw new IllegalArgumentException(
- "group " + group
- + " does not seem to belong to this protocol's contact list.");
- }
-
- parent.removeSubGroup(dictGroup);
-
- this.fireServerStoredGroupEvent(
- dictGroup, ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
- }
-
- /**
- * Renames the specified group from the server stored contact list.
- *
- * @param group the group to rename.
- * @param newName the new name of the group.
- */
- public void renameServerStoredContactGroup(ContactGroup group,
- String newName)
- {
- ((ContactGroupDictImpl)group).setGroupName(newName);
-
- this.fireServerStoredGroupEvent(
- group, ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
- }
-
- /**
- * Handler for incoming authorization requests.
- *
- * @param handler an instance of an AuthorizationHandler for
- * authorization requests coming from other users requesting
- * permission add us to their contact list.
- */
- public void setAuthorizationHandler(AuthorizationHandler handler)
- {
- this.authorizationHandler = handler;
- }
-
- /**
- * Persistently adds a subscription for the presence status of the
- * contact corresponding to the specified contactIdentifier and indicates
- * that it should be added to the specified group of the server stored
- * contact list.
- *
- * @param parent the parent group of the server stored contact list
- * where the contact should be added. <p>
- * @param contactIdentifier the contact whose status updates we are
- * subscribing for.
- * @throws IllegalArgumentException if <tt>contact</tt> or
- * <tt>parent</tt> are not a contact known to the underlying protocol
- * provider.
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(ContactGroup parent, String contactIdentifier) throws
- IllegalArgumentException, IllegalStateException,
- OperationFailedException
- {
- ContactDictImpl contact = new ContactDictImpl(
- contactIdentifier
- , parentProvider);
-
- ((ContactGroupDictImpl)parent).addContact(contact);
-
- fireSubscriptionEvent(contact,
- parent,
- SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- //notify presence listeners for the status change.
- fireContactPresenceStatusChangeEvent(contact
- , parent
- , DictStatusEnum.ONLINE);
- }
-
-
- /**
- * Depending on whether <tt>contact</tt> corresponds to another protocol
- * provider installed in sip-communicator, this method would either deliver
- * it to that provider or simulate a corresponding request from the
- * destination contact and make return a response after it has received
- * one If the destination contact matches us, then we'll ask the user to
- * act upon the request, and return the response.
- *
- * @param request the authorization request that we'd like to deliver to the
- * destination <tt>contact</tt>.
- * @param contact the <tt>Contact</tt> to notify
- *
- * @return the <tt>AuthorizationResponse</tt> that has been given or
- * generated in response to <tt>request</tt>.
- */
- private AuthorizationResponse deliverAuthorizationRequest(
- AuthorizationRequest request,
- Contact contact)
- {
- String userID = contact.getAddress();
-
- //if the user id is our own id, then this request is being routed to us
- //from another instance of the dict provider.
- if (userID.equals(this.parentProvider.getAccountID().getUserID()))
- {
- //check who is the provider sending the message
- String sourceUserID = contact.getProtocolProvider()
- .getAccountID().getUserID();
-
- //check whether they are in our contact list
- Contact from = findContactByID(sourceUserID);
-
- //and if not - add them there as volatile.
- if (from == null)
- {
- from = createVolatileContact(sourceUserID);
- }
-
- //and now handle the request.
- return authorizationHandler.processAuthorisationRequest(
- request, from);
- }
- else
- {
- //if userID is not our own, try a check whether another provider
- //has that id and if yes - deliver the request to them.
- ProtocolProviderServiceDictImpl dictProvider
- = this.findProviderForDictUserID(userID);
- if (dictProvider != null)
- {
- OperationSetPersistentPresenceDictImpl opSetPersPresence
- = (OperationSetPersistentPresenceDictImpl)
- dictProvider.getOperationSet(
- OperationSetPersistentPresence.class);
- return opSetPersPresence
- .deliverAuthorizationRequest(request, contact);
- }
- else
- {
- //if we got here then "to" is simply someone in our contact
- //list so let's just simulate a reciproce request and generate
- //a response accordingly.
-
- //pretend that the remote contact is asking for authorization
- authorizationHandler.processAuthorisationRequest(
- request, contact);
-
- //and now pretend that the remote contact has granted us
- //authorization
- return new AuthorizationResponse(AuthorizationResponse.ACCEPT
- , "You are welcome!");
- }
- }
- }
-
- /**
- * Adds a subscription for the presence status of the contact
- * corresponding to the specified contactIdentifier.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * updates we are subscribing for. <p>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(String contactIdentifier) throws
- IllegalArgumentException, IllegalStateException,
- OperationFailedException
- {
- //subscribe(contactListRoot, contactIdentifier);
-
- }
-
- /**
- * Removes a subscription for the presence status of the specified
- * contact.
- *
- * @param contact the contact whose status updates we are unsubscribing
- * from.
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * unsubscribing fails due to errors experienced during network
- * communication
- */
- public void unsubscribe(Contact contact) throws IllegalArgumentException,
- IllegalStateException, OperationFailedException
- {
- ContactGroupDictImpl parentGroup
- = (ContactGroupDictImpl)((ContactDictImpl)contact)
- .getParentContactGroup();
-
- parentGroup.removeContact((ContactDictImpl)contact);
-
- fireSubscriptionEvent(contact,
- ((ContactDictImpl)contact).getParentContactGroup()
- , SubscriptionEvent.SUBSCRIPTION_REMOVED);
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created Contact
- * against the server. The protocol provider may will later try and resolve
- * the contact. When this happens the corresponding event would notify
- * interested subscription listeners.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(String address,
- String persistentData)
- {
- return createUnresolvedContact(address
- , persistentData
- , getServerStoredContactListRoot());
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created Contact
- * against the server. The protocol provider may will later try and resolve
- * the contact. When this happens the corresponding event would notify
- * interested subscription listeners.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @param parent the group where the unresolved contact is
- * supposed to belong to.
- *
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(String address,
- String persistentData,
- ContactGroup parent)
- {
-
- ContactDictImpl contact = new ContactDictImpl(
- address
- , parentProvider);
- contact.setResolved(false);
-
- ( (ContactGroupDictImpl) parent).addContact(contact);
-
- fireSubscriptionEvent(contact,
- parent,
- SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- //since we don't have any server, we'll simply resolve the contact
- //ourselves as if we've just received an event from the server telling
- //us that it has been resolved.
- contact.setResolved(true);
- fireSubscriptionEvent(contact, parent, SubscriptionEvent.SUBSCRIPTION_RESOLVED);
-
- //since we are not a real protocol, we set the contact presence status
- //ourselves
- changePresenceStatusForContact( contact, getPresenceStatus());
-
- return contact;
- }
-
- /**
- * Looks for a dict protocol provider registered for a user id matching
- * <tt>dictUserID</tt>.
- *
- * @param dictUserID the ID of the Dict user whose corresponding
- * protocol provider we'd like to find.
- * @return ProtocolProviderServiceDictImpl a dict protocol
- * provider registered for a user with id <tt>dictUserID</tt> or null
- * if there is no such protocol provider.
- */
- public ProtocolProviderServiceDictImpl
- findProviderForDictUserID(String dictUserID)
- {
- BundleContext bc = DictActivator.getBundleContext();
-
- String osgiQuery = "(&"
- + "(" + ProtocolProviderFactory.PROTOCOL
- + "=Dict)"
- + "(" + ProtocolProviderFactory.USER_ID
- + "=" + dictUserID + ")"
- + ")";
-
- ServiceReference[] refs = null;
- try
- {
- refs = bc.getServiceReferences(
- ProtocolProviderService.class.getName()
- ,osgiQuery);
- }
- catch (InvalidSyntaxException ex)
- {
- logger.error("Failed to execute the following osgi query: "
- + osgiQuery
- , ex);
- }
-
- if(refs != null && refs.length > 0)
- {
- return (ProtocolProviderServiceDictImpl)bc.getService(refs[0]);
- }
-
- return null;
- }
-
- /**
- * Looks for dict protocol providers that have added us to their
- * contact list and returns list of all contacts representing us in these
- * providers.
- *
- * @return a list of all contacts in other providers' contact lists that
- * point to us.
- */
- public List<Contact> findContactsPointingToUs()
- {
- List<Contact> contacts = new LinkedList<Contact>();
- BundleContext bc = DictActivator.getBundleContext();
-
- String osgiQuery =
- "(" + ProtocolProviderFactory.PROTOCOL
- + "=Dict)";
-
- ServiceReference[] refs = null;
- try
- {
- refs = bc.getServiceReferences(
- ProtocolProviderService.class.getName()
- ,osgiQuery);
- }
- catch (InvalidSyntaxException ex)
- {
- logger.error("Failed to execute the following osgi query: "
- + osgiQuery
- , ex);
- }
-
- for (int i =0; refs != null && i < refs.length; i++)
- {
- ProtocolProviderServiceDictImpl gibProvider
- = (ProtocolProviderServiceDictImpl)bc.getService(refs[i]);
-
- OperationSetPersistentPresenceDictImpl opSetPersPresence
- = (OperationSetPersistentPresenceDictImpl)gibProvider
- .getOperationSet(OperationSetPersistentPresence.class);
-
- Contact contact = opSetPersPresence.findContactByID(
- parentProvider.getAccountID().getUserID());
-
- if (contact != null)
- contacts.add(contact);
- }
-
- return contacts;
- }
-
-
- /**
- * Creates and returns a unresolved contact group from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created
- * <tt>ContactGroup</tt> against the server or the contact itself. The
- * protocol provider will later resolve the contact group. When this happens
- * the corresponding event would notify interested subscription listeners.
- *
- * @param groupUID an identifier, returned by ContactGroup's getGroupUID,
- * that the protocol provider may use in order to create the group.
- * @param persistentData a String returned ContactGroups's
- * getPersistentData() method during a previous run and that has been
- * persistently stored locally.
- * @param parentGroup the group under which the new group is to be created
- * or null if this is group directly underneath the root.
- * @return the unresolved <tt>ContactGroup</tt> created from the specified
- * <tt>uid</tt> and <tt>persistentData</tt>
- */
- public ContactGroup createUnresolvedContactGroup(String groupUID,
- String persistentData, ContactGroup parentGroup)
- {
- ContactGroupDictImpl newGroup
- = new ContactGroupDictImpl(
- ContactGroupDictImpl.createNameFromUID(groupUID)
- , parentProvider);
- newGroup.setResolved(false);
-
- //if parent is null then we're adding under root.
- if(parentGroup == null)
- parentGroup = getServerStoredContactListRoot();
-
- ((ContactGroupDictImpl)parentGroup).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
-
- return newGroup;
- }
-
- private class UnregistrationListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenver
- * a change in the registration state of the corresponding provider had
- * occurred. The method is particularly interested in events stating
- * that the dict provider has unregistered so that it would fire
- * status change events for all contacts in our buddy list.
- *
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
- if (! evt.getNewState().equals(RegistrationState.UNREGISTERED)
- && !evt.getNewState().equals(RegistrationState.AUTHENTICATION_FAILED)
- && !evt.getNewState().equals(RegistrationState.CONNECTION_FAILED))
- {
- return;
- }
-
- //send event notifications saying that all our buddies are
- //offline. The icq protocol does not implement top level buddies
- //nor subgroups for top level groups so a simple nested loop
- //would be enough.
- Iterator<ContactGroup> groupsIter = getServerStoredContactListRoot()
- .subgroups();
- while (groupsIter.hasNext())
- {
- ContactGroupDictImpl group
- = (ContactGroupDictImpl) groupsIter.next();
-
- Iterator<Contact> contactsIter = group.contacts();
-
- while (contactsIter.hasNext())
- {
- ContactDictImpl contact
- = (ContactDictImpl) contactsIter.next();
-
- PresenceStatus oldContactStatus
- = contact.getPresenceStatus();
-
- if (!oldContactStatus.isOnline())
- continue;
-
- contact.setPresenceStatus(DictStatusEnum.OFFLINE);
-
- fireContactPresenceStatusChangeEvent(
- contact
- , contact.getParentContactGroup()
- , oldContactStatus);
- }
- }
- }
- }
-
- /**
- * Returns the volatile group or null if this group has not yet been
- * created.
- *
- * @return a volatile group existing in our contact list or <tt>null</tt>
- * if such a group has not yet been created.
- */
- private ContactGroupDictImpl getNonPersistentGroup()
- {
- for (int i = 0
- ; i < getServerStoredContactListRoot().countSubgroups()
- ; i++)
- {
- ContactGroupDictImpl gr =
- (ContactGroupDictImpl)getServerStoredContactListRoot()
- .getGroup(i);
-
- if(!gr.isPersistent())
- return gr;
- }
-
- return null;
- }
-
-
- /**
- * Creates a non persistent contact for the specified address. This would
- * also create (if necessary) a group for volatile contacts that would not
- * be added to the server stored contact list. This method would have no
- * effect on the server stored contact list.
- *
- * @param contactAddress the address of the volatile contact we'd like to
- * create.
- * @return the newly created volatile contact.
- */
- public ContactDictImpl createVolatileContact(String contactAddress)
- {
- //First create the new volatile contact;
- ContactDictImpl newVolatileContact
- = new ContactDictImpl(contactAddress
- , this.parentProvider);
- newVolatileContact.setPersistent(false);
-
-
- //Check whether a volatile group already exists and if not create
- //one
- ContactGroupDictImpl theVolatileGroup = getNonPersistentGroup();
-
-
- //if the parent volatile group is null then we create it
- if (theVolatileGroup == null)
- {
- theVolatileGroup = new ContactGroupDictImpl(
- DictActivator.getResources().getI18NString(
- "service.gui.NOT_IN_CONTACT_LIST_GROUP_NAME")
- , parentProvider);
- theVolatileGroup.setResolved(false);
- theVolatileGroup.setPersistent(false);
-
- this.contactListRoot.addSubgroup(theVolatileGroup);
-
- fireServerStoredGroupEvent(theVolatileGroup
- , ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
- //now add the volatile contact instide it
- theVolatileGroup.addContact(newVolatileContact);
- fireSubscriptionEvent(newVolatileContact
- , theVolatileGroup
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- return newVolatileContact;
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolIconDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolIconDictImpl.java
deleted file mode 100644
index 4f09f22..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolIconDictImpl.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Represents the Dict protocol icon. Implements the <tt>ProtocolIcon</tt>
- * interface in order to provide a Dict logo image in two different sizes.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class ProtocolIconDictImpl
- implements ProtocolIcon
-{
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String,byte[]> iconsTable
- = new Hashtable<String,byte[]>();
- static
- {
- iconsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- DictActivator.getResources()
- .getImageInBytes("service.protocol.dict.DICT_16x16"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- DictActivator.getResources()
- .getImageInBytes("service.protocol.dict.DICT_32x32"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- DictActivator.getResources()
- .getImageInBytes("service.protocol.dict.DICT_48x48"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- DictActivator.getResources()
- .getImageInBytes("service.protocol.dict.DICT_64x64"));
- }
-
- /**
- * A hash table containing the path to the protocol icon in different sizes.
- */
- private static Hashtable<String, String> iconPathsTable
- = new Hashtable<String, String>();
- static
- {
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- DictActivator.getResources()
- .getImagePath("service.protocol.dict.DICT_16x16"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- DictActivator.getResources()
- .getImagePath("service.protocol.dict.DICT_32x32"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- DictActivator.getResources()
- .getImagePath("service.protocol.dict.DICT_48x48"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- DictActivator.getResources()
- .getImagePath("service.protocol.dict.DICT_64x64"));
- }
-
- /**
- * Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns
- * an iterator to a set containing the supported icon sizes.
- * @return Returns an iterator to a set containing the supported icon sizes
- */
- public Iterator<String> getSupportedSizes()
- {
- return iconsTable.keySet().iterator();
- }
-
- /**
- * Returns TRUE if an icon with the given size is supported, FALSE otherwise.
- * @param iconSize The size of the icon, that we want to know if it is
- * supported.
- * @return Returns true if the size is supported. False otherwise.
- */
- public boolean isSizeSupported(String iconSize)
- {
- return iconsTable.containsKey(iconSize);
- }
-
- /**
- * Returns the icon image in the given size.
- * @param iconSize The icon size one of ICON_SIZE_XXX constants
- * @return Returns a byte[] containing the pixels of the icon for the given
- * size.
- */
- public byte[] getIcon(String iconSize)
- {
- return iconsTable.get(iconSize);
- }
-
- /**
- * Returns a path to the icon with the given size.
- * @param iconSize the size of the icon we're looking for
- * @return the path to the icon with the given size
- */
- public String getIconPath(String iconSize)
- {
- return iconPathsTable.get(iconSize);
- }
-
- /**
- * Returns the icon image used to represent the protocol connecting state.
- * @return Returns the icon image used to represent the protocol connecting
- * state.
- */
- public byte[] getConnectingIcon()
- {
- return iconsTable.get(ProtocolIcon.ICON_SIZE_16x16);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderFactoryDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderFactoryDictImpl.java
deleted file mode 100644
index d7eaf30..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderFactoryDictImpl.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.contactlist.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.osgi.framework.*;
-
-/**
- * The Dict protocol provider factory creates instances of the Dict
- * protocol provider service. One Service instance corresponds to one account.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class ProtocolProviderFactoryDictImpl
- extends ProtocolProviderFactory
-{
- private static final Logger logger
- = Logger.getLogger(ProtocolProviderFactoryDictImpl.class);
-
- /**
- * Creates an instance of the ProtocolProviderFactoryDictImpl.
- */
- public ProtocolProviderFactoryDictImpl()
- {
- super(DictActivator.getBundleContext(), ProtocolNames.DICT);
- }
-
- /**
- * Initializaed and creates an account corresponding to the specified
- * accountProperties and registers the resulting ProtocolProvider in the
- * <tt>context</tt> BundleContext parameter.
- *
- * @param userIDStr The user identifier uniquely representing the newly
- * created account within the protocol namespace.
- * @param accountProperties a set of protocol (or implementation)
- * specific properties defining the new account.
- * @return the AccountID of the newly created account.
- */
- @Override
- public AccountID installAccount( String userIDStr,
- Map<String, String> accountProperties)
- {
- BundleContext context = DictActivator.getBundleContext();
- if (context == null)
- {
- throw new NullPointerException("The specified BundleContext was null");
- }
- if (userIDStr == null)
- {
- throw new NullPointerException("The specified AccountID was null");
- }
- if (accountProperties == null)
- {
- throw new NullPointerException("The specified property map was null");
- }
-
- accountProperties.put(USER_ID, userIDStr);
-
- AccountID accountID = new DictAccountID(userIDStr, accountProperties);
-
- //make sure we haven't seen this account id before.
- if (registeredAccounts.containsKey(accountID))
- {
- throw new IllegalStateException("An account for id " + userIDStr + " was already installed!");
- }
-
- //first store the account and only then load it as the load generates
- //an osgi event, the osgi event triggers (through the UI) a call to the
- //ProtocolProviderService.register() method and it needs to acces
- //the configuration service and check for a stored password.
- this.storeAccount(accountID, false);
-
- accountID = loadAccount(accountProperties);
-
- // Creates the dict contact group.
- this.createGroup();
- // Creates the default conatct for this dict server.
- this.createDefaultContact(accountID);
-
- return accountID;
- }
-
- @Override
- protected AccountID createAccountID(String userID, Map<String, String> accountProperties)
- {
- return new DictAccountID(userID, accountProperties);
- }
-
- @Override
- protected ProtocolProviderService createService(String userID,
- AccountID accountID)
- {
- ProtocolProviderServiceDictImpl service =
- new ProtocolProviderServiceDictImpl();
-
- service.initialize(userID, accountID);
- return service;
- }
-
- /**
- * Creates a group for the dict contacts
- */
- private void createGroup()
- {
- // Get MetaContactListService
- BundleContext bundleContext = getBundleContext();
- ServiceReference<MetaContactListService> mfcServiceRef
- = bundleContext.getServiceReference(MetaContactListService.class);
-
- MetaContactListService mcl = bundleContext.getService(mfcServiceRef);
-
- try
- {
- String groupName = DictActivator.getResources()
- .getI18NString("service.protocol.DICTIONARIES");
-
- mcl.createMetaContactGroup(mcl.getRoot(), groupName);
- }
- catch (MetaContactListException ex)
- {
- int errorCode = ex.getErrorCode();
- if (errorCode != MetaContactListException.CODE_GROUP_ALREADY_EXISTS_ERROR)
- {
- logger.error(ex);
- }
- }
- }
-
- /**
- * Creates a default contact for the new DICT server.
- * @param accountID The accountID of the dict protocol provider for which we
- * want to add a default contact.
- */
- private void createDefaultContact(AccountID accountID)
- {
- // Gets the MetaContactListService.
- BundleContext bundleContext = getBundleContext();
- ServiceReference<MetaContactListService> mfcServiceRef
- = bundleContext.getServiceReference(MetaContactListService.class);
- MetaContactListService mcl = bundleContext.getService(mfcServiceRef);
-
- // Gets the ProtocolProviderService.
- ServiceReference<ProtocolProviderService> serRef
- = getProviderForAccount(accountID);
- ProtocolProviderService protocolProvider
- = DictActivator.getBundleContext().getService(serRef);
-
- // Gets group name
- String groupName = DictActivator.getResources()
- .getI18NString("service.protocol.DICTIONARIES");
-
- // Gets contact name
- String contactName = DictActivator.getResources()
- .getI18NString("plugin.dictaccregwizz.ANY_DICTIONARY_FORM",
- new String[] {accountID.getUserID()});
-
- // Gets the MetaContactGroup for the "dictionaries" group.
- MetaContactGroup group = mcl.getRoot().getMetaContactSubgroup(groupName);
-
- // Sets the default contact identifier to "*" corresponding to "all the
- // dictionaries" available on the server (cf. RFC-2229).
- String dict_uin = "*";
- // Create the default contact.
- mcl.createMetaContact(protocolProvider, group, dict_uin);
- // Rename the default contact.
- mcl.renameMetaContact(
- group.getMetaContact(protocolProvider, dict_uin),
- contactName);
- }
-
- @Override
- public void modifyAccount(
- ProtocolProviderService protocolProvider,
- Map<String, String> accountProperties)
- throws NullPointerException
- {
- // TODO Auto-generated method stub
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderServiceDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderServiceDictImpl.java
deleted file mode 100644
index aa9ef50..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderServiceDictImpl.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.dict;
-
-import net.java.dict4j.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.version.*;
-import org.osgi.framework.*;
-
-/**
- * A Dict implementation of the ProtocolProviderService.
- *
- * @author ROTH Damien
- * @author LITZELMANN Cedric
- */
-public class ProtocolProviderServiceDictImpl
- extends AbstractProtocolProviderService
-{
- private static final Logger logger
- = Logger.getLogger(ProtocolProviderServiceDictImpl.class);
-
- /**
- * The name of this protocol.
- */
- public static final String DICT_PROTOCOL_NAME = "Dict";
-
- /**
- * The id of the account that this protocol provider represents.
- */
- private DictAccountID accountID = null;
-
- /**
- * We use this to lock access to initialization.
- */
- private Object initializationLock = new Object();
-
- /**
- * Indicates whether or not the provider is initialized and ready for use.
- */
- private boolean isInitialized = false;
-
- /**
- * The logo corresponding to the gibberish protocol.
- */
- private ProtocolIconDictImpl dictIcon = new ProtocolIconDictImpl();
-
- /**
- * The registration state that we are currently in. Note that in a real
- * world protocol implementation this field won't exist and the registration
- * state would be retrieved from the protocol stack.
- */
- private RegistrationState currentRegistrationState
- = RegistrationState.UNREGISTERED;
-
- /**
- * the <tt>DictConnection</tt> opened by this provider
- */
- private DictConnection dictConnection;
-
- /**
- * The default constructor for the Dict protocol provider.
- */
- public ProtocolProviderServiceDictImpl()
- {
- if (logger.isTraceEnabled())
- logger.trace("Creating a Dict provider.");
- }
-
- /**
- * Initializes the service implementation, and puts it in a sate where it
- * could interoperate with other services. It is strongly recomended that
- * properties in this Map be mapped to property names as specified by
- * <tt>AccountProperties</tt>.
- *
- * @param userID the user id of the gibberish account we're currently
- * initializing
- * @param accountID the identifier of the account that this protocol
- * provider represents.
- *
- * @see net.java.sip.communicator.service.protocol.AccountID
- */
- protected void initialize(String userID,
- AccountID accountID)
- {
- synchronized(initializationLock)
- {
- this.accountID = (DictAccountID) accountID;
-
- this.dictConnection = new DictConnection(this.accountID.getHost(),
- this.accountID.getPort());
- this.dictConnection.setClientName(getSCVersion());
-
- //initialize the presence operationset
- OperationSetPersistentPresenceDictImpl persistentPresence =
- new OperationSetPersistentPresenceDictImpl(this);
-
- addSupportedOperationSet(
- OperationSetPersistentPresence.class,
- persistentPresence);
- //register it once again for those that simply need presence and
- //won't be smart enough to check for a persistent presence
- //alternative
- addSupportedOperationSet(
- OperationSetPresence.class,
- persistentPresence);
-
- //initialize the IM operation set
- addSupportedOperationSet(
- OperationSetBasicInstantMessaging.class,
- new OperationSetBasicInstantMessagingDictImpl(
- this,
- persistentPresence));
-
- //initialize the typing notifications operation set
- /*OperationSetTypingNotifications typingNotifications =
- new OperationSetTypingNotificationsDictImpl(
- this, persistentPresence);
-
- supportedOperationSets.put(
- OperationSetTypingNotifications.class.getName(),
- typingNotifications);
- */
- isInitialized = true;
- }
- }
-
- /**
- * Returns the <tt>DictConnection</tt> opened by this provider
- * @return the <tt>DictConnection</tt> opened by this provider
- */
- public DictConnection getConnection()
- {
- return this.dictConnection;
- }
-
- /**
- * Returns the AccountID that uniquely identifies the account represented
- * by this instance of the ProtocolProviderService.
- *
- * @return the id of the account represented by this provider.
- */
- public AccountID getAccountID()
- {
- return accountID;
- }
-
- /**
- * Returns the short name of the protocol that the implementation of this
- * provider is based upon (like SIP, Jabber, ICQ/AIM, or others for
- * example).
- *
- * @return a String containing the short name of the protocol this
- * service is implementing (most often that would be a name in
- * ProtocolNames).
- */
- public String getProtocolName()
- {
- return DICT_PROTOCOL_NAME;
- }
-
- /**
- * Returns the dict protocol icon.
- * @return the dict protocol icon
- */
- public ProtocolIcon getProtocolIcon()
- {
- return this.dictIcon;
- }
-
- /**
- * Returns the state of the registration of this protocol provider with
- * the corresponding registration service.
- *
- * @return ProviderRegistrationState
- */
- public RegistrationState getRegistrationState()
- {
- return currentRegistrationState;
- }
-
- /**
- * Starts the registration process.
- *
- * @param authority the security authority that will be used for
- * resolving any security challenges that may be returned during the
- * registration or at any moment while wer're registered.
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void register(SecurityAuthority authority)
- throws OperationFailedException
- {
- // Try to connect to the server
- boolean connected = connect();
-
- if (connected)
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.REGISTERED,
- RegistrationStateChangeEvent.REASON_USER_REQUEST,
- null);
- currentRegistrationState = RegistrationState.REGISTERED;
- }
- else
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.CONNECTION_FAILED,
- RegistrationStateChangeEvent.REASON_SERVER_NOT_FOUND,
- null);
- currentRegistrationState = RegistrationState.UNREGISTERED;
- }
- }
-
- /**
- * Checks if the connection to the dict server is open
- * @return TRUE if the connection is open - FALSE otherwise
- */
- private boolean connect()
- {
- if (this.dictConnection.isConnected())
- {
- return true;
- }
-
- try
- {
- return this.dictConnection.isAvailable();
- }
- catch (DictException dx)
- {
- if (logger.isInfoEnabled())
- logger.info(dx);
- }
-
- return false;
- }
-
- /**
- * Makes the service implementation close all open sockets and release
- * any resources that it might have taken and prepare for
- * shutdown/garbage collection.
- */
- public void shutdown()
- {
- if(!isInitialized)
- {
- return;
- }
- if (logger.isTraceEnabled())
- logger.trace("Killing the Dict Protocol Provider for account "
- + this.accountID.getUserID());
-
- closeConnection();
-
- if(isRegistered())
- {
- try
- {
- //do the unregistration
- unregister();
- }
- catch (OperationFailedException ex)
- {
- //we're shutting down so we need to silence the exception here
- logger.error(
- "Failed to properly unregister before shutting down. "
- + getAccountID()
- , ex);
- }
- }
-
- isInitialized = false;
- }
-
- /**
- * Ends the registration of this protocol provider with the current
- * registration service.
- *
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void unregister()
- throws OperationFailedException
- {
- closeConnection();
-
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.UNREGISTERED,
- RegistrationStateChangeEvent.REASON_USER_REQUEST,
- null);
- }
-
- /**
- * DICT has no support for secure transport.
- */
- public boolean isSignalingTransportSecure()
- {
- return false;
- }
-
- /**
- * Returns the "transport" protocol of this instance used to carry the
- * control channel for the current protocol service.
- *
- * @return The "transport" protocol of this instance: TCP.
- */
- public TransportProtocol getTransportProtocol()
- {
- return TransportProtocol.TCP;
- }
-
- /**
- * Close the connection to the server
- */
- private void closeConnection()
- {
- try
- {
- this.dictConnection.close();
- }
- catch (DictException dx)
- {
- if (logger.isInfoEnabled())
- logger.info(dx);
- }
- }
-
- /**
- * Returns the current version of SIP-Communicator
- * @return the current version of SIP-Communicator
- */
- private String getSCVersion()
- {
- BundleContext bc = DictActivator.getBundleContext();
- ServiceReference vsr = bc.getServiceReference(VersionService.class.getName());
-
- VersionService vs = (VersionService) bc.getService(vsr);
- return vs.getCurrentVersion().toString();
-
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/dict.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/dict/dict.provider.manifest.mf
deleted file mode 100644
index d764657..0000000
--- a/src/net/java/sip/communicator/impl/protocol/dict/dict.provider.manifest.mf
+++ /dev/null
@@ -1,15 +0,0 @@
-Bundle-Activator: net.java.sip.communicator.impl.protocol.dict.DictActivator
-Bundle-Name: Dict Protocol Provider
-Bundle-Description: A bundle providing support for the Dict protocol.
-Bundle-Vendor: jitsi.org
-Bundle-Version: 1.0.0
-Bundle-SymbolicName: net.java.sip.communicator.protocol.dict
-Import-Package: org.osgi.framework,
- org.jitsi.service.version,
- net.java.sip.communicator.service.contactlist,
- org.jitsi.service.configuration,
- org.jitsi.service.resources, net.java.sip.communicator.service.resources,
- net.java.sip.communicator.util,
- net.java.sip.communicator.service.protocol,
- net.java.sip.communicator.service.protocol.event,
-Export-Package: net.java.dict4j
diff --git a/src/net/java/sip/communicator/impl/protocol/gibberish/ContactGroupGibberishImpl.java b/src/net/java/sip/communicator/impl/protocol/gibberish/ContactGroupGibberishImpl.java
index 2a95493..8528267 100644
--- a/src/net/java/sip/communicator/impl/protocol/gibberish/ContactGroupGibberishImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/gibberish/ContactGroupGibberishImpl.java
@@ -577,4 +577,29 @@ public class ContactGroupGibberishImpl
return true;
}
+
+ @Override
+ public int hashCode()
+ {
+ List<Object> objects = new ArrayList<Object>();
+ objects.add(getGroupName());
+ objects.add(getUID());
+ objects.add(countContacts());
+ objects.add(countSubgroups());
+
+ //traverse child contacts
+ for (Contact c : contacts)
+ {
+ objects.add(c.getAddress());
+ }
+
+
+ //traverse subgroups
+ for (ContactGroup g : subGroups)
+ {
+ objects.add(g.getGroupName());
+ }
+
+ return Objects.hash(objects.toArray());
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/icq/icq.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/icq/icq.provider.manifest.mf
index da47277..959ae6d 100644
--- a/src/net/java/sip/communicator/impl/protocol/icq/icq.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/icq/icq.provider.manifest.mf
@@ -13,5 +13,4 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.dns,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.icqconstants,
- net.java.sip.communicator.service.protocol.aimconstants,
net.java.sip.communicator.service.protocol.event
diff --git a/src/net/java/sip/communicator/impl/protocol/irc/OperationSetMultiUserChatIrcImpl.java b/src/net/java/sip/communicator/impl/protocol/irc/OperationSetMultiUserChatIrcImpl.java
index 6b09978..7a1c2b3 100644
--- a/src/net/java/sip/communicator/impl/protocol/irc/OperationSetMultiUserChatIrcImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/irc/OperationSetMultiUserChatIrcImpl.java
@@ -275,7 +275,7 @@ public class OperationSetMultiUserChatIrcImpl
*/
protected ChatRoomIrcImpl getChatRoom(final String chatRoomName)
{
- return (ChatRoomIrcImpl) this.chatRoomCache.get(chatRoomName);
+ return this.chatRoomCache.get(chatRoomName);
}
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/AnonymousLoginStrategy.java b/src/net/java/sip/communicator/impl/protocol/jabber/AnonymousLoginStrategy.java
index c955100..b62d01a 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/AnonymousLoginStrategy.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/AnonymousLoginStrategy.java
@@ -70,7 +70,7 @@ public class AnonymousLoginStrategy
}
@Override
- public boolean login(XMPPConnection connection, String userName,
+ public boolean login(Connection connection, String userName,
String resource)
throws XMPPException
{
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
index e23481a..3987ea8 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
@@ -311,7 +311,7 @@ public class CallJabberImpl
contentRequest.addChannel(remoteChannelRequest);
}
- XMPPConnection connection = protocolProvider.getConnection();
+ Connection connection = protocolProvider.getConnection();
PacketCollector packetCollector
= connection.createPacketCollector(
new PacketIDFilter(conferenceRequest.getPacketID()));
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java
index 64eb5fa..c257202 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,1647 +15,1644 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.jabber;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
-import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
-import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.ContentPacketExtension.SendersEnum;
-import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.neomedia.*;
-import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.filter.*;
-import org.jivesoftware.smack.packet.*;
-import org.jivesoftware.smack.util.*;
-import org.jivesoftware.smackx.packet.*;
-
-/**
- * Implements a Jabber <tt>CallPeer</tt>.
- *
- * @author Emil Ivov
- * @author Lyubomir Marinov
- * @author Boris Grozev
- */
-public class CallPeerJabberImpl
- extends AbstractCallPeerJabberGTalkImpl
- <CallJabberImpl, CallPeerMediaHandlerJabberImpl, JingleIQ>
-{
- /**
- * The <tt>Logger</tt> used by the <tt>CallPeerJabberImpl</tt> class and its
- * instances for logging output.
- */
- private static final Logger logger
- = Logger.getLogger(CallPeerJabberImpl.class);
-
- /**
- * If the call is cancelled before session-initiate is sent.
- */
- private boolean cancelled = false;
-
- /**
- * Synchronization object for candidates available.
- */
- private final Object candSyncRoot = new Object();
-
- /**
- * If the content-add does not contains candidates.
- */
- private boolean contentAddWithNoCands = false;
-
- /**
- * If we have processed the session initiate.
- */
- private boolean sessionInitiateProcessed = false;
-
- /**
- * Synchronization object. Synchronization object? Wow, who would have
- * thought! ;) Would be great to have a word on what we are syncing with it
- */
- private final Object sessionInitiateSyncRoot = new Object();
-
- /**
- * Synchronization object for SID.
- */
- private final Object sidSyncRoot = new Object();
-
- /**
- * The current value of the 'senders' field of the audio content in the
- * Jingle session with this <tt>CallPeer</tt>.
- * <tt>null</tt> should be interpreted as 'both', which is the default in
- * Jingle if the XML attribute is missing.
- */
- private SendersEnum audioSenders = SendersEnum.none;
-
- /**
- * The current value of the 'senders' field of the video content in the
- * Jingle session with this <tt>CallPeer</tt>.
- * <tt>null</tt> should be interpreted as 'both', which is the default in
- * Jingle if the XML attribute is missing.
- */
- private SendersEnum videoSenders = SendersEnum.none;
-
- /**
- * Creates a new call peer with address <tt>peerAddress</tt>.
- *
- * @param peerAddress the Jabber address of the new call peer.
- * @param owningCall the call that contains this call peer.
- */
- public CallPeerJabberImpl(String peerAddress,
- CallJabberImpl owningCall)
- {
- super(peerAddress, owningCall);
-
- setMediaHandler(new CallPeerMediaHandlerJabberImpl(this));
- }
-
- /**
- * Creates a new call peer with address <tt>peerAddress</tt>.
- *
- * @param peerAddress the Jabber address of the new call peer.
- * @param owningCall the call that contains this call peer.
- * @param sessionIQ The session-initiate <tt>JingleIQ</tt> which was
- * received from <tt>peerAddress</tt> and caused the creation of this
- * <tt>CallPeerJabberImpl</tt>
- */
- public CallPeerJabberImpl(String peerAddress,
- CallJabberImpl owningCall,
- JingleIQ sessionIQ)
- {
- this(peerAddress, owningCall);
- this.sessionInitIQ = sessionIQ;
- }
-
- /**
- * Send a session-accept <tt>JingleIQ</tt> to this <tt>CallPeer</tt>
- * @throws OperationFailedException if we fail to create or send the
- * response.
- */
- public synchronized void answer()
- throws OperationFailedException
- {
- Iterable<ContentPacketExtension> answer;
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
-
- try
- {
- mediaHandler
- .getTransportManager()
- .wrapupConnectivityEstablishment();
- answer = mediaHandler.generateSessionAccept();
- for (ContentPacketExtension c : answer)
- setSenders(getMediaType(c), c.getSenders());
- }
- catch(Exception exc)
- {
- logger.info("Failed to answer an incoming call", exc);
-
- //send an error response
- String reasonText = "Error: " + exc.getMessage();
- JingleIQ errResp
- = JinglePacketFactory.createSessionTerminate(
- sessionInitIQ.getTo(),
- sessionInitIQ.getFrom(),
- sessionInitIQ.getSID(),
- Reason.FAILED_APPLICATION,
- reasonText);
-
- setState(CallPeerState.FAILED, reasonText);
- getProtocolProvider().getConnection().sendPacket(errResp);
- return;
- }
-
- JingleIQ response
- = JinglePacketFactory.createSessionAccept(
- sessionInitIQ.getTo(),
- sessionInitIQ.getFrom(),
- getSID(),
- answer);
-
- //send the packet first and start the stream later in case the media
- //relay needs to see it before letting hole punching techniques through.
- getProtocolProvider().getConnection().sendPacket(response);
-
- try
- {
- mediaHandler.start();
- }
- catch(UndeclaredThrowableException e)
- {
- Throwable exc = e.getUndeclaredThrowable();
-
- logger.info("Failed to establish a connection", exc);
-
- //send an error response
- String reasonText = "Error: " + exc.getMessage();
- JingleIQ errResp
- = JinglePacketFactory.createSessionTerminate(
- sessionInitIQ.getTo(),
- sessionInitIQ.getFrom(),
- sessionInitIQ.getSID(),
- Reason.GENERAL_ERROR,
- reasonText);
-
- setState(CallPeerState.FAILED, reasonText);
- getProtocolProvider().getConnection().sendPacket(errResp);
- return;
- }
-
- //tell everyone we are connected so that the audio notifications would
- //stop
- setState(CallPeerState.CONNECTED);
- }
-
- /**
- * Returns the session ID of the Jingle session associated with this call.
- *
- * @return the session ID of the Jingle session associated with this call.
- */
- @Override
- public String getSID()
- {
- return sessionInitIQ != null ? sessionInitIQ.getSID() : null;
- }
-
- /**
- * Returns the IQ ID of the Jingle session-initiate packet associated with
- * this call.
- *
- * @return the IQ ID of the Jingle session-initiate packet associated with
- * this call.
- */
- public JingleIQ getSessionIQ()
- {
- return sessionInitIQ;
- }
-
- /**
- * Ends the call with this <tt>CallPeer</tt>. Depending on the state
- * of the peer the method would send a CANCEL, BYE, or BUSY_HERE message
- * and set the new state to DISCONNECTED.
- *
- * @param failed indicates if the hangup is following to a call failure or
- * simply a disconnect
- * @param reasonText the text, if any, to be set on the
- * <tt>ReasonPacketExtension</tt> as the value of its
- * @param reasonOtherExtension the <tt>PacketExtension</tt>, if any, to be
- * set on the <tt>ReasonPacketExtension</tt> as the value of its
- * <tt>otherExtension</tt> property
- */
- public void hangup(boolean failed,
- String reasonText,
- PacketExtension reasonOtherExtension)
- {
- CallPeerState prevPeerState = getState();
-
- // do nothing if the call is already ended
- if (CallPeerState.DISCONNECTED.equals(prevPeerState)
- || CallPeerState.FAILED.equals(prevPeerState))
- {
- if (logger.isDebugEnabled())
- logger.debug("Ignoring a request to hangup a call peer "
- + "that is already DISCONNECTED");
- return;
- }
-
- setState(
- failed ? CallPeerState.FAILED : CallPeerState.DISCONNECTED,
- reasonText);
-
- JingleIQ responseIQ = null;
-
- if (prevPeerState.equals(CallPeerState.CONNECTED)
- || CallPeerState.isOnHold(prevPeerState))
- {
- responseIQ = JinglePacketFactory.createBye(
- getProtocolProvider().getOurJID(), peerJID, getSID());
- }
- else if (CallPeerState.CONNECTING.equals(prevPeerState)
- || CallPeerState.CONNECTING_WITH_EARLY_MEDIA.equals(prevPeerState)
- || CallPeerState.ALERTING_REMOTE_SIDE.equals(prevPeerState))
- {
- String jingleSID = getSID();
-
- if(jingleSID == null)
- {
- synchronized(sidSyncRoot)
- {
- // we cancelled the call too early because the jingleSID
- // is null (i.e. the session-initiate has not been created)
- // and no need to send the session-terminate
- cancelled = true;
- return;
- }
- }
-
- responseIQ = JinglePacketFactory.createCancel(
- getProtocolProvider().getOurJID(), peerJID, getSID());
- }
- else if (prevPeerState.equals(CallPeerState.INCOMING_CALL))
- {
- responseIQ = JinglePacketFactory.createBusy(
- getProtocolProvider().getOurJID(), peerJID, getSID());
- }
- else if (prevPeerState.equals(CallPeerState.BUSY)
- || prevPeerState.equals(CallPeerState.FAILED))
- {
- // For FAILED and BUSY we only need to update CALL_STATUS
- // as everything else has been done already.
- }
- else
- {
- logger.info("Could not determine call peer state!");
- }
-
- if (responseIQ != null)
- {
- if (reasonOtherExtension != null)
- {
- ReasonPacketExtension reason
- = (ReasonPacketExtension)
- responseIQ.getExtension(
- ReasonPacketExtension.ELEMENT_NAME,
- ReasonPacketExtension.NAMESPACE);
-
- if (reason != null)
- {
- reason.setOtherExtension(reasonOtherExtension);
- }
- else if(reasonOtherExtension instanceof ReasonPacketExtension)
- {
- responseIQ.setReason(
- (ReasonPacketExtension)reasonOtherExtension);
- }
- }
-
- getProtocolProvider().getConnection().sendPacket(responseIQ);
- }
- }
-
- /**
- * Creates and sends a session-initiate {@link JingleIQ}.
- *
- * @param sessionInitiateExtensions a collection of additional and optional
- * <tt>PacketExtension</tt>s to be added to the <tt>session-initiate</tt>
- * {@link JingleIQ} which is to initiate the session with this
- * <tt>CallPeerJabberImpl</tt>
- * @throws OperationFailedException exception
- */
- protected synchronized void initiateSession(
- Iterable<PacketExtension> sessionInitiateExtensions)
- throws OperationFailedException
- {
- initiator = false;
-
- //Create the media description that we'd like to send to the other side.
- List<ContentPacketExtension> offer
- = getMediaHandler().createContentList();
-
- ProtocolProviderServiceJabberImpl protocolProvider
- = getProtocolProvider();
-
- synchronized(sidSyncRoot)
- {
- sessionInitIQ
- = JinglePacketFactory.createSessionInitiate(
- protocolProvider.getOurJID(),
- this.peerJID,
- JingleIQ.generateSID(),
- offer);
-
- if(cancelled)
- {
- // we cancelled the call too early so no need to send the
- // session-initiate to peer
- getMediaHandler().getTransportManager().close();
- return;
- }
- }
-
- if (sessionInitiateExtensions != null)
- {
- for (PacketExtension sessionInitiateExtension
- : sessionInitiateExtensions)
- {
- sessionInitIQ.addExtension(sessionInitiateExtension);
- }
- }
-
- protocolProvider.getConnection().sendPacket(sessionInitIQ);
- }
-
- /**
- * Notifies this instance that a specific <tt>ColibriConferenceIQ</tt> has
- * been received. This <tt>CallPeerJabberImpl</tt> uses the part of the
- * information provided in the specified <tt>conferenceIQ</tt> which
- * concerns it only.
- *
- * @param conferenceIQ the <tt>ColibriConferenceIQ</tt> which has been
- * received
- */
- void processColibriConferenceIQ(ColibriConferenceIQ conferenceIQ)
- {
- /*
- * CallPeerJabberImpl does not itself/directly know the specifics
- * related to the channels allocated on the Jitsi Videobridge server.
- * The channels contain transport and media-related information so
- * forward the notification to CallPeerMediaHandlerJabberImpl.
- */
- getMediaHandler().processColibriConferenceIQ(conferenceIQ);
- }
-
- /**
- * Processes the content-accept {@link JingleIQ}.
- *
- * @param content The {@link JingleIQ} that contains content that remote
- * peer has accepted
- */
- public void processContentAccept(JingleIQ content)
- {
- List<ContentPacketExtension> contents = content.getContentList();
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
-
- try
- {
- mediaHandler
- .getTransportManager()
- .wrapupConnectivityEstablishment();
- mediaHandler.processAnswer(contents);
- for (ContentPacketExtension c : contents)
- setSenders(getMediaType(c), c.getSenders());
- }
- catch (Exception e)
- {
- logger.warn("Failed to process a content-accept", e);
-
- // Send an error response.
- String reason = "Error: " + e.getMessage();
- JingleIQ errResp
- = JinglePacketFactory.createSessionTerminate(
- getProtocolProvider().getOurJID(),
- peerJID,
- sessionInitIQ.getSID(),
- Reason.INCOMPATIBLE_PARAMETERS,
- reason);
-
- setState(CallPeerState.FAILED, reason);
- getProtocolProvider().getConnection().sendPacket(errResp);
- return;
- }
-
- mediaHandler.start();
- }
-
- /**
- * Processes the content-add {@link JingleIQ}.
- *
- * @param content The {@link JingleIQ} that contains content that remote
- * peer wants to be added
- */
- public void processContentAdd(final JingleIQ content)
- {
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
- List<ContentPacketExtension> contents = content.getContentList();
- Iterable<ContentPacketExtension> answerContents;
- JingleIQ contentIQ;
- boolean noCands = false;
- MediaStream oldVideoStream = mediaHandler.getStream(MediaType.VIDEO);
-
- if(logger.isInfoEnabled())
- logger.info("Looking for candidates in content-add.");
- try
- {
- if(!contentAddWithNoCands)
- {
- mediaHandler.processOffer(contents);
-
- /*
- * Gingle transport will not put candidate in session-initiate
- * and content-add.
- */
- for(ContentPacketExtension c : contents)
- {
- if(JingleUtils.getFirstCandidate(c, 1) == null)
- {
- contentAddWithNoCands = true;
- noCands = true;
- }
- }
- }
-
- // if no candidates are present, launch a new Thread which will
- // process and wait for the connectivity establishment (otherwise
- // the existing thread will be blocked and thus cannot receive
- // transport-info with candidates
- if(noCands)
- {
- new Thread()
- {
- @Override
- public void run()
- {
- try
- {
- synchronized(candSyncRoot)
- {
- candSyncRoot.wait();
- }
- }
- catch(InterruptedException e)
- {
- }
-
- processContentAdd(content);
- contentAddWithNoCands = false;
- }
- }.start();
- if(logger.isInfoEnabled())
- logger.info("No candidates found in content-add, started "
- + "new thread.");
- return;
- }
-
- mediaHandler
- .getTransportManager()
- .wrapupConnectivityEstablishment();
- if(logger.isInfoEnabled())
- logger.info("Wrapping up connectivity establishment");
- answerContents = mediaHandler.generateSessionAccept();
- contentIQ = null;
- }
- catch(Exception e)
- {
- logger.warn("Exception occurred", e);
-
- answerContents = null;
- contentIQ
- = JinglePacketFactory.createContentReject(
- getProtocolProvider().getOurJID(),
- this.peerJID,
- getSID(),
- answerContents);
- }
-
- if(contentIQ == null)
- {
- /* send content-accept */
- contentIQ
- = JinglePacketFactory.createContentAccept(
- getProtocolProvider().getOurJID(),
- this.peerJID,
- getSID(),
- answerContents);
- for (ContentPacketExtension c : answerContents)
- setSenders(getMediaType(c), c.getSenders());
- }
-
- getProtocolProvider().getConnection().sendPacket(contentIQ);
- mediaHandler.start();
-
- /*
- * If a remote peer turns her video on in a conference which is hosted
- * by the local peer and the local peer is not streaming her local
- * video, reinvite the other remote peers to enable RTP translation.
- */
- if (oldVideoStream == null)
- {
- MediaStream newVideoStream
- = mediaHandler.getStream(MediaType.VIDEO);
-
- if ((newVideoStream != null)
- && mediaHandler.isRTPTranslationEnabled(MediaType.VIDEO))
- {
- try
- {
- getCall().modifyVideoContent();
- }
- catch (OperationFailedException ofe)
- {
- logger.error("Failed to enable RTP translation", ofe);
- }
- }
- }
- }
-
- /**
- * Processes the content-modify {@link JingleIQ}.
- *
- * @param content The {@link JingleIQ} that contains content that remote
- * peer wants to be modified
- */
- public void processContentModify(JingleIQ content)
- {
- ContentPacketExtension ext = content.getContentList().get(0);
- MediaType mediaType = getMediaType(ext);
-
- try
- {
- boolean modify
- = (ext.getFirstChildOfType(RtpDescriptionPacketExtension.class)
- != null);
-
- getMediaHandler().reinitContent(ext.getName(), ext, modify);
-
- setSenders(mediaType, ext.getSenders());
-
- if (MediaType.VIDEO.equals(mediaType))
- getCall().modifyVideoContent();
- }
- catch(Exception e)
- {
- logger.info("Failed to process an incoming content-modify", e);
-
- // Send an error response.
- String reason = "Error: " + e.getMessage();
- JingleIQ errResp
- = JinglePacketFactory.createSessionTerminate(
- getProtocolProvider().getOurJID(),
- peerJID,
- sessionInitIQ.getSID(),
- Reason.INCOMPATIBLE_PARAMETERS,
- reason);
-
- setState(CallPeerState.FAILED, reason);
- getProtocolProvider().getConnection().sendPacket(errResp);
- return;
- }
- }
-
- /**
- * Processes the content-reject {@link JingleIQ}.
- *
- * @param content The {@link JingleIQ}
- */
- public void processContentReject(JingleIQ content)
- {
- if(content.getContentList().isEmpty())
- {
- //send an error response;
- JingleIQ errResp = JinglePacketFactory.createSessionTerminate(
- sessionInitIQ.getTo(), sessionInitIQ.getFrom(),
- sessionInitIQ.getSID(), Reason.INCOMPATIBLE_PARAMETERS,
- "Error: content rejected");
-
- setState(CallPeerState.FAILED, "Error: content rejected");
- getProtocolProvider().getConnection().sendPacket(errResp);
- return;
- }
- }
-
- /**
- * Processes the content-remove {@link JingleIQ}.
- *
- * @param content The {@link JingleIQ} that contains content that remote
- * peer wants to be removed
- */
- public void processContentRemove(JingleIQ content)
- {
- List<ContentPacketExtension> contents = content.getContentList();
- boolean videoContentRemoved = false;
-
- if (!contents.isEmpty())
- {
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
-
- for(ContentPacketExtension c : contents)
- {
- mediaHandler.removeContent(c.getName());
-
- MediaType mediaType = getMediaType(c);
- setSenders(mediaType, SendersEnum.none);
-
- if (MediaType.VIDEO.equals(mediaType))
- videoContentRemoved = true;
- }
-
- /*
- * TODO XEP-0166: Jingle says: If the content-remove results in zero
- * content definitions for the session, the entity that receives the
- * content-remove SHOULD send a session-terminate action to the
- * other party (since a session with no content definitions is
- * void).
- */
- }
-
- if (videoContentRemoved)
- {
- // removing of the video content might affect the other sessions
- // in the call
- try
- {
- getCall().modifyVideoContent();
- }
- catch (Exception e)
- {
- logger.warn("Failed to update Jingle sessions");
- }
- }
- }
-
- /**
- * Processes a session-accept {@link JingleIQ}.
- *
- * @param sessionInitIQ The session-accept {@link JingleIQ} to process.
- */
- public void processSessionAccept(JingleIQ sessionInitIQ)
- {
- this.sessionInitIQ = sessionInitIQ;
-
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
- List<ContentPacketExtension> answer = sessionInitIQ.getContentList();
-
- try
- {
- mediaHandler
- .getTransportManager()
- .wrapupConnectivityEstablishment();
- mediaHandler.processAnswer(answer);
- for (ContentPacketExtension c : answer)
- setSenders(getMediaType(c), c.getSenders());
- }
- catch(Exception exc)
- {
- if (logger.isInfoEnabled())
- logger.info("Failed to process a session-accept", exc);
-
- //send an error response;
- JingleIQ errResp = JinglePacketFactory.createSessionTerminate(
- sessionInitIQ.getTo(), sessionInitIQ.getFrom(),
- sessionInitIQ.getSID(), Reason.INCOMPATIBLE_PARAMETERS,
- exc.getClass().getName() + ": " + exc.getMessage());
-
- setState(CallPeerState.FAILED, "Error: " + exc.getMessage());
- getProtocolProvider().getConnection().sendPacket(errResp);
- return;
- }
-
- //tell everyone we are connected so that the audio notifications would
- //stop
- setState(CallPeerState.CONNECTED);
-
- mediaHandler.start();
-
- /*
- * If video was added to the call after we sent the session-initiate
- * to this peer, it needs to be added to this peer's session with a
- * content-add.
- */
- sendModifyVideoContent();
- }
-
- /**
- * Handles the specified session <tt>info</tt> packet according to its
- * content.
- *
- * @param info the {@link SessionInfoPacketExtension} that we just received.
- */
- public void processSessionInfo(SessionInfoPacketExtension info)
- {
- switch (info.getType())
- {
- case ringing:
- setState(CallPeerState.ALERTING_REMOTE_SIDE);
- break;
- case hold:
- getMediaHandler().setRemotelyOnHold(true);
- reevalRemoteHoldStatus();
- break;
- case unhold:
- case active:
- getMediaHandler().setRemotelyOnHold(false);
- reevalRemoteHoldStatus();
- break;
- default:
- logger.warn("Received SessionInfoPacketExtension of unknown type");
- }
- }
-
- /**
- * Processes the session initiation {@link JingleIQ} that we were created
- * with, passing its content to the media handler and then sends either a
- * "session-info/ringing" or a "session-terminate" response.
- *
- * @param sessionInitIQ The {@link JingleIQ} that created the session that
- * we are handling here.
- */
- protected synchronized void processSessionInitiate(JingleIQ sessionInitIQ)
- {
- // Do initiate the session.
- this.sessionInitIQ = sessionInitIQ;
- this.initiator = true;
-
- // This is the SDP offer that came from the initial session-initiate.
- // Contrary to SIP, we are guaranteed to have content because XEP-0166
- // says: "A session consists of at least one content type at a time."
- List<ContentPacketExtension> offer = sessionInitIQ.getContentList();
-
- try
- {
- getMediaHandler().processOffer(offer);
-
- CoinPacketExtension coin = null;
-
- for(PacketExtension ext : sessionInitIQ.getExtensions())
- {
- if(ext.getElementName().equals(
- CoinPacketExtension.ELEMENT_NAME))
- {
- coin = (CoinPacketExtension)ext;
- break;
- }
- }
-
- /* does the call peer acts as a conference focus ? */
- if(coin != null)
- {
- setConferenceFocus(Boolean.parseBoolean(
- (String)coin.getAttribute("isfocus")));
- }
- }
- catch(Exception ex)
- {
- logger.info("Failed to process an incoming session initiate", ex);
-
- //send an error response;
- String reasonText = "Error: " + ex.getMessage();
- JingleIQ errResp
- = JinglePacketFactory.createSessionTerminate(
- sessionInitIQ.getTo(),
- sessionInitIQ.getFrom(),
- sessionInitIQ.getSID(),
- Reason.INCOMPATIBLE_PARAMETERS,
- reasonText);
-
- setState(CallPeerState.FAILED, reasonText);
- getProtocolProvider().getConnection().sendPacket(errResp);
- return;
- }
-
- // If we do not get the info about the remote peer yet. Get it right
- // now.
- if(this.getDiscoveryInfo() == null)
- {
- String calleeURI = sessionInitIQ.getFrom();
- retrieveDiscoveryInfo(calleeURI);
- }
-
- //send a ringing response
- if (logger.isTraceEnabled())
- logger.trace("will send ringing response: ");
-
- getProtocolProvider().getConnection().sendPacket(
- JinglePacketFactory.createRinging(sessionInitIQ));
-
- synchronized(sessionInitiateSyncRoot)
- {
- sessionInitiateProcessed = true;
- sessionInitiateSyncRoot.notify();
- }
-
- //if this is a 3264 initiator, let's give them an early peek at our
- //answer so that they could start ICE (SIP-2-Jingle gateways won't
- //be able to send their candidates unless they have this)
- DiscoverInfo discoverInfo = getDiscoveryInfo();
- if ((discoverInfo != null)
- && discoverInfo.containsFeature(
- ProtocolProviderServiceJabberImpl.URN_IETF_RFC_3264))
- {
- getProtocolProvider().getConnection().sendPacket(
- JinglePacketFactory.createDescriptionInfo(
- sessionInitIQ.getTo(),
- sessionInitIQ.getFrom(),
- sessionInitIQ.getSID(),
- getMediaHandler().getLocalContentList()));
- }
- }
-
- /**
- * Puts this peer into a {@link CallPeerState#DISCONNECTED}, indicating a
- * reason to the user, if there is one.
- *
- * @param jingleIQ the {@link JingleIQ} that's terminating our session.
- */
- public void processSessionTerminate(JingleIQ jingleIQ)
- {
- String reasonStr = "Call ended by remote side.";
- ReasonPacketExtension reasonExt = jingleIQ.getReason();
-
- if(reasonExt != null)
- {
- Reason reason = reasonExt.getReason();
-
- if(reason != null)
- reasonStr += " Reason: " + reason.toString() + ".";
-
- String text = reasonExt.getText();
-
- if(text != null)
- reasonStr += " " + text;
- }
-
- setState(CallPeerState.DISCONNECTED, reasonStr);
- }
-
- /**
- * Processes a specific "XEP-0251: Jingle Session Transfer"
- * <tt>transfer</tt> packet (extension).
- *
- * @param transfer the "XEP-0251: Jingle Session Transfer" transfer packet
- * (extension) to process
- * @throws OperationFailedException if anything goes wrong while processing
- * the specified <tt>transfer</tt> packet (extension)
- */
- public void processTransfer(TransferPacketExtension transfer)
- throws OperationFailedException
- {
- String attendantAddress = transfer.getFrom();
-
- if (attendantAddress == null)
- {
- throw new OperationFailedException(
- "Session transfer must contain a \'from\' attribute value.",
- OperationFailedException.ILLEGAL_ARGUMENT);
- }
-
- String calleeAddress = transfer.getTo();
-
- if (calleeAddress == null)
- {
- throw new OperationFailedException(
- "Session transfer must contain a \'to\' attribute value.",
- OperationFailedException.ILLEGAL_ARGUMENT);
- }
-
- // Checks if the transfer remote peer is contained by the roster of this
- // account.
- Roster roster = getProtocolProvider().getConnection().getRoster();
- if(!roster.contains(StringUtils.parseBareAddress(calleeAddress)))
- {
- String failedMessage =
- "Transfer impossible:\n"
- + "Account roster does not contain transfer peer: "
- + StringUtils.parseBareAddress(calleeAddress);
- setState(CallPeerState.FAILED, failedMessage);
- logger.info(failedMessage);
- }
-
- OperationSetBasicTelephonyJabberImpl basicTelephony
- = (OperationSetBasicTelephonyJabberImpl)
- getProtocolProvider()
- .getOperationSet(OperationSetBasicTelephony.class);
- CallJabberImpl calleeCall = new CallJabberImpl(basicTelephony);
- TransferPacketExtension calleeTransfer = new TransferPacketExtension();
- String sid = transfer.getSID();
-
- calleeTransfer.setFrom(attendantAddress);
- if (sid != null)
- {
- calleeTransfer.setSID(sid);
- calleeTransfer.setTo(calleeAddress);
- }
- basicTelephony.createOutgoingCall(
- calleeCall,
- calleeAddress,
- Arrays.asList(new PacketExtension[] { calleeTransfer }));
- }
-
- /**
- * Processes the <tt>transport-info</tt> {@link JingleIQ}.
- *
- * @param jingleIQ the <tt>transport-info</tt> {@link JingleIQ} to process
- */
- public void processTransportInfo(JingleIQ jingleIQ)
- {
- /*
- * The transport-info action is used to exchange transport candidates so
- * it only concerns the mediaHandler.
- */
- try
- {
- if(isInitiator())
- {
- synchronized(sessionInitiateSyncRoot)
- {
- if(!sessionInitiateProcessed)
- {
- try
- {
- sessionInitiateSyncRoot.wait();
- }
- catch(InterruptedException e)
- {
- }
- }
- }
- }
-
- getMediaHandler().processTransportInfo(
- jingleIQ.getContentList());
- }
- catch (OperationFailedException ofe)
- {
- logger.warn("Failed to process an incoming transport-info", ofe);
-
- //send an error response
- String reasonText = "Error: " + ofe.getMessage();
- JingleIQ errResp
- = JinglePacketFactory.createSessionTerminate(
- getProtocolProvider().getOurJID(),
- peerJID,
- sessionInitIQ.getSID(),
- Reason.GENERAL_ERROR,
- reasonText);
-
- setState(CallPeerState.FAILED, reasonText);
- getProtocolProvider().getConnection().sendPacket(errResp);
-
- return;
- }
-
- synchronized(candSyncRoot)
- {
- candSyncRoot.notify();
- }
- }
-
- /**
- * Puts the <tt>CallPeer</tt> represented by this instance on or off hold.
- *
- * @param onHold <tt>true</tt> to have the <tt>CallPeer</tt> put on hold;
- * <tt>false</tt>, otherwise
- *
- * @throws OperationFailedException if we fail to construct or send the
- * INVITE request putting the remote side on/off hold.
- */
- public void putOnHold(boolean onHold)
- throws OperationFailedException
- {
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
-
- mediaHandler.setLocallyOnHold(onHold);
-
- SessionInfoType type;
-
- if(onHold)
- type = SessionInfoType.hold;
- else
- {
- type = SessionInfoType.unhold;
- getMediaHandler().reinitAllContents();
- }
-
- //we are now on hold and need to realize this before potentially
- //spoiling it all with an exception while sending the packet :).
- reevalLocalHoldStatus();
-
- JingleIQ onHoldIQ = JinglePacketFactory.createSessionInfo(
- getProtocolProvider().getOurJID(),
- peerJID,
- getSID(),
- type);
-
- getProtocolProvider().getConnection().sendPacket(onHoldIQ);
- }
-
- /**
- * Send a <tt>content-add</tt> to add video setup.
- */
- private void sendAddVideoContent()
- {
- List<ContentPacketExtension> contents;
-
- try
- {
- contents = getMediaHandler().createContentList(MediaType.VIDEO);
- }
- catch(Exception exc)
- {
- logger.warn("Failed to gather content for video type", exc);
- return;
- }
-
- ProtocolProviderServiceJabberImpl protocolProvider
- = getProtocolProvider();
- JingleIQ contentIQ
- = JinglePacketFactory.createContentAdd(
- protocolProvider.getOurJID(),
- this.peerJID,
- getSID(),
- contents);
-
- protocolProvider.getConnection().sendPacket(contentIQ);
- }
-
- /**
- * Sends a <tt>content</tt> message to reflect changes in the setup such as
- * the local peer/user becoming a conference focus.
- */
- public void sendCoinSessionInfo()
- {
- JingleIQ sessionInfoIQ
- = JinglePacketFactory.createSessionInfo(
- getProtocolProvider().getOurJID(),
- this.peerJID,
- getSID());
- CoinPacketExtension coinExt
- = new CoinPacketExtension(getCall().isConferenceFocus());
-
- sessionInfoIQ.addExtension(coinExt);
- getProtocolProvider().getConnection().sendPacket(sessionInfoIQ);
- }
-
- /**
- * Returns the <tt>MediaDirection</tt> that should be set for the content
- * of type <tt>mediaType</tt> in the Jingle session for this
- * <tt>CallPeer</tt>.
- * If we are the focus of a conference and are doing RTP translation,
- * takes into account the other <tt>CallPeer</tt>s in the <tt>Call</tt>.
- *
- * @param mediaType the <tt>MediaType</tt> for which to return the
- * <tt>MediaDirection</tt>
- * @return the <tt>MediaDirection</tt> that should be used for the content
- * of type <tt>mediaType</tt> in the Jingle session for this
- * <tt>CallPeer</tt>.
- */
- private MediaDirection getDirectionForJingle(MediaType mediaType)
- {
- MediaDirection direction = MediaDirection.INACTIVE;
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
-
- // If we are streaming media, the direction should allow sending
- if ( (MediaType.AUDIO == mediaType &&
- mediaHandler.isLocalAudioTransmissionEnabled()) ||
- (MediaType.VIDEO == mediaType &&
- isLocalVideoStreaming()))
- direction = direction.or(MediaDirection.SENDONLY);
-
- // If we are receiving media from this CallPeer, the direction should
- // allow receiving
- SendersEnum senders = getSenders(mediaType);
- if (senders == null || senders == SendersEnum.both ||
- (isInitiator() && senders == SendersEnum.initiator) ||
- (!isInitiator() && senders == SendersEnum.responder))
- direction = direction.or(MediaDirection.RECVONLY);
-
- // If we are the focus of a conference and we are receiving media from
- // another CallPeer in the same Call, the direction should allow sending
- CallJabberImpl call = getCall();
- if (call != null && call.isConferenceFocus())
- {
- for (CallPeerJabberImpl peer : call.getCallPeerList())
- {
- if (peer != this)
- {
- senders = peer.getSenders(mediaType);
- if (senders == null || senders == SendersEnum.both ||
- (peer.isInitiator()
- && senders == SendersEnum.initiator) ||
- (!peer.isInitiator()
- && senders == SendersEnum.responder))
- {
- direction = direction.or(MediaDirection.SENDONLY);
- break;
- }
- }
- }
- }
-
- return direction;
- }
-
- /**
- * Send, if necessary, a jingle <tt>content</tt> message to reflect change
- * in video setup. Whether the jingle session should have a video content,
- * and if so, the value of the <tt>senders</tt> field is determined
- * based on whether we are streaming local video and, if we are the focus
- * of a conference, on the other peers in the conference.
- * The message can be content-modify if video content exists (and the
- * <tt>senders</tt> field changes), content-add or content-remove.
- *
- * @return <tt>true</tt> if a jingle <tt>content</tt> message was sent.
- */
- public boolean sendModifyVideoContent()
- {
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
- MediaDirection direction = getDirectionForJingle(MediaType.VIDEO);
-
- ContentPacketExtension remoteContent
- = mediaHandler.getLocalContent(MediaType.VIDEO.toString());
-
- if (remoteContent == null)
- {
- if (direction == MediaDirection.INACTIVE)
- {
- // no video content, none needed
- return false;
- }
- else
- {
- if (getState() == CallPeerState.CONNECTED)
- {
- if (logger.isInfoEnabled())
- logger.info("Adding video content for " + this);
- sendAddVideoContent();
- return true;
- }
- return false;
- }
- }
- else
- {
- if (direction == MediaDirection.INACTIVE)
- {
- sendRemoveVideoContent();
- return true;
- }
- }
-
- SendersEnum senders = getSenders(MediaType.VIDEO);
- if (senders == null)
- senders = SendersEnum.both;
-
- SendersEnum newSenders = SendersEnum.none;
- if (MediaDirection.SENDRECV == direction)
- newSenders = SendersEnum.both;
- else if (MediaDirection.RECVONLY == direction)
- newSenders = isInitiator()
- ? SendersEnum.initiator : SendersEnum.responder;
- else if (MediaDirection.SENDONLY == direction)
- newSenders = isInitiator()
- ? SendersEnum.responder : SendersEnum.initiator;
-
- /*
- * Send Content-Modify
- */
- ContentPacketExtension ext = new ContentPacketExtension();
- String remoteContentName = remoteContent.getName();
-
- ext.setSenders(newSenders);
- ext.setCreator(remoteContent.getCreator());
- ext.setName(remoteContentName);
-
- if (newSenders != senders)
- {
- if (logger.isInfoEnabled())
- logger.info("Sending content modify, senders: "
- + senders + "->" + newSenders);
- ProtocolProviderServiceJabberImpl protocolProvider
- = getProtocolProvider();
- JingleIQ contentIQ
- = JinglePacketFactory.createContentModify(
- protocolProvider.getOurJID(),
- this.peerJID,
- getSID(),
- ext);
-
- protocolProvider.getConnection().sendPacket(contentIQ);
- }
-
- try
- {
- mediaHandler.reinitContent(remoteContentName, ext, false);
- mediaHandler.start();
- }
- catch(Exception e)
- {
- logger.warn("Exception occurred during media reinitialization", e);
- }
-
- return (newSenders != senders);
- }
-
- /**
- * Send a <tt>content</tt> message to reflect change in video setup (start
- * or stop).
- */
- public void sendModifyVideoResolutionContent()
- {
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
- ContentPacketExtension remoteContent
- = mediaHandler.getRemoteContent(MediaType.VIDEO.toString());
- ContentPacketExtension content;
-
- logger.info("send modify-content to change resolution");
-
- // send content-modify with RTP description
-
- // create content list with resolution
- try
- {
- content = mediaHandler.createContentForMedia(MediaType.VIDEO);
- }
- catch (Exception e)
- {
- logger.warn("Failed to gather content for video type", e);
- return;
- }
-
- // if we are only receiving video senders is null
- SendersEnum senders = remoteContent.getSenders();
-
- if (senders != null)
- content.setSenders(senders);
-
- ProtocolProviderServiceJabberImpl protocolProvider
- = getProtocolProvider();
- JingleIQ contentIQ
- = JinglePacketFactory.createContentModify(
- protocolProvider.getOurJID(),
- this.peerJID,
- getSID(),
- content);
-
- protocolProvider.getConnection().sendPacket(contentIQ);
-
- try
- {
- mediaHandler.reinitContent(remoteContent.getName(), content, false);
- mediaHandler.start();
- }
- catch(Exception e)
- {
- logger.warn("Exception occurred when media reinitialization", e);
- }
- }
-
- /**
- * Send a <tt>content-remove</tt> to remove video setup.
- */
- private void sendRemoveVideoContent()
- {
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
-
- ContentPacketExtension content = new ContentPacketExtension();
- ContentPacketExtension remoteContent
- = mediaHandler.getRemoteContent(MediaType.VIDEO.toString());
- if (remoteContent == null)
- return;
- String remoteContentName = remoteContent.getName();
-
- content.setName(remoteContentName);
- content.setCreator(remoteContent.getCreator());
- content.setSenders(remoteContent.getSenders());
-
- ProtocolProviderServiceJabberImpl protocolProvider
- = getProtocolProvider();
- JingleIQ contentIQ
- = JinglePacketFactory.createContentRemove(
- protocolProvider.getOurJID(),
- this.peerJID,
- getSID(),
- Arrays.asList(content));
-
- protocolProvider.getConnection().sendPacket(contentIQ);
- mediaHandler.removeContent(remoteContentName);
- setSenders(MediaType.VIDEO, SendersEnum.none);
- }
-
- /**
- * Sends local candidate addresses from the local peer to the remote peer
- * using the <tt>transport-info</tt> {@link JingleIQ}.
- *
- * @param contents the local candidate addresses to be sent from the local
- * peer to the remote peer using the <tt>transport-info</tt>
- * {@link JingleIQ}
- */
- protected void sendTransportInfo(Iterable<ContentPacketExtension> contents)
- {
- // if the call is canceled, do not start sending candidates in
- // transport-info
- if(cancelled)
- return;
-
- JingleIQ transportInfo = new JingleIQ();
-
- for (ContentPacketExtension content : contents)
- transportInfo.addContent(content);
-
- ProtocolProviderServiceJabberImpl protocolProvider
- = getProtocolProvider();
-
- transportInfo.setAction(JingleAction.TRANSPORT_INFO);
- transportInfo.setFrom(protocolProvider.getOurJID());
- transportInfo.setSID(getSID());
- transportInfo.setTo(getAddress());
- transportInfo.setType(IQ.Type.SET);
-
- PacketCollector collector
- = protocolProvider.getConnection().createPacketCollector(
- new PacketIDFilter(transportInfo.getPacketID()));
-
- protocolProvider.getConnection().sendPacket(transportInfo);
- collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- collector.cancel();
- }
-
- @Override
- public void setState(CallPeerState newState, String reason, int reasonCode)
- {
- CallPeerState oldState = getState();
- try
- {
- /*
- * We need to dispose of the transport manager before the
- * 'call' field is set to null, because if Jitsi Videobridge is in
- * use, it (the call) is needed in order to expire the
- * Videobridge channels.
- */
- if (CallPeerState.DISCONNECTED.equals(newState)
- || CallPeerState.FAILED.equals(newState))
- getMediaHandler().getTransportManager().close();
- }
- finally
- {
- super.setState(newState, reason, reasonCode);
- }
-
- if (CallPeerState.isOnHold(oldState)
- && CallPeerState.CONNECTED.equals(newState))
- {
- try
- {
- getCall().modifyVideoContent();
- }
- catch (OperationFailedException ofe)
- {
- logger.error("Failed to update call video state after " +
- "'hold' status removed for "+this);
- }
- }
- }
-
- /**
- * Transfer (in the sense of call transfer) this <tt>CallPeer</tt> to a
- * specific callee address which may optionally be participating in an
- * active <tt>Call</tt>.
- *
- * @param to the address of the callee to transfer this <tt>CallPeer</tt> to
- * @param sid the Jingle session ID of the active <tt>Call</tt> between the
- * local peer and the callee in the case of attended transfer; <tt>null</tt>
- * in the case of unattended transfer
- * @throws OperationFailedException if something goes wrong
- */
- protected void transfer(String to, String sid)
- throws OperationFailedException
- {
- JingleIQ transferSessionInfo = new JingleIQ();
- ProtocolProviderServiceJabberImpl protocolProvider
- = getProtocolProvider();
-
- transferSessionInfo.setAction(JingleAction.SESSION_INFO);
- transferSessionInfo.setFrom(protocolProvider.getOurJID());
- transferSessionInfo.setSID(getSID());
- transferSessionInfo.setTo(getAddress());
- transferSessionInfo.setType(IQ.Type.SET);
-
- TransferPacketExtension transfer = new TransferPacketExtension();
-
- // Attended transfer.
- if (sid != null)
- {
- /*
- * Not really sure what the value of the "from" attribute of the
- * "transfer" element should be but the examples in "XEP-0251:
- * Jingle Session Transfer" has it in the case of attended transfer.
- */
- transfer.setFrom(protocolProvider.getOurJID());
- transfer.setSID(sid);
-
- // Puts on hold the 2 calls before making the attended transfer.
- OperationSetBasicTelephonyJabberImpl basicTelephony
- = (OperationSetBasicTelephonyJabberImpl)
- protocolProvider.getOperationSet(
- OperationSetBasicTelephony.class);
- CallPeerJabberImpl callPeer = basicTelephony.getActiveCallPeer(sid);
- if(callPeer != null)
- {
- if(!CallPeerState.isOnHold(callPeer.getState()))
- {
- callPeer.putOnHold(true);
- }
- }
-
- if(!CallPeerState.isOnHold(this.getState()))
- {
- this.putOnHold(true);
- }
- }
- transfer.setTo(to);
-
- transferSessionInfo.addExtension(transfer);
-
- Connection connection = protocolProvider.getConnection();
- PacketCollector collector = connection.createPacketCollector(
- new PacketIDFilter(transferSessionInfo.getPacketID()));
- protocolProvider.getConnection().sendPacket(transferSessionInfo);
-
- Packet result
- = collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- if(result == null)
- {
- // Log the failed transfer call and notify the user.
- throw new OperationFailedException(
- "No response to the \"transfer\" request.",
- OperationFailedException.ILLEGAL_ARGUMENT);
- }
- else if (((IQ) result).getType() != IQ.Type.RESULT)
- {
- // Log the failed transfer call and notify the user.
- throw new OperationFailedException(
- "Remote peer does not manage call \"transfer\"."
- + "Response to the \"transfer\" request is: "
- + ((IQ) result).getType(),
- OperationFailedException.ILLEGAL_ARGUMENT);
- }
- else
- {
- String message = ((sid == null) ? "Unattended" : "Attended")
- + " transfer to: "
- + to;
- // Implements the SIP behavior: once the transfer is accepted, the
- // current call is closed.
- hangup(
- false,
- message,
- new ReasonPacketExtension(Reason.SUCCESS,
- message,
- new TransferredPacketExtension()));
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public String getEntity()
- {
- return getAddress();
- }
-
- /**
- * {@inheritDoc}
- *
- * In Jingle there isn't an actual "direction" parameter. We use the
- * <tt>senders</tt> field to calculate the direction.
- */
- @Override
- public MediaDirection getDirection(MediaType mediaType)
- {
- SendersEnum senders = getSenders(mediaType);
-
- if (senders == SendersEnum.none)
- {
- return MediaDirection.INACTIVE;
- }
- else if (senders == null || senders == SendersEnum.both)
- {
- return MediaDirection.SENDRECV;
- }
- else if (senders == SendersEnum.initiator)
- {
- return
- isInitiator()
- ? MediaDirection.RECVONLY
- : MediaDirection.SENDONLY;
- }
- else //senders == SendersEnum.responder
- {
- return
- isInitiator()
- ? MediaDirection.SENDONLY
- : MediaDirection.RECVONLY;
- }
- }
-
- /**
- * Gets the current value of the <tt>senders</tt> field of the content with
- * name <tt>mediaType</tt> in the Jingle session with this
- * <tt>CallPeer</tt>.
- *
- * @param mediaType the <tt>MediaType</tt> for which to get the current
- * value of the <tt>senders</tt> field.
- * @return the current value of the <tt>senders</tt> field of the content
- * with name <tt>mediaType</tt> in the Jingle session with this
- * <tt>CallPeer</tt>.
- */
- public SendersEnum getSenders(MediaType mediaType)
- {
- switch (mediaType)
- {
- case AUDIO:
- return audioSenders;
- case DATA:
- /*
- * FIXME DATA has been introduced as a MediaType but explicit
- * support for DATA content has not been added yet.
- */
- return SendersEnum.none;
- case VIDEO:
- return videoSenders;
- default:
- throw new IllegalArgumentException("mediaType");
- }
- }
-
- /**
- * Set the current value of the <tt>senders</tt> field of the content with
- * name <tt>mediaType</tt> in the Jingle session with this <tt>CallPeer</tt>
- * @param mediaType the <tt>MediaType</tt> for which to get the current
- * value of the <tt>senders</tt> field.
- * @param senders the value to set
- */
- public void setSenders(MediaType mediaType, SendersEnum senders)
- {
- if (mediaType == null)
- return;
- else if (MediaType.AUDIO.equals(mediaType))
- this.audioSenders = senders;
- else if (MediaType.VIDEO.equals(mediaType))
- this.videoSenders = senders;
- else
- throw new IllegalArgumentException("mediaType");
- }
-
- /**
- * Gets the <tt>MediaType</tt> of <tt>content</tt>. If <tt>content</tt>
- * does not have a <tt>description</tt> child and therefore not
- * <tt>MediaType</tt> can be associated with it, tries to take the
- * <tt>MediaType</tt> from the session's already established contents with
- * the same name as <tt>content</tt>
- * @param content the <tt>ContentPacketExtention</tt> for which to get the
- * <tt>MediaType</tt>
- * @return the <tt>MediaType</tt> of <tt>content</tt>.
- */
- public MediaType getMediaType(ContentPacketExtension content)
- {
- String contentName = content.getName();
- if (contentName == null)
- return null;
-
- MediaType mediaType = JingleUtils.getMediaType(content);
- if (mediaType == null)
- {
- CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
- for (MediaType m : MediaType.values())
- {
- ContentPacketExtension sessionContent
- = mediaHandler.getRemoteContent(m.toString());
- if (sessionContent == null)
- sessionContent = mediaHandler.getLocalContent(m.toString());
-
- if (sessionContent != null
- && contentName.equals(sessionContent.getName()))
- {
- mediaType = m;
- break;
- }
- }
- }
-
- return mediaType;
- }
-}
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.ContentPacketExtension.SendersEnum;
+import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.neomedia.*;
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.util.*;
+import org.jivesoftware.smackx.packet.*;
+
+/**
+ * Implements a Jabber <tt>CallPeer</tt>.
+ *
+ * @author Emil Ivov
+ * @author Lyubomir Marinov
+ * @author Boris Grozev
+ */
+public class CallPeerJabberImpl
+ extends AbstractCallPeerJabberGTalkImpl
+ <CallJabberImpl, CallPeerMediaHandlerJabberImpl, JingleIQ>
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>CallPeerJabberImpl</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(CallPeerJabberImpl.class);
+
+ /**
+ * If the call is cancelled before session-initiate is sent.
+ */
+ private boolean cancelled = false;
+
+ /**
+ * Synchronization object for candidates available.
+ */
+ private final Object candSyncRoot = new Object();
+
+ /**
+ * If the content-add does not contains candidates.
+ */
+ private boolean contentAddWithNoCands = false;
+
+ /**
+ * If we have processed the session initiate.
+ */
+ private boolean sessionInitiateProcessed = false;
+
+ /**
+ * Synchronization object. Synchronization object? Wow, who would have
+ * thought! ;) Would be great to have a word on what we are syncing with it
+ */
+ private final Object sessionInitiateSyncRoot = new Object();
+
+ /**
+ * Synchronization object for SID.
+ */
+ private final Object sidSyncRoot = new Object();
+
+ /**
+ * The current value of the 'senders' field of the audio content in the
+ * Jingle session with this <tt>CallPeer</tt>.
+ * <tt>null</tt> should be interpreted as 'both', which is the default in
+ * Jingle if the XML attribute is missing.
+ */
+ private SendersEnum audioSenders = SendersEnum.none;
+
+ /**
+ * The current value of the 'senders' field of the video content in the
+ * Jingle session with this <tt>CallPeer</tt>.
+ * <tt>null</tt> should be interpreted as 'both', which is the default in
+ * Jingle if the XML attribute is missing.
+ */
+ private SendersEnum videoSenders = SendersEnum.none;
+
+ /**
+ * Creates a new call peer with address <tt>peerAddress</tt>.
+ *
+ * @param peerAddress the Jabber address of the new call peer.
+ * @param owningCall the call that contains this call peer.
+ */
+ public CallPeerJabberImpl(String peerAddress,
+ CallJabberImpl owningCall)
+ {
+ super(peerAddress, owningCall);
+
+ setMediaHandler(new CallPeerMediaHandlerJabberImpl(this));
+ }
+
+ /**
+ * Creates a new call peer with address <tt>peerAddress</tt>.
+ *
+ * @param peerAddress the Jabber address of the new call peer.
+ * @param owningCall the call that contains this call peer.
+ * @param sessionIQ The session-initiate <tt>JingleIQ</tt> which was
+ * received from <tt>peerAddress</tt> and caused the creation of this
+ * <tt>CallPeerJabberImpl</tt>
+ */
+ public CallPeerJabberImpl(String peerAddress,
+ CallJabberImpl owningCall,
+ JingleIQ sessionIQ)
+ {
+ this(peerAddress, owningCall);
+ this.sessionInitIQ = sessionIQ;
+ }
+
+ /**
+ * Send a session-accept <tt>JingleIQ</tt> to this <tt>CallPeer</tt>
+ * @throws OperationFailedException if we fail to create or send the
+ * response.
+ */
+ public synchronized void answer()
+ throws OperationFailedException
+ {
+ Iterable<ContentPacketExtension> answer;
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+
+ try
+ {
+ mediaHandler
+ .getTransportManager()
+ .wrapupConnectivityEstablishment();
+ answer = mediaHandler.generateSessionAccept();
+ for (ContentPacketExtension c : answer)
+ setSenders(getMediaType(c), c.getSenders());
+ }
+ catch(Exception exc)
+ {
+ logger.info("Failed to answer an incoming call", exc);
+
+ //send an error response
+ String reasonText = "Error: " + exc.getMessage();
+ JingleIQ errResp
+ = JinglePacketFactory.createSessionTerminate(
+ sessionInitIQ.getTo(),
+ sessionInitIQ.getFrom(),
+ sessionInitIQ.getSID(),
+ Reason.FAILED_APPLICATION,
+ reasonText);
+
+ setState(CallPeerState.FAILED, reasonText);
+ getProtocolProvider().getConnection().sendPacket(errResp);
+ return;
+ }
+
+ JingleIQ response
+ = JinglePacketFactory.createSessionAccept(
+ sessionInitIQ.getTo(),
+ sessionInitIQ.getFrom(),
+ getSID(),
+ answer);
+
+ //send the packet first and start the stream later in case the media
+ //relay needs to see it before letting hole punching techniques through.
+ getProtocolProvider().getConnection().sendPacket(response);
+
+ try
+ {
+ mediaHandler.start();
+ }
+ catch(UndeclaredThrowableException e)
+ {
+ Throwable exc = e.getUndeclaredThrowable();
+
+ logger.info("Failed to establish a connection", exc);
+
+ //send an error response
+ String reasonText = "Error: " + exc.getMessage();
+ JingleIQ errResp
+ = JinglePacketFactory.createSessionTerminate(
+ sessionInitIQ.getTo(),
+ sessionInitIQ.getFrom(),
+ sessionInitIQ.getSID(),
+ Reason.GENERAL_ERROR,
+ reasonText);
+
+ setState(CallPeerState.FAILED, reasonText);
+ getProtocolProvider().getConnection().sendPacket(errResp);
+ return;
+ }
+
+ //tell everyone we are connected so that the audio notifications would
+ //stop
+ setState(CallPeerState.CONNECTED);
+ }
+
+ /**
+ * Returns the session ID of the Jingle session associated with this call.
+ *
+ * @return the session ID of the Jingle session associated with this call.
+ */
+ @Override
+ public String getSID()
+ {
+ return sessionInitIQ != null ? sessionInitIQ.getSID() : null;
+ }
+
+ /**
+ * Returns the IQ ID of the Jingle session-initiate packet associated with
+ * this call.
+ *
+ * @return the IQ ID of the Jingle session-initiate packet associated with
+ * this call.
+ */
+ public JingleIQ getSessionIQ()
+ {
+ return sessionInitIQ;
+ }
+
+ /**
+ * Ends the call with this <tt>CallPeer</tt>. Depending on the state
+ * of the peer the method would send a CANCEL, BYE, or BUSY_HERE message
+ * and set the new state to DISCONNECTED.
+ *
+ * @param failed indicates if the hangup is following to a call failure or
+ * simply a disconnect
+ * @param reasonText the text, if any, to be set on the
+ * <tt>ReasonPacketExtension</tt> as the value of its
+ * @param reasonOtherExtension the <tt>PacketExtension</tt>, if any, to be
+ * set on the <tt>ReasonPacketExtension</tt> as the value of its
+ * <tt>otherExtension</tt> property
+ */
+ public void hangup(boolean failed,
+ String reasonText,
+ PacketExtension reasonOtherExtension)
+ {
+ CallPeerState prevPeerState = getState();
+
+ // do nothing if the call is already ended
+ if (CallPeerState.DISCONNECTED.equals(prevPeerState)
+ || CallPeerState.FAILED.equals(prevPeerState))
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Ignoring a request to hangup a call peer "
+ + "that is already DISCONNECTED");
+ return;
+ }
+
+ setState(
+ failed ? CallPeerState.FAILED : CallPeerState.DISCONNECTED,
+ reasonText);
+
+ JingleIQ responseIQ = null;
+
+ if (prevPeerState.equals(CallPeerState.CONNECTED)
+ || CallPeerState.isOnHold(prevPeerState))
+ {
+ responseIQ = JinglePacketFactory.createBye(
+ getProtocolProvider().getOurJID(), peerJID, getSID());
+ }
+ else if (CallPeerState.CONNECTING.equals(prevPeerState)
+ || CallPeerState.CONNECTING_WITH_EARLY_MEDIA.equals(prevPeerState)
+ || CallPeerState.ALERTING_REMOTE_SIDE.equals(prevPeerState))
+ {
+ String jingleSID = getSID();
+
+ if(jingleSID == null)
+ {
+ synchronized(sidSyncRoot)
+ {
+ // we cancelled the call too early because the jingleSID
+ // is null (i.e. the session-initiate has not been created)
+ // and no need to send the session-terminate
+ cancelled = true;
+ return;
+ }
+ }
+
+ responseIQ = JinglePacketFactory.createCancel(
+ getProtocolProvider().getOurJID(), peerJID, getSID());
+ }
+ else if (prevPeerState.equals(CallPeerState.INCOMING_CALL))
+ {
+ responseIQ = JinglePacketFactory.createBusy(
+ getProtocolProvider().getOurJID(), peerJID, getSID());
+ }
+ else if (prevPeerState.equals(CallPeerState.BUSY)
+ || prevPeerState.equals(CallPeerState.FAILED))
+ {
+ // For FAILED and BUSY we only need to update CALL_STATUS
+ // as everything else has been done already.
+ }
+ else
+ {
+ logger.info("Could not determine call peer state!");
+ }
+
+ if (responseIQ != null)
+ {
+ if (reasonOtherExtension != null)
+ {
+ ReasonPacketExtension reason
+ = (ReasonPacketExtension)
+ responseIQ.getExtension(
+ ReasonPacketExtension.ELEMENT_NAME,
+ ReasonPacketExtension.NAMESPACE);
+
+ if (reason != null)
+ {
+ reason.setOtherExtension(reasonOtherExtension);
+ }
+ else if(reasonOtherExtension instanceof ReasonPacketExtension)
+ {
+ responseIQ.setReason(
+ (ReasonPacketExtension)reasonOtherExtension);
+ }
+ }
+
+ getProtocolProvider().getConnection().sendPacket(responseIQ);
+ }
+ }
+
+ /**
+ * Creates and sends a session-initiate {@link JingleIQ}.
+ *
+ * @param sessionInitiateExtensions a collection of additional and optional
+ * <tt>PacketExtension</tt>s to be added to the <tt>session-initiate</tt>
+ * {@link JingleIQ} which is to initiate the session with this
+ * <tt>CallPeerJabberImpl</tt>
+ * @throws OperationFailedException exception
+ */
+ protected synchronized void initiateSession(
+ Iterable<PacketExtension> sessionInitiateExtensions)
+ throws OperationFailedException
+ {
+ initiator = false;
+
+ //Create the media description that we'd like to send to the other side.
+ List<ContentPacketExtension> offer
+ = getMediaHandler().createContentList();
+
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
+
+ synchronized(sidSyncRoot)
+ {
+ sessionInitIQ
+ = JinglePacketFactory.createSessionInitiate(
+ protocolProvider.getOurJID(),
+ this.peerJID,
+ JingleIQ.generateSID(),
+ offer);
+
+ if(cancelled)
+ {
+ // we cancelled the call too early so no need to send the
+ // session-initiate to peer
+ getMediaHandler().getTransportManager().close();
+ return;
+ }
+ }
+
+ if (sessionInitiateExtensions != null)
+ {
+ for (PacketExtension sessionInitiateExtension
+ : sessionInitiateExtensions)
+ {
+ sessionInitIQ.addExtension(sessionInitiateExtension);
+ }
+ }
+
+ protocolProvider.getConnection().sendPacket(sessionInitIQ);
+ }
+
+ /**
+ * Notifies this instance that a specific <tt>ColibriConferenceIQ</tt> has
+ * been received. This <tt>CallPeerJabberImpl</tt> uses the part of the
+ * information provided in the specified <tt>conferenceIQ</tt> which
+ * concerns it only.
+ *
+ * @param conferenceIQ the <tt>ColibriConferenceIQ</tt> which has been
+ * received
+ */
+ void processColibriConferenceIQ(ColibriConferenceIQ conferenceIQ)
+ {
+ /*
+ * CallPeerJabberImpl does not itself/directly know the specifics
+ * related to the channels allocated on the Jitsi Videobridge server.
+ * The channels contain transport and media-related information so
+ * forward the notification to CallPeerMediaHandlerJabberImpl.
+ */
+ getMediaHandler().processColibriConferenceIQ(conferenceIQ);
+ }
+
+ /**
+ * Processes the content-accept {@link JingleIQ}.
+ *
+ * @param content The {@link JingleIQ} that contains content that remote
+ * peer has accepted
+ */
+ public void processContentAccept(JingleIQ content)
+ {
+ List<ContentPacketExtension> contents = content.getContentList();
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+
+ try
+ {
+ mediaHandler
+ .getTransportManager()
+ .wrapupConnectivityEstablishment();
+ mediaHandler.processAnswer(contents);
+ for (ContentPacketExtension c : contents)
+ setSenders(getMediaType(c), c.getSenders());
+ }
+ catch (Exception e)
+ {
+ logger.warn("Failed to process a content-accept", e);
+
+ // Send an error response.
+ String reason = "Error: " + e.getMessage();
+ JingleIQ errResp
+ = JinglePacketFactory.createSessionTerminate(
+ getProtocolProvider().getOurJID(),
+ peerJID,
+ sessionInitIQ.getSID(),
+ Reason.INCOMPATIBLE_PARAMETERS,
+ reason);
+
+ setState(CallPeerState.FAILED, reason);
+ getProtocolProvider().getConnection().sendPacket(errResp);
+ return;
+ }
+
+ mediaHandler.start();
+ }
+
+ /**
+ * Processes the content-add {@link JingleIQ}.
+ *
+ * @param content The {@link JingleIQ} that contains content that remote
+ * peer wants to be added
+ */
+ public void processContentAdd(final JingleIQ content)
+ {
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+ List<ContentPacketExtension> contents = content.getContentList();
+ Iterable<ContentPacketExtension> answerContents;
+ JingleIQ contentIQ;
+ boolean noCands = false;
+ MediaStream oldVideoStream = mediaHandler.getStream(MediaType.VIDEO);
+
+ if(logger.isInfoEnabled())
+ logger.info("Looking for candidates in content-add.");
+ try
+ {
+ if(!contentAddWithNoCands)
+ {
+ mediaHandler.processOffer(contents);
+
+ /*
+ * Gingle transport will not put candidate in session-initiate
+ * and content-add.
+ */
+ for(ContentPacketExtension c : contents)
+ {
+ if(JingleUtils.getFirstCandidate(c, 1) == null)
+ {
+ contentAddWithNoCands = true;
+ noCands = true;
+ }
+ }
+ }
+
+ // if no candidates are present, launch a new Thread which will
+ // process and wait for the connectivity establishment (otherwise
+ // the existing thread will be blocked and thus cannot receive
+ // transport-info with candidates
+ if(noCands)
+ {
+ new Thread()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ synchronized(candSyncRoot)
+ {
+ candSyncRoot.wait();
+ }
+ }
+ catch(InterruptedException e)
+ {
+ }
+
+ processContentAdd(content);
+ contentAddWithNoCands = false;
+ }
+ }.start();
+ if(logger.isInfoEnabled())
+ logger.info("No candidates found in content-add, started "
+ + "new thread.");
+ return;
+ }
+
+ mediaHandler
+ .getTransportManager()
+ .wrapupConnectivityEstablishment();
+ if(logger.isInfoEnabled())
+ logger.info("Wrapping up connectivity establishment");
+ answerContents = mediaHandler.generateSessionAccept();
+ contentIQ = null;
+ }
+ catch(Exception e)
+ {
+ logger.warn("Exception occurred", e);
+
+ answerContents = null;
+ contentIQ
+ = JinglePacketFactory.createContentReject(
+ getProtocolProvider().getOurJID(),
+ this.peerJID,
+ getSID(),
+ answerContents);
+ }
+
+ if(contentIQ == null)
+ {
+ /* send content-accept */
+ contentIQ
+ = JinglePacketFactory.createContentAccept(
+ getProtocolProvider().getOurJID(),
+ this.peerJID,
+ getSID(),
+ answerContents);
+ for (ContentPacketExtension c : answerContents)
+ setSenders(getMediaType(c), c.getSenders());
+ }
+
+ getProtocolProvider().getConnection().sendPacket(contentIQ);
+ mediaHandler.start();
+
+ /*
+ * If a remote peer turns her video on in a conference which is hosted
+ * by the local peer and the local peer is not streaming her local
+ * video, reinvite the other remote peers to enable RTP translation.
+ */
+ if (oldVideoStream == null)
+ {
+ MediaStream newVideoStream
+ = mediaHandler.getStream(MediaType.VIDEO);
+
+ if ((newVideoStream != null)
+ && mediaHandler.isRTPTranslationEnabled(MediaType.VIDEO))
+ {
+ try
+ {
+ getCall().modifyVideoContent();
+ }
+ catch (OperationFailedException ofe)
+ {
+ logger.error("Failed to enable RTP translation", ofe);
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes the content-modify {@link JingleIQ}.
+ *
+ * @param content The {@link JingleIQ} that contains content that remote
+ * peer wants to be modified
+ */
+ public void processContentModify(JingleIQ content)
+ {
+ ContentPacketExtension ext = content.getContentList().get(0);
+ MediaType mediaType = getMediaType(ext);
+
+ try
+ {
+ boolean modify
+ = (ext.getFirstChildOfType(RtpDescriptionPacketExtension.class)
+ != null);
+
+ getMediaHandler().reinitContent(ext.getName(), ext, modify);
+
+ setSenders(mediaType, ext.getSenders());
+
+ if (MediaType.VIDEO.equals(mediaType))
+ getCall().modifyVideoContent();
+ }
+ catch(Exception e)
+ {
+ logger.info("Failed to process an incoming content-modify", e);
+
+ // Send an error response.
+ String reason = "Error: " + e.getMessage();
+ JingleIQ errResp
+ = JinglePacketFactory.createSessionTerminate(
+ getProtocolProvider().getOurJID(),
+ peerJID,
+ sessionInitIQ.getSID(),
+ Reason.INCOMPATIBLE_PARAMETERS,
+ reason);
+
+ setState(CallPeerState.FAILED, reason);
+ getProtocolProvider().getConnection().sendPacket(errResp);
+ return;
+ }
+ }
+
+ /**
+ * Processes the content-reject {@link JingleIQ}.
+ *
+ * @param content The {@link JingleIQ}
+ */
+ public void processContentReject(JingleIQ content)
+ {
+ if(content.getContentList().isEmpty())
+ {
+ //send an error response;
+ JingleIQ errResp = JinglePacketFactory.createSessionTerminate(
+ sessionInitIQ.getTo(), sessionInitIQ.getFrom(),
+ sessionInitIQ.getSID(), Reason.INCOMPATIBLE_PARAMETERS,
+ "Error: content rejected");
+
+ setState(CallPeerState.FAILED, "Error: content rejected");
+ getProtocolProvider().getConnection().sendPacket(errResp);
+ return;
+ }
+ }
+
+ /**
+ * Processes the content-remove {@link JingleIQ}.
+ *
+ * @param content The {@link JingleIQ} that contains content that remote
+ * peer wants to be removed
+ */
+ public void processContentRemove(JingleIQ content)
+ {
+ List<ContentPacketExtension> contents = content.getContentList();
+ boolean videoContentRemoved = false;
+
+ if (!contents.isEmpty())
+ {
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+
+ for(ContentPacketExtension c : contents)
+ {
+ mediaHandler.removeContent(c.getName());
+
+ MediaType mediaType = getMediaType(c);
+ setSenders(mediaType, SendersEnum.none);
+
+ if (MediaType.VIDEO.equals(mediaType))
+ videoContentRemoved = true;
+ }
+
+ /*
+ * TODO XEP-0166: Jingle says: If the content-remove results in zero
+ * content definitions for the session, the entity that receives the
+ * content-remove SHOULD send a session-terminate action to the
+ * other party (since a session with no content definitions is
+ * void).
+ */
+ }
+
+ if (videoContentRemoved)
+ {
+ // removing of the video content might affect the other sessions
+ // in the call
+ try
+ {
+ getCall().modifyVideoContent();
+ }
+ catch (Exception e)
+ {
+ logger.warn("Failed to update Jingle sessions");
+ }
+ }
+ }
+
+ /**
+ * Processes a session-accept {@link JingleIQ}.
+ *
+ * @param sessionInitIQ The session-accept {@link JingleIQ} to process.
+ */
+ public void processSessionAccept(JingleIQ sessionInitIQ)
+ {
+ this.sessionInitIQ = sessionInitIQ;
+
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+ List<ContentPacketExtension> answer = sessionInitIQ.getContentList();
+
+ try
+ {
+ mediaHandler
+ .getTransportManager()
+ .wrapupConnectivityEstablishment();
+ mediaHandler.processAnswer(answer);
+ for (ContentPacketExtension c : answer)
+ setSenders(getMediaType(c), c.getSenders());
+ }
+ catch(Exception exc)
+ {
+ if (logger.isInfoEnabled())
+ logger.info("Failed to process a session-accept", exc);
+
+ //send an error response;
+ JingleIQ errResp = JinglePacketFactory.createSessionTerminate(
+ sessionInitIQ.getTo(), sessionInitIQ.getFrom(),
+ sessionInitIQ.getSID(), Reason.INCOMPATIBLE_PARAMETERS,
+ exc.getClass().getName() + ": " + exc.getMessage());
+
+ setState(CallPeerState.FAILED, "Error: " + exc.getMessage());
+ getProtocolProvider().getConnection().sendPacket(errResp);
+ return;
+ }
+
+ //tell everyone we are connected so that the audio notifications would
+ //stop
+ setState(CallPeerState.CONNECTED);
+
+ mediaHandler.start();
+
+ /*
+ * If video was added to the call after we sent the session-initiate
+ * to this peer, it needs to be added to this peer's session with a
+ * content-add.
+ */
+ sendModifyVideoContent();
+ }
+
+ /**
+ * Handles the specified session <tt>info</tt> packet according to its
+ * content.
+ *
+ * @param info the {@link SessionInfoPacketExtension} that we just received.
+ */
+ public void processSessionInfo(SessionInfoPacketExtension info)
+ {
+ switch (info.getType())
+ {
+ case ringing:
+ setState(CallPeerState.ALERTING_REMOTE_SIDE);
+ break;
+ case hold:
+ getMediaHandler().setRemotelyOnHold(true);
+ reevalRemoteHoldStatus();
+ break;
+ case unhold:
+ case active:
+ getMediaHandler().setRemotelyOnHold(false);
+ reevalRemoteHoldStatus();
+ break;
+ default:
+ logger.warn("Received SessionInfoPacketExtension of unknown type");
+ }
+ }
+
+ /**
+ * Processes the session initiation {@link JingleIQ} that we were created
+ * with, passing its content to the media handler and then sends either a
+ * "session-info/ringing" or a "session-terminate" response.
+ *
+ * @param sessionInitIQ The {@link JingleIQ} that created the session that
+ * we are handling here.
+ */
+ protected synchronized void processSessionInitiate(JingleIQ sessionInitIQ)
+ {
+ // Do initiate the session.
+ this.sessionInitIQ = sessionInitIQ;
+ this.initiator = true;
+
+ // This is the SDP offer that came from the initial session-initiate.
+ // Contrary to SIP, we are guaranteed to have content because XEP-0166
+ // says: "A session consists of at least one content type at a time."
+ List<ContentPacketExtension> offer = sessionInitIQ.getContentList();
+
+ try
+ {
+ getMediaHandler().processOffer(offer);
+
+ CoinPacketExtension coin = null;
+
+ for(PacketExtension ext : sessionInitIQ.getExtensions())
+ {
+ if(ext.getElementName().equals(
+ CoinPacketExtension.ELEMENT_NAME))
+ {
+ coin = (CoinPacketExtension)ext;
+ break;
+ }
+ }
+
+ /* does the call peer acts as a conference focus ? */
+ if(coin != null)
+ {
+ setConferenceFocus(Boolean.parseBoolean(
+ (String)coin.getAttribute("isfocus")));
+ }
+ }
+ catch(Exception ex)
+ {
+ logger.info("Failed to process an incoming session initiate", ex);
+
+ //send an error response;
+ String reasonText = "Error: " + ex.getMessage();
+ JingleIQ errResp
+ = JinglePacketFactory.createSessionTerminate(
+ sessionInitIQ.getTo(),
+ sessionInitIQ.getFrom(),
+ sessionInitIQ.getSID(),
+ Reason.INCOMPATIBLE_PARAMETERS,
+ reasonText);
+
+ setState(CallPeerState.FAILED, reasonText);
+ getProtocolProvider().getConnection().sendPacket(errResp);
+ return;
+ }
+
+ // If we do not get the info about the remote peer yet. Get it right
+ // now.
+ if(this.getDiscoveryInfo() == null)
+ {
+ String calleeURI = sessionInitIQ.getFrom();
+ retrieveDiscoveryInfo(calleeURI);
+ }
+
+ //send a ringing response
+ if (logger.isTraceEnabled())
+ logger.trace("will send ringing response: ");
+
+ getProtocolProvider().getConnection().sendPacket(
+ JinglePacketFactory.createRinging(sessionInitIQ));
+
+ synchronized(sessionInitiateSyncRoot)
+ {
+ sessionInitiateProcessed = true;
+ sessionInitiateSyncRoot.notify();
+ }
+
+ //if this is a 3264 initiator, let's give them an early peek at our
+ //answer so that they could start ICE (SIP-2-Jingle gateways won't
+ //be able to send their candidates unless they have this)
+ DiscoverInfo discoverInfo = getDiscoveryInfo();
+ if ((discoverInfo != null)
+ && discoverInfo.containsFeature(
+ ProtocolProviderServiceJabberImpl.URN_IETF_RFC_3264))
+ {
+ getProtocolProvider().getConnection().sendPacket(
+ JinglePacketFactory.createDescriptionInfo(
+ sessionInitIQ.getTo(),
+ sessionInitIQ.getFrom(),
+ sessionInitIQ.getSID(),
+ getMediaHandler().getLocalContentList()));
+ }
+ }
+
+ /**
+ * Puts this peer into a {@link CallPeerState#DISCONNECTED}, indicating a
+ * reason to the user, if there is one.
+ *
+ * @param jingleIQ the {@link JingleIQ} that's terminating our session.
+ */
+ public void processSessionTerminate(JingleIQ jingleIQ)
+ {
+ String reasonStr = "Call ended by remote side.";
+ ReasonPacketExtension reasonExt = jingleIQ.getReason();
+
+ if(reasonExt != null)
+ {
+ Reason reason = reasonExt.getReason();
+
+ if(reason != null)
+ reasonStr += " Reason: " + reason.toString() + ".";
+
+ String text = reasonExt.getText();
+
+ if(text != null)
+ reasonStr += " " + text;
+ }
+
+ setState(CallPeerState.DISCONNECTED, reasonStr);
+ }
+
+ /**
+ * Processes a specific "XEP-0251: Jingle Session Transfer"
+ * <tt>transfer</tt> packet (extension).
+ *
+ * @param transfer the "XEP-0251: Jingle Session Transfer" transfer packet
+ * (extension) to process
+ * @throws OperationFailedException if anything goes wrong while processing
+ * the specified <tt>transfer</tt> packet (extension)
+ */
+ public void processTransfer(TransferPacketExtension transfer)
+ throws OperationFailedException
+ {
+ String attendantAddress = transfer.getFrom();
+
+ if (attendantAddress == null)
+ {
+ throw new OperationFailedException(
+ "Session transfer must contain a \'from\' attribute value.",
+ OperationFailedException.ILLEGAL_ARGUMENT);
+ }
+
+ String calleeAddress = transfer.getTo();
+
+ if (calleeAddress == null)
+ {
+ throw new OperationFailedException(
+ "Session transfer must contain a \'to\' attribute value.",
+ OperationFailedException.ILLEGAL_ARGUMENT);
+ }
+
+ // Checks if the transfer remote peer is contained by the roster of this
+ // account.
+ Roster roster = getProtocolProvider().getConnection().getRoster();
+ if(!roster.contains(StringUtils.parseBareAddress(calleeAddress)))
+ {
+ String failedMessage =
+ "Transfer impossible:\n"
+ + "Account roster does not contain transfer peer: "
+ + StringUtils.parseBareAddress(calleeAddress);
+ setState(CallPeerState.FAILED, failedMessage);
+ logger.info(failedMessage);
+ }
+
+ OperationSetBasicTelephonyJabberImpl basicTelephony
+ = (OperationSetBasicTelephonyJabberImpl)
+ getProtocolProvider()
+ .getOperationSet(OperationSetBasicTelephony.class);
+ CallJabberImpl calleeCall = new CallJabberImpl(basicTelephony);
+ TransferPacketExtension calleeTransfer = new TransferPacketExtension();
+ String sid = transfer.getSID();
+
+ calleeTransfer.setFrom(attendantAddress);
+ if (sid != null)
+ {
+ calleeTransfer.setSID(sid);
+ calleeTransfer.setTo(calleeAddress);
+ }
+ basicTelephony.createOutgoingCall(
+ calleeCall,
+ calleeAddress,
+ Arrays.asList(new PacketExtension[] { calleeTransfer }));
+ }
+
+ /**
+ * Processes the <tt>transport-info</tt> {@link JingleIQ}.
+ *
+ * @param jingleIQ the <tt>transport-info</tt> {@link JingleIQ} to process
+ */
+ public void processTransportInfo(JingleIQ jingleIQ)
+ {
+ /*
+ * The transport-info action is used to exchange transport candidates so
+ * it only concerns the mediaHandler.
+ */
+ try
+ {
+ if(isInitiator())
+ {
+ synchronized(sessionInitiateSyncRoot)
+ {
+ if(!sessionInitiateProcessed)
+ {
+ try
+ {
+ sessionInitiateSyncRoot.wait();
+ }
+ catch(InterruptedException e)
+ {
+ }
+ }
+ }
+ }
+
+ getMediaHandler().processTransportInfo(
+ jingleIQ.getContentList());
+ }
+ catch (OperationFailedException ofe)
+ {
+ logger.warn("Failed to process an incoming transport-info", ofe);
+
+ //send an error response
+ String reasonText = "Error: " + ofe.getMessage();
+ JingleIQ errResp
+ = JinglePacketFactory.createSessionTerminate(
+ getProtocolProvider().getOurJID(),
+ peerJID,
+ sessionInitIQ.getSID(),
+ Reason.GENERAL_ERROR,
+ reasonText);
+
+ setState(CallPeerState.FAILED, reasonText);
+ getProtocolProvider().getConnection().sendPacket(errResp);
+
+ return;
+ }
+
+ synchronized(candSyncRoot)
+ {
+ candSyncRoot.notify();
+ }
+ }
+
+ /**
+ * Puts the <tt>CallPeer</tt> represented by this instance on or off hold.
+ *
+ * @param onHold <tt>true</tt> to have the <tt>CallPeer</tt> put on hold;
+ * <tt>false</tt>, otherwise
+ *
+ * @throws OperationFailedException if we fail to construct or send the
+ * INVITE request putting the remote side on/off hold.
+ */
+ public void putOnHold(boolean onHold)
+ throws OperationFailedException
+ {
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+
+ mediaHandler.setLocallyOnHold(onHold);
+
+ SessionInfoType type;
+
+ if(onHold)
+ type = SessionInfoType.hold;
+ else
+ {
+ type = SessionInfoType.unhold;
+ getMediaHandler().reinitAllContents();
+ }
+
+ //we are now on hold and need to realize this before potentially
+ //spoiling it all with an exception while sending the packet :).
+ reevalLocalHoldStatus();
+
+ JingleIQ onHoldIQ = JinglePacketFactory.createSessionInfo(
+ getProtocolProvider().getOurJID(),
+ peerJID,
+ getSID(),
+ type);
+
+ getProtocolProvider().getConnection().sendPacket(onHoldIQ);
+ }
+
+ /**
+ * Send a <tt>content-add</tt> to add video setup.
+ */
+ private void sendAddVideoContent()
+ {
+ List<ContentPacketExtension> contents;
+
+ try
+ {
+ contents = getMediaHandler().createContentList(MediaType.VIDEO);
+ }
+ catch(Exception exc)
+ {
+ logger.warn("Failed to gather content for video type", exc);
+ return;
+ }
+
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
+ JingleIQ contentIQ
+ = JinglePacketFactory.createContentAdd(
+ protocolProvider.getOurJID(),
+ this.peerJID,
+ getSID(),
+ contents);
+
+ protocolProvider.getConnection().sendPacket(contentIQ);
+ }
+
+ /**
+ * Sends a <tt>content</tt> message to reflect changes in the setup such as
+ * the local peer/user becoming a conference focus.
+ */
+ public void sendCoinSessionInfo()
+ {
+ JingleIQ sessionInfoIQ
+ = JinglePacketFactory.createSessionInfo(
+ getProtocolProvider().getOurJID(),
+ this.peerJID,
+ getSID());
+ CoinPacketExtension coinExt
+ = new CoinPacketExtension(getCall().isConferenceFocus());
+
+ sessionInfoIQ.addExtension(coinExt);
+ getProtocolProvider().getConnection().sendPacket(sessionInfoIQ);
+ }
+
+ /**
+ * Returns the <tt>MediaDirection</tt> that should be set for the content
+ * of type <tt>mediaType</tt> in the Jingle session for this
+ * <tt>CallPeer</tt>.
+ * If we are the focus of a conference and are doing RTP translation,
+ * takes into account the other <tt>CallPeer</tt>s in the <tt>Call</tt>.
+ *
+ * @param mediaType the <tt>MediaType</tt> for which to return the
+ * <tt>MediaDirection</tt>
+ * @return the <tt>MediaDirection</tt> that should be used for the content
+ * of type <tt>mediaType</tt> in the Jingle session for this
+ * <tt>CallPeer</tt>.
+ */
+ private MediaDirection getDirectionForJingle(MediaType mediaType)
+ {
+ MediaDirection direction = MediaDirection.INACTIVE;
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+
+ // If we are streaming media, the direction should allow sending
+ if ( (MediaType.AUDIO == mediaType &&
+ mediaHandler.isLocalAudioTransmissionEnabled()) ||
+ (MediaType.VIDEO == mediaType &&
+ isLocalVideoStreaming()))
+ direction = direction.or(MediaDirection.SENDONLY);
+
+ // If we are receiving media from this CallPeer, the direction should
+ // allow receiving
+ SendersEnum senders = getSenders(mediaType);
+ if (senders == null || senders == SendersEnum.both ||
+ (isInitiator() && senders == SendersEnum.initiator) ||
+ (!isInitiator() && senders == SendersEnum.responder))
+ direction = direction.or(MediaDirection.RECVONLY);
+
+ // If we are the focus of a conference and we are receiving media from
+ // another CallPeer in the same Call, the direction should allow sending
+ CallJabberImpl call = getCall();
+ if (call != null && call.isConferenceFocus())
+ {
+ for (CallPeerJabberImpl peer : call.getCallPeerList())
+ {
+ if (peer != this)
+ {
+ senders = peer.getSenders(mediaType);
+ if (senders == null || senders == SendersEnum.both ||
+ (peer.isInitiator()
+ && senders == SendersEnum.initiator) ||
+ (!peer.isInitiator()
+ && senders == SendersEnum.responder))
+ {
+ direction = direction.or(MediaDirection.SENDONLY);
+ break;
+ }
+ }
+ }
+ }
+
+ return direction;
+ }
+
+ /**
+ * Send, if necessary, a jingle <tt>content</tt> message to reflect change
+ * in video setup. Whether the jingle session should have a video content,
+ * and if so, the value of the <tt>senders</tt> field is determined
+ * based on whether we are streaming local video and, if we are the focus
+ * of a conference, on the other peers in the conference.
+ * The message can be content-modify if video content exists (and the
+ * <tt>senders</tt> field changes), content-add or content-remove.
+ *
+ * @return <tt>true</tt> if a jingle <tt>content</tt> message was sent.
+ */
+ public boolean sendModifyVideoContent()
+ {
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+ MediaDirection direction = getDirectionForJingle(MediaType.VIDEO);
+
+ ContentPacketExtension remoteContent
+ = mediaHandler.getLocalContent(MediaType.VIDEO.toString());
+
+ if (remoteContent == null)
+ {
+ if (direction == MediaDirection.INACTIVE)
+ {
+ // no video content, none needed
+ return false;
+ }
+ else
+ {
+ if (getState() == CallPeerState.CONNECTED)
+ {
+ if (logger.isInfoEnabled())
+ logger.info("Adding video content for " + this);
+ sendAddVideoContent();
+ return true;
+ }
+ return false;
+ }
+ }
+ else
+ {
+ if (direction == MediaDirection.INACTIVE)
+ {
+ sendRemoveVideoContent();
+ return true;
+ }
+ }
+
+ SendersEnum senders = getSenders(MediaType.VIDEO);
+ if (senders == null)
+ senders = SendersEnum.both;
+
+ SendersEnum newSenders = SendersEnum.none;
+ if (MediaDirection.SENDRECV == direction)
+ newSenders = SendersEnum.both;
+ else if (MediaDirection.RECVONLY == direction)
+ newSenders = isInitiator()
+ ? SendersEnum.initiator : SendersEnum.responder;
+ else if (MediaDirection.SENDONLY == direction)
+ newSenders = isInitiator()
+ ? SendersEnum.responder : SendersEnum.initiator;
+
+ /*
+ * Send Content-Modify
+ */
+ ContentPacketExtension ext = new ContentPacketExtension();
+ String remoteContentName = remoteContent.getName();
+
+ ext.setSenders(newSenders);
+ ext.setCreator(remoteContent.getCreator());
+ ext.setName(remoteContentName);
+
+ if (newSenders != senders)
+ {
+ if (logger.isInfoEnabled())
+ logger.info("Sending content modify, senders: "
+ + senders + "->" + newSenders);
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
+ JingleIQ contentIQ
+ = JinglePacketFactory.createContentModify(
+ protocolProvider.getOurJID(),
+ this.peerJID,
+ getSID(),
+ ext);
+
+ protocolProvider.getConnection().sendPacket(contentIQ);
+ }
+
+ try
+ {
+ mediaHandler.reinitContent(remoteContentName, ext, false);
+ mediaHandler.start();
+ }
+ catch(Exception e)
+ {
+ logger.warn("Exception occurred during media reinitialization", e);
+ }
+
+ return (newSenders != senders);
+ }
+
+ /**
+ * Send a <tt>content</tt> message to reflect change in video setup (start
+ * or stop).
+ */
+ public void sendModifyVideoResolutionContent()
+ {
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+ ContentPacketExtension remoteContent
+ = mediaHandler.getRemoteContent(MediaType.VIDEO.toString());
+ ContentPacketExtension content;
+
+ logger.info("send modify-content to change resolution");
+
+ // send content-modify with RTP description
+
+ // create content list with resolution
+ try
+ {
+ content = mediaHandler.createContentForMedia(MediaType.VIDEO);
+ }
+ catch (Exception e)
+ {
+ logger.warn("Failed to gather content for video type", e);
+ return;
+ }
+
+ // if we are only receiving video senders is null
+ SendersEnum senders = remoteContent.getSenders();
+
+ if (senders != null)
+ content.setSenders(senders);
+
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
+ JingleIQ contentIQ
+ = JinglePacketFactory.createContentModify(
+ protocolProvider.getOurJID(),
+ this.peerJID,
+ getSID(),
+ content);
+
+ protocolProvider.getConnection().sendPacket(contentIQ);
+
+ try
+ {
+ mediaHandler.reinitContent(remoteContent.getName(), content, false);
+ mediaHandler.start();
+ }
+ catch(Exception e)
+ {
+ logger.warn("Exception occurred when media reinitialization", e);
+ }
+ }
+
+ /**
+ * Send a <tt>content-remove</tt> to remove video setup.
+ */
+ private void sendRemoveVideoContent()
+ {
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+
+ ContentPacketExtension content = new ContentPacketExtension();
+ ContentPacketExtension remoteContent
+ = mediaHandler.getRemoteContent(MediaType.VIDEO.toString());
+ if (remoteContent == null)
+ return;
+ String remoteContentName = remoteContent.getName();
+
+ content.setName(remoteContentName);
+ content.setCreator(remoteContent.getCreator());
+ content.setSenders(remoteContent.getSenders());
+
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
+ JingleIQ contentIQ
+ = JinglePacketFactory.createContentRemove(
+ protocolProvider.getOurJID(),
+ this.peerJID,
+ getSID(),
+ Arrays.asList(content));
+
+ protocolProvider.getConnection().sendPacket(contentIQ);
+ mediaHandler.removeContent(remoteContentName);
+ setSenders(MediaType.VIDEO, SendersEnum.none);
+ }
+
+ /**
+ * Sends local candidate addresses from the local peer to the remote peer
+ * using the <tt>transport-info</tt> {@link JingleIQ}.
+ *
+ * @param contents the local candidate addresses to be sent from the local
+ * peer to the remote peer using the <tt>transport-info</tt>
+ * {@link JingleIQ}
+ */
+ protected void sendTransportInfo(Iterable<ContentPacketExtension> contents)
+ {
+ // if the call is canceled, do not start sending candidates in
+ // transport-info
+ if(cancelled)
+ return;
+
+ JingleIQ transportInfo = new JingleIQ();
+
+ for (ContentPacketExtension content : contents)
+ transportInfo.addContent(content);
+
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
+
+ transportInfo.setAction(JingleAction.TRANSPORT_INFO);
+ transportInfo.setFrom(protocolProvider.getOurJID());
+ transportInfo.setSID(getSID());
+ transportInfo.setTo(getAddress());
+ transportInfo.setType(IQ.Type.SET);
+
+ PacketCollector collector
+ = protocolProvider.getConnection().createPacketCollector(
+ new PacketIDFilter(transportInfo.getPacketID()));
+
+ protocolProvider.getConnection().sendPacket(transportInfo);
+ collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ collector.cancel();
+ }
+
+ @Override
+ public void setState(CallPeerState newState, String reason, int reasonCode)
+ {
+ CallPeerState oldState = getState();
+ try
+ {
+ /*
+ * We need to dispose of the transport manager before the
+ * 'call' field is set to null, because if Jitsi Videobridge is in
+ * use, it (the call) is needed in order to expire the
+ * Videobridge channels.
+ */
+ if (CallPeerState.DISCONNECTED.equals(newState)
+ || CallPeerState.FAILED.equals(newState))
+ getMediaHandler().getTransportManager().close();
+ }
+ finally
+ {
+ super.setState(newState, reason, reasonCode);
+ }
+
+ if (CallPeerState.isOnHold(oldState)
+ && CallPeerState.CONNECTED.equals(newState))
+ {
+ try
+ {
+ getCall().modifyVideoContent();
+ }
+ catch (OperationFailedException ofe)
+ {
+ logger.error("Failed to update call video state after " +
+ "'hold' status removed for "+this);
+ }
+ }
+ }
+
+ /**
+ * Transfer (in the sense of call transfer) this <tt>CallPeer</tt> to a
+ * specific callee address which may optionally be participating in an
+ * active <tt>Call</tt>.
+ *
+ * @param to the address of the callee to transfer this <tt>CallPeer</tt> to
+ * @param sid the Jingle session ID of the active <tt>Call</tt> between the
+ * local peer and the callee in the case of attended transfer; <tt>null</tt>
+ * in the case of unattended transfer
+ * @throws OperationFailedException if something goes wrong
+ */
+ protected void transfer(String to, String sid)
+ throws OperationFailedException
+ {
+ JingleIQ transferSessionInfo = new JingleIQ();
+ ProtocolProviderServiceJabberImpl protocolProvider
+ = getProtocolProvider();
+
+ transferSessionInfo.setAction(JingleAction.SESSION_INFO);
+ transferSessionInfo.setFrom(protocolProvider.getOurJID());
+ transferSessionInfo.setSID(getSID());
+ transferSessionInfo.setTo(getAddress());
+ transferSessionInfo.setType(IQ.Type.SET);
+
+ TransferPacketExtension transfer = new TransferPacketExtension();
+
+ // Attended transfer.
+ if (sid != null)
+ {
+ /*
+ * Not really sure what the value of the "from" attribute of the
+ * "transfer" element should be but the examples in "XEP-0251:
+ * Jingle Session Transfer" has it in the case of attended transfer.
+ */
+ transfer.setFrom(protocolProvider.getOurJID());
+ transfer.setSID(sid);
+
+ // Puts on hold the 2 calls before making the attended transfer.
+ OperationSetBasicTelephonyJabberImpl basicTelephony
+ = (OperationSetBasicTelephonyJabberImpl)
+ protocolProvider.getOperationSet(
+ OperationSetBasicTelephony.class);
+ CallPeerJabberImpl callPeer = basicTelephony.getActiveCallPeer(sid);
+ if(callPeer != null)
+ {
+ if(!CallPeerState.isOnHold(callPeer.getState()))
+ {
+ callPeer.putOnHold(true);
+ }
+ }
+
+ if(!CallPeerState.isOnHold(this.getState()))
+ {
+ this.putOnHold(true);
+ }
+ }
+ transfer.setTo(to);
+
+ transferSessionInfo.addExtension(transfer);
+
+ Connection connection = protocolProvider.getConnection();
+ PacketCollector collector = connection.createPacketCollector(
+ new PacketIDFilter(transferSessionInfo.getPacketID()));
+ protocolProvider.getConnection().sendPacket(transferSessionInfo);
+
+ Packet result
+ = collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ if(result == null)
+ {
+ // Log the failed transfer call and notify the user.
+ throw new OperationFailedException(
+ "No response to the \"transfer\" request.",
+ OperationFailedException.ILLEGAL_ARGUMENT);
+ }
+ else if (((IQ) result).getType() != IQ.Type.RESULT)
+ {
+ // Log the failed transfer call and notify the user.
+ throw new OperationFailedException(
+ "Remote peer does not manage call \"transfer\"."
+ + "Response to the \"transfer\" request is: "
+ + ((IQ) result).getType(),
+ OperationFailedException.ILLEGAL_ARGUMENT);
+ }
+ else
+ {
+ String message = ((sid == null) ? "Unattended" : "Attended")
+ + " transfer to: "
+ + to;
+ // Implements the SIP behavior: once the transfer is accepted, the
+ // current call is closed.
+ hangup(
+ false,
+ message,
+ new ReasonPacketExtension(Reason.SUCCESS,
+ message,
+ new TransferredPacketExtension()));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getEntity()
+ {
+ return getAddress();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * In Jingle there isn't an actual "direction" parameter. We use the
+ * <tt>senders</tt> field to calculate the direction.
+ */
+ @Override
+ public MediaDirection getDirection(MediaType mediaType)
+ {
+ SendersEnum senders = getSenders(mediaType);
+
+ if (senders == SendersEnum.none)
+ {
+ return MediaDirection.INACTIVE;
+ }
+ else if (senders == null || senders == SendersEnum.both)
+ {
+ return MediaDirection.SENDRECV;
+ }
+ else if (senders == SendersEnum.initiator)
+ {
+ return
+ isInitiator()
+ ? MediaDirection.RECVONLY
+ : MediaDirection.SENDONLY;
+ }
+ else //senders == SendersEnum.responder
+ {
+ return
+ isInitiator()
+ ? MediaDirection.SENDONLY
+ : MediaDirection.RECVONLY;
+ }
+ }
+
+ /**
+ * Gets the current value of the <tt>senders</tt> field of the content with
+ * name <tt>mediaType</tt> in the Jingle session with this
+ * <tt>CallPeer</tt>.
+ *
+ * @param mediaType the <tt>MediaType</tt> for which to get the current
+ * value of the <tt>senders</tt> field.
+ * @return the current value of the <tt>senders</tt> field of the content
+ * with name <tt>mediaType</tt> in the Jingle session with this
+ * <tt>CallPeer</tt>.
+ */
+ public SendersEnum getSenders(MediaType mediaType)
+ {
+ switch (mediaType)
+ {
+ case AUDIO:
+ return audioSenders;
+ case VIDEO:
+ return videoSenders;
+ default:
+ return SendersEnum.none;
+ }
+ }
+
+ /**
+ * Set the current value of the <tt>senders</tt> field of the content with
+ * name <tt>mediaType</tt> in the Jingle session with this <tt>CallPeer</tt>
+ * @param mediaType the <tt>MediaType</tt> for which to get the current
+ * value of the <tt>senders</tt> field.
+ * @param senders the value to set
+ */
+ public void setSenders(MediaType mediaType, SendersEnum senders)
+ {
+ switch(mediaType)
+ {
+ case AUDIO:
+ this.audioSenders = senders;
+ break;
+ case VIDEO:
+ this.videoSenders = senders;
+ break;
+ default:
+ throw new IllegalArgumentException("mediaType");
+ }
+ }
+
+ /**
+ * Gets the <tt>MediaType</tt> of <tt>content</tt>. If <tt>content</tt>
+ * does not have a <tt>description</tt> child and therefore not
+ * <tt>MediaType</tt> can be associated with it, tries to take the
+ * <tt>MediaType</tt> from the session's already established contents with
+ * the same name as <tt>content</tt>
+ * @param content the <tt>ContentPacketExtention</tt> for which to get the
+ * <tt>MediaType</tt>
+ * @return the <tt>MediaType</tt> of <tt>content</tt>.
+ */
+ public MediaType getMediaType(ContentPacketExtension content)
+ {
+ String contentName = content.getName();
+ if (contentName == null)
+ return null;
+
+ MediaType mediaType = JingleUtils.getMediaType(content);
+ if (mediaType == null)
+ {
+ CallPeerMediaHandlerJabberImpl mediaHandler = getMediaHandler();
+ for (MediaType m : MediaType.values())
+ {
+ ContentPacketExtension sessionContent
+ = mediaHandler.getRemoteContent(m.toString());
+ if (sessionContent == null)
+ sessionContent = mediaHandler.getLocalContent(m.toString());
+
+ if (sessionContent != null
+ && contentName.equals(sessionContent.getName()))
+ {
+ mediaType = m;
+ break;
+ }
+ }
+ }
+
+ return mediaType;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
index 2c8845d..979d696 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
@@ -937,19 +937,18 @@ public class CallPeerMediaHandlerJabberImpl
if (supportedTransports != null
&& supportedTransports.length > 0)
{
- for (int i = 0; i < supportedTransports.length; i++)
+ for(String supportedTransport : supportedTransports)
{
if (ProtocolProviderServiceJabberImpl.
URN_XMPP_JINGLE_ICE_UDP_1.
- equals(supportedTransports[i]))
+ equals(supportedTransport))
{
- transportManager
- = new IceUdpTransportManager(peer);
+ transportManager = new IceUdpTransportManager(peer);
break;
}
else if (ProtocolProviderServiceJabberImpl.
- URN_XMPP_JINGLE_RAW_UDP_0.
- equals(supportedTransports[i]))
+ URN_XMPP_JINGLE_RAW_UDP_0.
+ equals(supportedTransport))
{
transportManager
= new RawUdpTransportManager(peer);
@@ -1117,12 +1116,11 @@ public class CallPeerMediaHandlerJabberImpl
List<Component> visualComponents
= new LinkedList<Component>();
- for (int i = 0; i < remoteSSRCs.length; i++)
+ for(int remoteSSRC : remoteSSRCs)
{
- int remoteSSRC = remoteSSRCs[i];
Component visualComponent
- = videoStream.getVisualComponent(
- 0xFFFFFFFFL & remoteSSRC);
+ = videoStream.getVisualComponent(
+ 0xFFFFFFFFL & remoteSSRC);
if (visualComponent != null)
visualComponents.add(visualComponent);
@@ -1605,7 +1603,7 @@ public class CallPeerMediaHandlerJabberImpl
{
List<MediaFormat> fmts = supportedFormats;
- if(fmts.size() > 0)
+ if(!fmts.isEmpty())
{
MediaFormat fmt = fmts.get(0);
@@ -2108,21 +2106,17 @@ public class CallPeerMediaHandlerJabberImpl
* TODO The transportManager is going to be changed so it may need to be
* disposed of prior to the change.
*/
-
- if (xmlns.equals(
- ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_ICE_UDP_1))
+ switch (xmlns)
{
- transportManager = new IceUdpTransportManager(peer);
- }
- else if (xmlns.equals(
- ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0))
- {
- transportManager = new RawUdpTransportManager(peer);
- }
- else
- {
- throw new IllegalArgumentException(
- "Unsupported Jingle transport " + xmlns);
+ case ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_ICE_UDP_1:
+ transportManager = new IceUdpTransportManager(peer);
+ break;
+ case ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0:
+ transportManager = new RawUdpTransportManager(peer);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported Jingle " +
+ "transport " + xmlns);
}
synchronized(transportManagerSyncRoot)
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java
index 8a6f3ed..6c4c358 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ChatRoomJabberImpl.java
@@ -609,7 +609,7 @@ public class ChatRoomJabberImpl
this.provider.getConnection().addPacketListener(
presenceListener,
new AndFilter(
- new FromMatchesFilter(multiUserChat.getRoom()),
+ FromMatchesFilter.create(multiUserChat.getRoom()),
new PacketTypeFilter(
org.jivesoftware.smack.packet.Presence.class)));
if(password == null)
@@ -868,7 +868,7 @@ public class ChatRoomJabberImpl
clearCachedConferenceDescriptionList();
- XMPPConnection connection = this.provider.getConnection();
+ Connection connection = this.provider.getConnection();
try
{
// if we are already disconnected
@@ -1896,6 +1896,23 @@ public class ChatRoomJabberImpl
}
/**
+ * Removes given <tt>PacketExtension</tt> from the MUC presence and
+ * publishes it immediately.
+ * @param extension the <tt>PacketExtension</tt> to be removed from the MUC
+ * presence.
+ */
+ public void removePresenceExtension(PacketExtension extension)
+ {
+ if (lastPresenceSent != null)
+ {
+ setPacketExtension(
+ lastPresenceSent, null, extension.getNamespace());
+
+ provider.getConnection().sendPacket(lastPresenceSent);
+ }
+ }
+
+ /**
* Returns the ids of the users that has the member role in the room.
* When the room is member only, this are the users allowed to join.
* @return the ids of the users that has the member role in the room.
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java
index 1f4e3d8..c3c852c 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java
@@ -58,11 +58,21 @@ public class IceUdpTransportManager
= Logger.getLogger(IceUdpTransportManager.class);
/**
+ * Default STUN server address.
+ */
+ protected static final String DEFAULT_STUN_SERVER_ADDRESS = "stun.jitsi.net";
+
+ /**
+ * Default STUN server port.
+ */
+ protected static final int DEFAULT_STUN_SERVER_PORT = 3478;
+
+ /**
* The ICE <tt>Component</tt> IDs in their common order used, for example,
* by <tt>DefaultStreamConnector</tt>, <tt>MediaStreamTarget</tt>.
*/
private static final int[] COMPONENT_IDS
- = new int[] { Component.RTP, Component.RTCP };
+ = new int[] { Component.RTP, Component.RTCP };
/**
* This is where we keep our answer between the time we get the offer and
@@ -76,15 +86,6 @@ public class IceUdpTransportManager
*/
protected final Agent iceAgent;
- /**
- * Default STUN server address.
- */
- protected static final String DEFAULT_STUN_SERVER_ADDRESS = "stun.jitsi.net";
-
- /**
- * Default STUN server port.
- */
- protected static final int DEFAULT_STUN_SERVER_PORT = 3478;
/**
* Creates a new instance of this transport manager, binding it to the
@@ -156,7 +157,10 @@ public class IceUdpTransportManager
// in case user has canceled the login window
if(credentials == null)
+ {
+ logger.info("Credentials were null. User has most likely canceled the login operation");
return null;
+ }
//extract the password the user passed us.
char[] pass = credentials.getPassword();
@@ -164,7 +168,10 @@ public class IceUdpTransportManager
// the user didn't provide us a password (i.e. canceled the
// operation)
if(pass == null)
+ {
+ logger.info("Password was null. User has most likely canceled the login operation");
return null;
+ }
password = new String(pass);
if (credentials.isPasswordPersistent())
@@ -390,28 +397,29 @@ public class IceUdpTransportManager
for (int i = 0; i < COMPONENT_IDS.length; i++)
{
Component component = stream.getComponent(COMPONENT_IDS[i]);
-
- if (component != null)
+ if (component == null)
{
- CandidatePair selectedPair = component.getSelectedPair();
-
- if (selectedPair != null)
- {
- DatagramSocket streamConnectorSocket
- = selectedPair.getLocalCandidate().
- getDatagramSocket();
+ continue;
+ }
- if (streamConnectorSocket != null)
- {
- streamConnectorSockets[i] = streamConnectorSocket;
- streamConnectorSocketCount++;
- }
- }
+ DatagramSocket streamConnectorSocket = component.getSocket();
+ if (streamConnectorSocket != null)
+ {
+ streamConnectorSockets[i] = streamConnectorSocket;
+ streamConnectorSocketCount++;
+ logger.trace("Added a streamConnectorSocket to the array " +
+ "StreamConnectorSocket and increased " +
+ "the count of streamConnectorSocketCount by one to " +
+ streamConnectorSocketCount);
}
}
+
if (streamConnectorSocketCount > 0)
+ {
return streamConnectorSockets;
+ }
}
+
return null;
}
@@ -742,20 +750,25 @@ public class IceUdpTransportManager
ex);
}
- //let's now update the next port var as best we can: we would assume
- //that all local candidates are bound on the same port and set it
- //to the one just above. if the assumption is wrong the next bind
- //would simply include one more bind retry.
+ // Attempt to minimize subsequent bind retries: see if we have allocated
+ // any ports from the dynamic range, and if so update the port tracker.
+ // Do NOT update the port tracker with non-dynamic ports (e.g. 4443
+ // coming from TCP) because this will force it to revert back it its
+ // configured min port. When maxPort is reached, allocation will begin
+ // from minPort again, so we don't have to worry about wraps.
try
{
- portTracker.setNextPort(
- 1
- + stream
- .getComponent(Component.RTCP)
- .getLocalCandidates()
- .get(0)
- .getTransportAddress()
- .getPort());
+ int maxAllocatedPort = getMaxAllocatedPort(
+ stream,
+ portTracker.getMinPort(),
+ portTracker.getMaxPort());
+
+ if(maxAllocatedPort > 0)
+ {
+ int nextPort = 1 + maxAllocatedPort;
+ portTracker.setNextPort(nextPort);
+ logger.debug("Updating the port tracker min port: " + nextPort);
+ }
}
catch(Throwable t)
{
@@ -768,6 +781,48 @@ public class IceUdpTransportManager
}
/**
+ * @return the highest local port used by any of the local candidates of
+ * {@code iceStream}, which falls in the range [{@code min}, {@code max}].
+ */
+ private int getMaxAllocatedPort(IceMediaStream iceStream, int min, int max)
+ {
+ return
+ Math.max(
+ getMaxAllocatedPort(
+ iceStream.getComponent(Component.RTP),
+ min, max),
+ getMaxAllocatedPort(
+ iceStream.getComponent(Component.RTCP),
+ min, max));
+ }
+
+ /**
+ * @return the highest local port used by any of the local candidates of
+ * {@code component}, which falls in the range [{@code min}, {@code max}].
+ */
+ private int getMaxAllocatedPort(Component component, int min, int max)
+ {
+ int maxAllocatedPort = -1;
+
+ if (component != null)
+ {
+ for (LocalCandidate candidate : component.getLocalCandidates())
+ {
+ int candidatePort = candidate.getTransportAddress().getPort();
+
+ if (min <= candidatePort
+ && candidatePort <= max
+ && maxAllocatedPort < candidatePort)
+ {
+ maxAllocatedPort = candidatePort;
+ }
+ }
+ }
+
+ return maxAllocatedPort;
+ }
+
+ /**
* Simply returns the list of local candidates that we gathered during the
* harvest.
*
@@ -898,8 +953,12 @@ public class IceUdpTransportManager
= transport.getChildExtensionsOfType(
CandidatePacketExtension.class);
- if (iceAgentStateIsRunning && (candidates.size() == 0))
+ if (iceAgentStateIsRunning && candidates.isEmpty())
+ {
+ logger.info("connectivity establishment has not been started " +
+ "because candidate list is empty");
return false;
+ }
String media = e.getKey();
IceMediaStream stream = iceAgent.getStream(media);
@@ -938,6 +997,12 @@ public class IceUdpTransportManager
if (candidate.getGeneration() != generation)
continue;
+ if (candidate.getIP() == null || "".equals(candidate.getIP()))
+ {
+ logger.warn("Skipped ICE candidate with empty IP");
+ continue;
+ }
+
Component component
= stream.getComponent(candidate.getComponent());
String relAddr;
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java b/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
index a0387df..c3137ad 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
@@ -151,7 +151,7 @@ public class InfoRetreiver
List<GenericDetail> result = new LinkedList<GenericDetail>();
try
{
- XMPPConnection connection = jabberProvider.getConnection();
+ Connection connection = jabberProvider.getConnection();
if(connection == null || !connection.isAuthenticated())
return null;
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/JabberLoginStrategy.java b/src/net/java/sip/communicator/impl/protocol/jabber/JabberLoginStrategy.java
index 438ea1b..de7578c 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/JabberLoginStrategy.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/JabberLoginStrategy.java
@@ -61,7 +61,7 @@ public interface JabberLoginStrategy
* @param resource the XMPP resource
* @return true to continue connecting, false to abort
*/
- public boolean login(XMPPConnection connection, String userName,
+ public boolean login(Connection connection, String userName,
String resource)
throws XMPPException;
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesCandidate.java b/src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesCandidate.java
index 0ea9a54..f2473dd 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesCandidate.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesCandidate.java
@@ -87,7 +87,7 @@ public class JingleNodesCandidate
* @return the <tt>RelayedCandidateDatagramSocket</tt> of this
* <tt>RelayedCandidate</tt>
*/
- public synchronized JingleNodesCandidateDatagramSocket
+ private synchronized JingleNodesCandidateDatagramSocket
getRelayedCandidateDatagramSocket()
{
if (jingleNodesCandidateDatagramSocket == null)
@@ -113,7 +113,7 @@ public class JingleNodesCandidate
* <tt>Candidate</tt>
*/
@Override
- public IceSocketWrapper getIceSocketWrapper()
+ protected IceSocketWrapper getCandidateIceSocketWrapper()
{
if (socket == null)
{
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesHarvester.java b/src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesHarvester.java
index bb7d31b..d29be03 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesHarvester.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/JingleNodesHarvester.java
@@ -36,7 +36,7 @@ import org.xmpp.jnodes.smack.*;
* @author Sebastien Vincent
*/
public class JingleNodesHarvester
- extends CandidateHarvester
+ extends AbstractCandidateHarvester
{
/**
* The <tt>Logger</tt> used by the <tt>JingleNodesHarvester</tt> class and
@@ -125,7 +125,7 @@ public class JingleNodesHarvester
}
}
- if (ciq != null && ciq.getRemoteport() > 0)
+ if (ciq != null)
{
ip = ciq.getHost();
port = ciq.getRemoteport();
@@ -136,6 +136,22 @@ public class JingleNodesHarvester
" local port: " + ciq.getLocalport());
}
+ if (ip == null || ciq.getRemoteport() == 0)
+ {
+ logger.warn("JN relay ignored because ip was null or port 0");
+ return candidates;
+ }
+
+ // Drop the scope or interface name if the relay sends it
+ // along in its IPv6 address. The scope/ifname is only valid on the
+ // host that owns the IP and we don't need it here.
+ int scopeIndex = ip.indexOf('%');
+ if (scopeIndex > 0)
+ {
+ logger.warn("Dropping scope from assumed IPv6 address " + ip);
+ ip = ip.substring(0, scopeIndex);
+ }
+
/* RTP */
TransportAddress relayedAddress = new TransportAddress(ip, port,
Transport.UDP);
@@ -160,6 +176,7 @@ public class JingleNodesHarvester
candidates.add(local);
}
}
+
return candidates;
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/LoginByClientCertificateStrategy.java b/src/net/java/sip/communicator/impl/protocol/jabber/LoginByClientCertificateStrategy.java
index 09c9462..4825e01 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/LoginByClientCertificateStrategy.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/LoginByClientCertificateStrategy.java
@@ -116,7 +116,7 @@ class LoginByClientCertificateStrategy
* accepted.
* @throws XMPPException
*/
- public boolean login(XMPPConnection connection, String userName,
+ public boolean login(Connection connection, String userName,
String resource)
throws XMPPException
{
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java b/src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java
index 43fc8a4..7034221 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java
@@ -115,7 +115,7 @@ public class LoginByPasswordStrategy
* @return always true.
* @throws XMPPException
*/
- public boolean login(XMPPConnection connection, String userName,
+ public boolean login(Connection connection, String userName,
String resource)
throws XMPPException
{
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/MobileIndicator.java b/src/net/java/sip/communicator/impl/protocol/jabber/MobileIndicator.java
index 926848c..8c801c6 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/MobileIndicator.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/MobileIndicator.java
@@ -222,11 +222,13 @@ public class MobileIndicator
/**
* Caps for user has been changed.
* @param user the user (full JID)
+ * @param fullJids a list of all resources of the user (full JIDs)
* @param node the entity caps node#ver
* @param online indicates if the user for which we're notified is online
*/
@Override
- public void userCapsNodeAdded(String user, String node, boolean online)
+ public void userCapsNodeAdded(String user, ArrayList<String> fullJids,
+ String node, boolean online)
{
updateMobileIndicatorUsingCaps(user);
}
@@ -234,11 +236,13 @@ public class MobileIndicator
/**
* Caps for user has been changed.
* @param user the user (full JID)
+ * @param fullJids a list of all resources of the user (full JIDs)
* @param node the entity caps node#ver
* @param online indicates if the user for which we're notified is online
*/
@Override
- public void userCapsNodeRemoved(String user, String node, boolean online)
+ public void userCapsNodeRemoved(String user, ArrayList<String> fullJids,
+ String node, boolean online)
{
updateMobileIndicatorUsingCaps(user);
}
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 42a3916..2f35fef 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java
@@ -815,6 +815,17 @@ public class OperationSetBasicInstantMessagingJabberImpl
ForwardedPacketExtension.class);
if(extensions.isEmpty())
return;
+
+ // according to xep-0280 all carbons should come from
+ // our bare jid
+ if (!msg.getFrom().equals(
+ StringUtils.parseBareAddress(
+ jabberProvider.getOurJID())))
+ {
+ logger.info("Received a carbon copy with wrong from!");
+ return;
+ }
+
ForwardedPacketExtension forwardedExt = extensions.get(0);
msg = forwardedExt.getMessage();
if(msg == null || msg.getBody() == null)
@@ -1109,7 +1120,7 @@ public class OperationSetBasicInstantMessagingJabberImpl
NewMailNotificationIQ.NAMESPACE,
new NewMailNotificationProvider());
- XMPPConnection connection = jabberProvider.getConnection();
+ Connection connection = jabberProvider.getConnection();
connection.addPacketListener(
new MailboxIQListener(), new PacketTypeFilter(MailboxIQ.class));
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java
index cc36936..78027c0 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java
@@ -280,7 +280,10 @@ public class OperationSetBasicTelephonyJabberImpl
Iterable<PacketExtension> sessionInitiateExtensions)
throws OperationFailedException
{
- return createOutgoingCall(call, calleeAddress, null, null);
+ if (calleeAddress.contains("/"))
+ return createOutgoingCall(call, calleeAddress, calleeAddress, null);
+ else
+ return createOutgoingCall(call, calleeAddress, null, null);
}
/**
@@ -774,7 +777,7 @@ public class OperationSetBasicTelephonyJabberImpl
*/
private void unsubscribeForJinglePackets()
{
- XMPPConnection connection = protocolProvider.getConnection();
+ Connection connection = protocolProvider.getConnection();
if(connection != null)
connection.removePacketListener(this);
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java
index 0a6edfe..59cc17c 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java
@@ -26,7 +26,7 @@ import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.packet.*;
-import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smack.util.*;
/**
* Represents an <tt>OperationSet</tt> to query the <tt>OperationSet</tt>s
@@ -52,6 +52,19 @@ public class OperationSetContactCapabilitiesJabberImpl
= Logger.getLogger(OperationSetContactCapabilitiesJabberImpl.class);
/**
+ * The name of the property used to control whether to use
+ * all resources to show capabilities
+ */
+ public static final String PROP_XMPP_USE_ALL_RESOURCES_FOR_CAPABILITIES =
+ "net.java.sip.communicator.XMPP_USE_ALL_RESOURCES_FOR_CAPABILITIES";
+
+ /**
+ * The default value for the capabilities setting
+ */
+ public static final boolean USE_ALL_RESOURCES_FOR_CAPABILITIES_DEFAULT =
+ true;
+
+ /**
* The list of <tt>OperationSet</tt> capabilities presumed to be supported
* by a <tt>Contact</tt> when it is offline.
*/
@@ -276,6 +289,42 @@ public class OperationSetContactCapabilitiesJabberImpl
}
/**
+ * Gets the largest set of <tt>OperationSet</tt>s supported from a
+ * list of full JIDs. The returned <tt>OperationSet</tt>s are considered
+ * by the associated protocol provider to capabilities possessed by the
+ * specified <tt>contact</tt>.
+ *
+ * @param fullJids a list of full JIDs in which to find the resource with
+ * the most capabilities.
+ * @return the <tt>Map</tt> listing the most <tt>OperationSet</tt>s
+ * considered by the associated protocol provider to be supported by the
+ * specified <tt>contact</tt> (i.e. to be possessed as capabilities).
+ * Each supported <tt>OperationSet</tt> capability is represented by a
+ * <tt>Map.Entry</tt> with key equal to the <tt>OperationSet</tt> class
+ * name and value equal to the respective <tt>OperationSet</tt> instance
+ */
+ protected Map<String, OperationSet> getLargestSupportedOperationSet(
+ ArrayList<String> fullJids)
+ {
+ Map<String, OperationSet> supportedOperationSets =
+ new HashMap<String, OperationSet>();
+ if (fullJids!=null)
+ {
+ for (String fullJid : fullJids)
+ {
+ Map<String, OperationSet> newSupportedOperationSets=
+ getSupportedOperationSets(fullJid, true);
+ if (newSupportedOperationSets.size()>
+ supportedOperationSets.size())
+ {
+ supportedOperationSets = newSupportedOperationSets;
+ }
+ }
+ }
+ return supportedOperationSets;
+ }
+
+ /**
* Gets the <tt>OperationSet</tt> corresponding to the specified
* <tt>Class</tt> and supported by the specified <tt>Contact</tt>. If the
* returned value is non-<tt>null</tt>, it indicates that the
@@ -387,17 +436,19 @@ public class OperationSetContactCapabilitiesJabberImpl
* record for a specific user about the caps node the user has.
*
* @param user the user (full JID)
+ * @param fullJids a list of all resources of the user (full JIDs)
* @param node the entity caps node#ver
* @param online indicates if the user is currently online
* @see UserCapsNodeListener#userCapsNodeAdded(String, String, boolean)
*/
- public void userCapsNodeAdded(String user, String node, boolean online)
+ public void userCapsNodeAdded(String user, ArrayList<String> fullJids,
+ String node, boolean online)
{
/*
* It doesn't matter to us whether a caps node has been added or removed
* for the specified user because we report all changes.
*/
- userCapsNodeRemoved(user, node, online);
+ userCapsNodeChanged(user, fullJids, node, online);
}
/**
@@ -405,45 +456,86 @@ public class OperationSetContactCapabilitiesJabberImpl
* record for a specific user about the caps node the user has.
*
* @param user the user (full JID)
+ * @param fullJids a list of all resources of the user (full JIDs)
+ * @param node the entity caps node#ver
+ * @param online indicates if the user is currently online
+ * @see UserCapsNodeListener#userCapsNodeAdded(String, String, boolean)
+ */
+ public void userCapsNodeRemoved(String user, ArrayList<String> fullJids,
+ String node, boolean online)
+ {
+ /*
+ * It doesn't matter to us whether a caps node has been added or removed
+ * for the specified user because we report all changes.
+ */
+ userCapsNodeChanged(user, fullJids, node, online);
+ }
+
+ /**
+ * Notifies this listener that an <tt>EntityCapsManager</tt> has changed a
+ * record for a specific user about the caps node the user has.
+ *
+ * @param user the user (full JID)
+ * @param fullJids a list of all resources of the user (full JIDs)
* @param node the entity caps node#ver
* @param online indicates if the given user is online
- * @see UserCapsNodeListener#userCapsNodeRemoved(String, String, boolean)
*/
- public void userCapsNodeRemoved(String user, String node, boolean online)
+ public void userCapsNodeChanged(String user, ArrayList<String> fullJids,
+ String node, boolean online)
{
OperationSetPresence opsetPresence
- = parentProvider.getOperationSet(OperationSetPresence.class);
-
- if (opsetPresence != null)
- {
- String jid = StringUtils.parseBareAddress(user);
- Contact contact = opsetPresence.findContactByID(jid);
-
- // If the contact isn't null and is online we try to discover the
- // new set of operation sets and to notify interested parties.
- // Otherwise we ignore the event.
- if (contact != null)
+ = parentProvider.getOperationSet(OperationSetPresence.class);
+ if (opsetPresence != null) {
+ if(JabberActivator.getConfigurationService()
+ .getBoolean(
+ PROP_XMPP_USE_ALL_RESOURCES_FOR_CAPABILITIES,
+ USE_ALL_RESOURCES_FOR_CAPABILITIES_DEFAULT)
+ && !fullJids.isEmpty())
{
- if(online)
+ String bareJid = StringUtils.parseBareAddress(user);
+ Contact contact = opsetPresence.findContactByID(bareJid);
+ if (contact != null)
{
- // when going online we have received a presence
- // and make sure we discover this particular jid
- // for getSupportedOperationSets
fireContactCapabilitiesEvent(
contact,
- ContactCapabilitiesEvent.SUPPORTED_OPERATION_SETS_CHANGED,
- getSupportedOperationSets(user,
- online));
+ ContactCapabilitiesEvent.
+ SUPPORTED_OPERATION_SETS_CHANGED,
+ getLargestSupportedOperationSet(fullJids));
}
- else
+ }
+ else
+ {
+ String jid = StringUtils.parseBareAddress(user);
+ Contact contact = opsetPresence.findContactByID(jid);
+
+ // If the contact isn't null and is online we try to discover
+ // the new set of operation sets and to notify interested
+ // parties. Otherwise we ignore the event.
+ if (contact != null)
{
- // when offline, we use the contact, and selecting
- // the most connected jid
- // for getSupportedOperationSets
- fireContactCapabilitiesEvent(
- contact,
- ContactCapabilitiesEvent.SUPPORTED_OPERATION_SETS_CHANGED,
- getSupportedOperationSets(contact));
+ if(online)
+ {
+ // when going online we have received a presence
+ // and make sure we discover this particular jid
+ // for getSupportedOperationSets
+ fireContactCapabilitiesEvent(
+ contact,
+ ContactCapabilitiesEvent.
+ SUPPORTED_OPERATION_SETS_CHANGED,
+ getSupportedOperationSets(user,
+ online));
+ }
+ else
+ {
+ // when offline, we use the contact, and selecting
+ // the most connected jid
+ // for getSupportedOperationSets
+ fireContactCapabilitiesEvent(
+ contact,
+ ContactCapabilitiesEvent.
+ SUPPORTED_OPERATION_SETS_CHANGED,
+ getSupportedOperationSets(contact));
+ }
}
}
}
@@ -460,7 +552,8 @@ public class OperationSetContactCapabilitiesJabberImpl
{
// If the user goes offline we ensure to remove the caps node.
if (capsManager != null
- && evt.getNewStatus().getStatus() < PresenceStatus.ONLINE_THRESHOLD)
+ && evt.getNewStatus().getStatus() < PresenceStatus.ONLINE_THRESHOLD
+ && !evt.isResourceChanged())
{
capsManager.removeContactCapsNode(evt.getSourceContact());
}
@@ -469,31 +562,59 @@ public class OperationSetContactCapabilitiesJabberImpl
/**
* Fires event that contact capabilities has changed.
* @param user the user to search for its contact.
+ * @param fullJids a list of all resources of the user (full JIDs)
*/
- public void fireContactCapabilitiesChanged(String user)
+ public void fireContactCapabilitiesChanged(String user,
+ ArrayList<String> fullJids)
{
- OperationSetPresence opsetPresence
+ if(!JabberActivator.getConfigurationService()
+ .getBoolean(
+ PROP_XMPP_USE_ALL_RESOURCES_FOR_CAPABILITIES,
+ USE_ALL_RESOURCES_FOR_CAPABILITIES_DEFAULT)
+ || fullJids.isEmpty())
+ {
+ OperationSetPresence opsetPresence
= parentProvider.getOperationSet(OperationSetPresence.class);
- if (opsetPresence != null)
+ if (opsetPresence != null)
+ {
+ String userID = StringUtils.parseBareAddress(user);
+ Contact contact = opsetPresence.findContactByID(userID);
+
+ // this called by received discovery info for particular jid
+ // so we use its online and opsets for this particular jid
+ boolean online = false;
+ Presence presence = parentProvider.getConnection().getRoster()
+ .getPresence(user);
+ if(presence != null)
+ online = presence.isAvailable();
+
+ if(contact != null)
+ {
+ fireContactCapabilitiesEvent(
+ contact,
+ ContactCapabilitiesEvent.
+ SUPPORTED_OPERATION_SETS_CHANGED,
+ getSupportedOperationSets(user, online));
+ }
+ }
+ }
+ else
{
- String userID = StringUtils.parseBareAddress(user);
- Contact contact = opsetPresence.findContactByID(userID);
-
- // this called by received discovery info for particular jid
- // so we use its online and opsets for this particular jid
- boolean online = false;
- Presence presence = parentProvider.getConnection().getRoster()
- .getPresence(user);
- if(presence != null)
- online = presence.isAvailable();
-
- if(contact != null)
+ OperationSetPresence opsetPresence
+ = parentProvider.getOperationSet(OperationSetPresence.class);
+ if (opsetPresence != null)
{
- fireContactCapabilitiesEvent(
- contact,
- ContactCapabilitiesEvent.SUPPORTED_OPERATION_SETS_CHANGED,
- getSupportedOperationSets(user, online));
+ String bareJid = StringUtils.parseBareAddress(user);
+ Contact contact = opsetPresence.findContactByID(bareJid);
+ if(contact != null)
+ {
+ fireContactCapabilitiesEvent(
+ contact,
+ ContactCapabilitiesEvent.
+ SUPPORTED_OPERATION_SETS_CHANGED,
+ getLargestSupportedOperationSet(fullJids));
+ }
}
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetJitsiMeetToolsJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetJitsiMeetToolsJabberImpl.java
index 0fb6979..7ea4453 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetJitsiMeetToolsJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetJitsiMeetToolsJabberImpl.java
@@ -72,6 +72,16 @@ public class OperationSetJitsiMeetToolsJabberImpl
* {@inheritDoc}
*/
@Override
+ public void removePresenceExtension(ChatRoom chatRoom,
+ PacketExtension extension)
+ {
+ ((ChatRoomJabberImpl)chatRoom).removePresenceExtension(extension);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public void setPresenceStatus(ChatRoom chatRoom, String statusMessage)
{
((ChatRoomJabberImpl)chatRoom).publishPresenceStatus(statusMessage);
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java
index 80bbb4e..cf53906 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetMultiUserChatJabberImpl.java
@@ -471,10 +471,10 @@ public class OperationSetMultiUserChatJabberImpl
* Almost all <tt>MultiUserChat</tt> methods require an xmpp connection
* param so I added this method only for the sake of utility.
*
- * @return the XMPPConnection currently in use by the jabber provider or
+ * @return the XMPP connection currently in use by the jabber provider or
* null if jabber provider has yet to be initialized.
*/
- private XMPPConnection getXmppConnection()
+ private Connection getXmppConnection()
{
return (jabberProvider == null)
? null
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java
index 69c168c..c502824 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java
@@ -691,7 +691,7 @@ public class OperationSetPersistentPresenceJabberImpl
*/
assertConnected();
- XMPPConnection xmppConnection = parentProvider.getConnection();
+ Connection xmppConnection = parentProvider.getConnection();
if (xmppConnection == null)
{
@@ -1124,7 +1124,7 @@ public class OperationSetPersistentPresenceJabberImpl
ssContactList.cleanup();
- XMPPConnection connection = parentProvider.getConnection();
+ Connection connection = parentProvider.getConnection();
if(connection != null)
{
connection.removePacketListener(subscribtionPacketListener);
@@ -1528,6 +1528,19 @@ public class OperationSetPersistentPresenceJabberImpl
o2, parentProvider).getStatus()
- jabberStatusToPresenceStatus(
o1, parentProvider).getStatus();
+ // We have run out of "logical" ways to order
+ // the presences inside the TreeSet. We have
+ // make sure we are consinstent with equals.
+ // We do this by comparing the unique resource
+ // names. If this evaluates to 0 again, then we
+ // can safely assume this presence object
+ // represents the same resource and by that the
+ // same client.
+ if(res == 0)
+ {
+ res = o1.getFrom().compareTo(
+ o2.getFrom());
+ }
}
return res;
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java
index e81b43a..e5b83e7 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTelephonyConferencingJabberImpl.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,585 +15,585 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.jabber;
-
-import java.util.*;
-
-import net.java.sip.communicator.impl.protocol.jabber.extensions.coin.*;
-import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.service.protocol.media.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.util.xml.*;
-import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.filter.*;
-import org.jivesoftware.smack.packet.*;
-import org.jivesoftware.smack.packet.IQ.Type;
-import org.jivesoftware.smack.util.*;
-import org.jivesoftware.smackx.packet.*;
-
-/**
- * Implements <tt>OperationSetTelephonyConferencing</tt> for Jabber.
- *
- * @author Lyubomir Marinov
- * @author Sebastien Vincent
- * @author Boris Grozev
- * @author Pawel Domas
- */
-public class OperationSetTelephonyConferencingJabberImpl
- extends AbstractOperationSetTelephonyConferencing<
- ProtocolProviderServiceJabberImpl,
- OperationSetBasicTelephonyJabberImpl,
- CallJabberImpl,
- CallPeerJabberImpl,
- String>
- implements RegistrationStateChangeListener,
- PacketListener,
- PacketFilter
-
-{
- /**
- * The <tt>Logger</tt> used by the
- * <tt>OperationSetTelephonyConferencingJabberImpl</tt> class and its
- * instances for logging output.
- */
- private static final Logger logger
- = Logger.getLogger(OperationSetTelephonyConferencingJabberImpl.class);
-
- /**
- * The minimum interval in milliseconds between COINs sent to a single
- * <tt>CallPeer</tt>.
- */
- private static final int COIN_MIN_INTERVAL = 200;
-
- /**
- * Property used to disable COIN notifications.
- */
- public static final String DISABLE_COIN_PROP_NAME
- = "net.java.sip.communicator.impl.protocol.jabber.DISABLE_COIN";
-
- /**
- * Synchronization object.
- */
- private final Object lock = new Object();
-
- /**
- * Field indicates whether COIN notification are disabled or not.
- */
- private boolean isCoinDisabled = false;
-
- /**
- * Initializes a new <tt>OperationSetTelephonyConferencingJabberImpl</tt>
- * instance which is to provide telephony conferencing services for the
- * specified Jabber <tt>ProtocolProviderService</tt> implementation.
- *
- * @param parentProvider the Jabber <tt>ProtocolProviderService</tt>
- * implementation which has requested the creation of the new instance and
- * for which the new instance is to provide telephony conferencing services
- */
- public OperationSetTelephonyConferencingJabberImpl(
- ProtocolProviderServiceJabberImpl parentProvider)
- {
- super(parentProvider);
-
- this.isCoinDisabled
- = JabberActivator.getConfigurationService()
- .getBoolean(DISABLE_COIN_PROP_NAME, false);
- }
-
- /**
- * Notifies all <tt>CallPeer</tt>s associated with a specific <tt>Call</tt>
- * about changes in the telephony conference-related information. In
- * contrast, {@link #notifyAll()} notifies all <tt>CallPeer</tt>s associated
- * with the telephony conference in which a specific <tt>Call</tt> is
- * participating.
- *
- * @param call the <tt>Call</tt> whose <tt>CallPeer</tt>s are to be notified
- * about changes in the telephony conference-related information
- */
- @Override
- protected void notifyCallPeers(Call call)
- {
- if (!isCoinDisabled && call.isConferenceFocus())
- {
- synchronized (lock)
- {
- // send conference-info to all CallPeers of the specified call.
- for (Iterator<? extends CallPeer> i = call.getCallPeers();
- i.hasNext();)
- {
- notify(i.next());
- }
- }
- }
- }
-
- /**
- * Notifies a specific <tt>CallPeer</tt> about changes in the telephony
- * conference-related information.
- *
- * @param callPeer the <tt>CallPeer</tt> to notify.
- */
- private void notify(CallPeer callPeer)
- {
- if(!(callPeer instanceof CallPeerJabberImpl))
- return;
-
- //Don't send COINs to peers with might not be ready to accept COINs yet
- CallPeerState peerState = callPeer.getState();
- if (peerState == CallPeerState.CONNECTING
- || peerState == CallPeerState.UNKNOWN
- || peerState == CallPeerState.INITIATING_CALL
- || peerState == CallPeerState.DISCONNECTED
- || peerState == CallPeerState.FAILED)
- return;
-
- final CallPeerJabberImpl callPeerJabber = (CallPeerJabberImpl)callPeer;
-
- final long timeSinceLastCoin = System.currentTimeMillis()
- - callPeerJabber.getLastConferenceInfoSentTimestamp();
- if (timeSinceLastCoin < COIN_MIN_INTERVAL)
- {
- if (callPeerJabber.isConfInfoScheduled())
- return;
-
- logger.info("Scheduling to send a COIN to " + callPeerJabber);
- callPeerJabber.setConfInfoScheduled(true);
- new Thread(new Runnable(){
- @Override
- public void run()
- {
- try
- {
- Thread.sleep(1 + COIN_MIN_INTERVAL - timeSinceLastCoin);
- }
- catch (InterruptedException ie) {}
-
- OperationSetTelephonyConferencingJabberImpl.this
- .notify(callPeerJabber);
- }
- }).start();
-
- return;
- }
-
- // check that callPeer supports COIN before sending him a
- // conference-info
- String to = getBasicTelephony().getFullCalleeURI(callPeer.getAddress());
-
- // XXX if this generates actual disco#info requests we might want to
- // cache it.
- try
- {
- DiscoverInfo discoverInfo
- = parentProvider.getDiscoveryManager().discoverInfo(to);
-
- if (!discoverInfo.containsFeature(
- ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_COIN))
- {
- logger.info(callPeer.getAddress() + " does not support COIN");
- callPeerJabber.setConfInfoScheduled(false);
- return;
- }
- }
- catch (XMPPException xmppe)
- {
- logger.warn("Failed to retrieve DiscoverInfo for " + to, xmppe);
- }
-
- ConferenceInfoDocument currentConfInfo
- = getCurrentConferenceInfo(callPeerJabber);
- ConferenceInfoDocument lastSentConfInfo
- = callPeerJabber.getLastConferenceInfoSent();
-
- ConferenceInfoDocument diff;
-
- if (lastSentConfInfo == null)
- diff = currentConfInfo;
- else
- diff = getConferenceInfoDiff(lastSentConfInfo, currentConfInfo);
-
- if (diff != null)
- {
- int newVersion
- = lastSentConfInfo == null
- ? 1
- : lastSentConfInfo.getVersion() + 1;
- diff.setVersion(newVersion);
-
- IQ iq = getConferenceInfo(callPeerJabber, diff);
-
- if (iq != null)
- {
- parentProvider.getConnection().sendPacket(iq);
-
- // We save currentConfInfo, because it is of state "full", while
- // diff could be a partial
- currentConfInfo.setVersion(newVersion);
- callPeerJabber.setLastConferenceInfoSent(currentConfInfo);
- callPeerJabber.setLastConferenceInfoSentTimestamp(
- System.currentTimeMillis());
- }
- }
- callPeerJabber.setConfInfoScheduled(false);
- }
-
- /**
- * Generates the conference-info IQ to be sent to a specific
- * <tt>CallPeer</tt> in order to notify it of the current state of the
- * conference managed by the local peer.
- *
- * @param callPeer the <tt>CallPeer</tt> to generate conference-info XML for
- * @param confInfo the <tt>ConferenceInformationDocument</tt> which is to be
- * included in the IQ
- * @return the conference-info IQ to be sent to the specified
- * <tt>callPeer</tt> in order to notify it of the current state of the
- * conference managed by the local peer
- */
- private IQ getConferenceInfo(CallPeerJabberImpl callPeer,
- final ConferenceInfoDocument confInfo)
- {
- String callPeerSID = callPeer.getSID();
-
- if (callPeerSID == null)
- return null;
-
- IQ iq = new IQ(){
- @Override
- public String getChildElementXML()
- {
- return confInfo.toXml();
- }
- };
-
- CallJabberImpl call = callPeer.getCall();
-
- iq.setFrom(call.getProtocolProvider().getOurJID());
- iq.setTo(callPeer.getAddress());
- iq.setType(Type.SET);
-
- return iq;
- }
-
- /**
- * Implementation of method <tt>registrationStateChange</tt> from
- * interface RegistrationStateChangeListener for setting up (or down)
- * our <tt>JingleManager</tt> when an <tt>XMPPConnection</tt> is available
- *
- * @param evt the event received
- */
- @Override
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
- super.registrationStateChanged(evt);
-
- RegistrationState registrationState = evt.getNewState();
-
- if (RegistrationState.REGISTERED.equals(registrationState))
- {
- if(logger.isDebugEnabled())
- logger.debug("Subscribes to Coin packets");
- subscribeForCoinPackets();
- }
- else if (RegistrationState.UNREGISTERED.equals(registrationState))
- {
- if(logger.isDebugEnabled())
- logger.debug("Unsubscribes to Coin packets");
- unsubscribeForCoinPackets();
- }
- }
-
- /**
- * Creates a new outgoing <tt>Call</tt> into which conference callees are to
- * be invited by this <tt>OperationSetTelephonyConferencing</tt>.
- *
- * @return a new outgoing <tt>Call</tt> into which conference callees are to
- * be invited by this <tt>OperationSetTelephonyConferencing</tt>
- * @throws OperationFailedException if anything goes wrong
- */
- @Override
- protected CallJabberImpl createOutgoingCall()
- throws OperationFailedException
- {
- return new CallJabberImpl(getBasicTelephony());
- }
-
- /**
- * {@inheritDoc}
- *
- * Implements the protocol-dependent part of the logic of inviting a callee
- * to a <tt>Call</tt>. The protocol-independent part of that logic is
- * implemented by
- * {@link AbstractOperationSetTelephonyConferencing#inviteCalleeToCall(String,Call)}.
- */
- @Override
- protected CallPeer doInviteCalleeToCall(
- String calleeAddress,
- CallJabberImpl call)
- throws OperationFailedException
- {
- return
- getBasicTelephony().createOutgoingCall(
- call,
- calleeAddress,
- Arrays.asList(
- new PacketExtension[]
- {
- new CoinPacketExtension(true)
- }));
- }
-
- /**
- * Parses a <tt>String</tt> value which represents a callee address
- * specified by the user into an object which is to actually represent the
- * callee during the invitation to a conference <tt>Call</tt>.
- *
- * @param calleeAddressString a <tt>String</tt> value which represents a
- * callee address to be parsed into an object which is to actually represent
- * the callee during the invitation to a conference <tt>Call</tt>
- * @return an object which is to actually represent the specified
- * <tt>calleeAddressString</tt> during the invitation to a conference
- * <tt>Call</tt>
- * @throws OperationFailedException if parsing the specified
- * <tt>calleeAddressString</tt> fails
- */
- @Override
- protected String parseAddressString(String calleeAddressString)
- throws OperationFailedException
- {
- return getBasicTelephony().getFullCalleeURI(calleeAddressString);
- }
-
- /**
- * Subscribes us to notifications about incoming Coin packets.
- */
- private void subscribeForCoinPackets()
- {
- parentProvider.getConnection().addPacketListener(this, this);
- }
-
- /**
- * Unsubscribes us from notifications about incoming Coin packets.
- */
- private void unsubscribeForCoinPackets()
- {
- XMPPConnection connection = parentProvider.getConnection();
-
- if (connection != null)
- connection.removePacketListener(this);
- }
-
- /**
- * Tests whether or not the specified packet should be handled by this
- * operation set. This method is called by smack prior to packet delivery
- * and it would only accept <tt>CoinIQ</tt>s.
- *
- * @param packet the packet to test.
- * @return true if and only if <tt>packet</tt> passes the filter.
- */
- public boolean accept(Packet packet)
- {
- return (packet instanceof CoinIQ);
- }
-
- /**
- * Handles incoming jingle packets and passes them to the corresponding
- * method based on their action.
- *
- * @param packet the packet to process.
- */
- public void processPacket(Packet packet)
- {
- CoinIQ coinIQ = (CoinIQ) packet;
- String errorMessage = null;
-
- //first ack all "set" requests.
- IQ.Type type = coinIQ.getType();
- if (type == IQ.Type.SET)
- {
- IQ ack = IQ.createResultIQ(coinIQ);
-
- parentProvider.getConnection().sendPacket(ack);
- }
- else if(type == IQ.Type.ERROR)
- {
- XMPPError error = coinIQ.getError();
- if(error != null)
- {
- String msg = error.getMessage();
- errorMessage = ((msg != null)? (msg + " ") : "")
- + "Error code: " + error.getCode();
- }
-
- logger.error("Received error in COIN packet. "+errorMessage);
- }
-
- String sid = coinIQ.getSID();
-
- if (sid != null)
- {
- CallPeerJabberImpl callPeer
- = getBasicTelephony().getActiveCallsRepository().findCallPeer(
- sid);
-
-
- if (callPeer != null)
- {
- if(type == IQ.Type.ERROR)
- {
- callPeer.fireConferenceMemberErrorEvent(errorMessage);
- return;
- }
-
- if (logger.isDebugEnabled())
- logger.debug("Processing COIN from " + coinIQ.getFrom()
- + " (version=" + coinIQ.getVersion() + ")");
-
- handleCoin(callPeer, coinIQ);
- }
- }
- }
-
- /**
- * Handles a specific <tt>CoinIQ</tt> sent from a specific
- * <tt>CallPeer</tt>.
- *
- * @param callPeer the <tt>CallPeer</tt> from which the specified
- * <tt>CoinIQ</tt> was sent
- * @param coinIQ the <tt>CoinIQ</tt> which was sent from the specified
- * <tt>callPeer</tt>
- */
- private void handleCoin(CallPeerJabberImpl callPeer, CoinIQ coinIQ)
- {
- try
- {
- setConferenceInfoXML(callPeer, coinIQ.getChildElementXML());
- }
- catch (XMLException e)
- {
- logger.error("Could not handle received COIN from " + callPeer
- + ": " + coinIQ);
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * For COINs (XEP-0298), we use the attributes of the
- * <tt>conference-info</tt> element to piggyback a Jingle SID. This is
- * temporary and should be removed once we choose a better way to pass the
- * SID.
- */
- @Override
- protected ConferenceInfoDocument getCurrentConferenceInfo(
- MediaAwareCallPeer<?,?,?> callPeer)
- {
- ConferenceInfoDocument confInfo
- = super.getCurrentConferenceInfo(callPeer);
-
- if (callPeer instanceof CallPeerJabberImpl
- && confInfo != null)
- {
- confInfo.setSid(((CallPeerJabberImpl)callPeer).getSID());
- }
- return confInfo;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected String getLocalEntity(CallPeer callPeer)
- {
- JingleIQ sessionIQ = ((CallPeerJabberImpl)callPeer).getSessionIQ();
- String from = sessionIQ.getFrom();
- String chatRoomName = StringUtils.parseBareAddress(from);
- OperationSetMultiUserChatJabberImpl opSetMUC
- = (OperationSetMultiUserChatJabberImpl)
- parentProvider.getOperationSet(OperationSetMultiUserChat.class);
- ChatRoom room = null;
- if(opSetMUC != null)
- room = opSetMUC.getChatRoom(chatRoomName);
-
- if(room != null)
- return "xmpp:" + chatRoomName + "/" + room.getUserNickname();
-
- return "xmpp:" + parentProvider.getOurJID();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected String getLocalDisplayName()
- {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * The URI of the returned <tt>ConferenceDescription</tt> is the occupant
- * JID with which we have joined the room.
- *
- * If a Videobridge is available for our <tt>ProtocolProviderService</tt>
- * we use it. TODO: this should be relaxed when we refactor the Videobridge
- * implementation, so that any Videobridge (on any protocol provider) can
- * be used.
- */
- @Override
- public ConferenceDescription setupConference(final ChatRoom chatRoom)
- {
- OperationSetVideoBridge videoBridge
- = parentProvider.getOperationSet(OperationSetVideoBridge.class);
- boolean isVideobridge = (videoBridge != null) && videoBridge.isActive();
-
- CallJabberImpl call = new CallJabberImpl(getBasicTelephony());
- call.setAutoAnswer(true);
-
- String uri = "xmpp:" + chatRoom.getIdentifier() +
- "/" + chatRoom.getUserNickname();
-
- ConferenceDescription cd
- = new ConferenceDescription(uri, call.getCallID());
-
- call.addCallChangeListener(new CallChangeListener()
- {
- @Override
- public void callStateChanged(CallChangeEvent ev)
- {
- if(CallState.CALL_ENDED.equals(ev.getNewValue()))
- chatRoom.publishConference(null, null);
- }
-
- @Override
- public void callPeerRemoved(CallPeerEvent ev)
- {
- }
-
- @Override
- public void callPeerAdded(CallPeerEvent ev)
- {
- }
- });
- if (isVideobridge)
- {
- call.setConference(new MediaAwareCallConference(true));
-
- //For Jitsi Videobridge we set the transports to RAW-UDP, otherwise
- //we leave them empty (meaning both RAW-UDP and ICE could be used)
- cd.addTransport(
- ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0);
- }
-
- if (logger.isInfoEnabled())
- {
- logger.info("Setup a conference with uri=" + uri + " and callid=" +
- call.getCallID() + ". Videobridge in use: " + isVideobridge);
- }
-
- return cd;
- }
-}
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import java.util.*;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.coin.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.protocol.media.*;
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.util.xml.*;
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.packet.IQ.Type;
+import org.jivesoftware.smack.util.*;
+import org.jivesoftware.smackx.packet.*;
+
+/**
+ * Implements <tt>OperationSetTelephonyConferencing</tt> for Jabber.
+ *
+ * @author Lyubomir Marinov
+ * @author Sebastien Vincent
+ * @author Boris Grozev
+ * @author Pawel Domas
+ */
+public class OperationSetTelephonyConferencingJabberImpl
+ extends AbstractOperationSetTelephonyConferencing<
+ ProtocolProviderServiceJabberImpl,
+ OperationSetBasicTelephonyJabberImpl,
+ CallJabberImpl,
+ CallPeerJabberImpl,
+ String>
+ implements RegistrationStateChangeListener,
+ PacketListener,
+ PacketFilter
+
+{
+ /**
+ * The <tt>Logger</tt> used by the
+ * <tt>OperationSetTelephonyConferencingJabberImpl</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(OperationSetTelephonyConferencingJabberImpl.class);
+
+ /**
+ * The minimum interval in milliseconds between COINs sent to a single
+ * <tt>CallPeer</tt>.
+ */
+ private static final int COIN_MIN_INTERVAL = 200;
+
+ /**
+ * Property used to disable COIN notifications.
+ */
+ public static final String DISABLE_COIN_PROP_NAME
+ = "net.java.sip.communicator.impl.protocol.jabber.DISABLE_COIN";
+
+ /**
+ * Synchronization object.
+ */
+ private final Object lock = new Object();
+
+ /**
+ * Field indicates whether COIN notification are disabled or not.
+ */
+ private boolean isCoinDisabled = false;
+
+ /**
+ * Initializes a new <tt>OperationSetTelephonyConferencingJabberImpl</tt>
+ * instance which is to provide telephony conferencing services for the
+ * specified Jabber <tt>ProtocolProviderService</tt> implementation.
+ *
+ * @param parentProvider the Jabber <tt>ProtocolProviderService</tt>
+ * implementation which has requested the creation of the new instance and
+ * for which the new instance is to provide telephony conferencing services
+ */
+ public OperationSetTelephonyConferencingJabberImpl(
+ ProtocolProviderServiceJabberImpl parentProvider)
+ {
+ super(parentProvider);
+
+ this.isCoinDisabled
+ = JabberActivator.getConfigurationService()
+ .getBoolean(DISABLE_COIN_PROP_NAME, false);
+ }
+
+ /**
+ * Notifies all <tt>CallPeer</tt>s associated with a specific <tt>Call</tt>
+ * about changes in the telephony conference-related information. In
+ * contrast, {@link #notifyAll()} notifies all <tt>CallPeer</tt>s associated
+ * with the telephony conference in which a specific <tt>Call</tt> is
+ * participating.
+ *
+ * @param call the <tt>Call</tt> whose <tt>CallPeer</tt>s are to be notified
+ * about changes in the telephony conference-related information
+ */
+ @Override
+ protected void notifyCallPeers(Call call)
+ {
+ if (!isCoinDisabled && call.isConferenceFocus())
+ {
+ synchronized (lock)
+ {
+ // send conference-info to all CallPeers of the specified call.
+ for (Iterator<? extends CallPeer> i = call.getCallPeers();
+ i.hasNext();)
+ {
+ notify(i.next());
+ }
+ }
+ }
+ }
+
+ /**
+ * Notifies a specific <tt>CallPeer</tt> about changes in the telephony
+ * conference-related information.
+ *
+ * @param callPeer the <tt>CallPeer</tt> to notify.
+ */
+ private void notify(CallPeer callPeer)
+ {
+ if(!(callPeer instanceof CallPeerJabberImpl))
+ return;
+
+ //Don't send COINs to peers with might not be ready to accept COINs yet
+ CallPeerState peerState = callPeer.getState();
+ if (peerState == CallPeerState.CONNECTING
+ || peerState == CallPeerState.UNKNOWN
+ || peerState == CallPeerState.INITIATING_CALL
+ || peerState == CallPeerState.DISCONNECTED
+ || peerState == CallPeerState.FAILED)
+ return;
+
+ final CallPeerJabberImpl callPeerJabber = (CallPeerJabberImpl)callPeer;
+
+ final long timeSinceLastCoin = System.currentTimeMillis()
+ - callPeerJabber.getLastConferenceInfoSentTimestamp();
+ if (timeSinceLastCoin < COIN_MIN_INTERVAL)
+ {
+ if (callPeerJabber.isConfInfoScheduled())
+ return;
+
+ logger.info("Scheduling to send a COIN to " + callPeerJabber);
+ callPeerJabber.setConfInfoScheduled(true);
+ new Thread(new Runnable(){
+ @Override
+ public void run()
+ {
+ try
+ {
+ Thread.sleep(1 + COIN_MIN_INTERVAL - timeSinceLastCoin);
+ }
+ catch (InterruptedException ie) {}
+
+ OperationSetTelephonyConferencingJabberImpl.this
+ .notify(callPeerJabber);
+ }
+ }).start();
+
+ return;
+ }
+
+ // check that callPeer supports COIN before sending him a
+ // conference-info
+ String to = getBasicTelephony().getFullCalleeURI(callPeer.getAddress());
+
+ // XXX if this generates actual disco#info requests we might want to
+ // cache it.
+ try
+ {
+ DiscoverInfo discoverInfo
+ = parentProvider.getDiscoveryManager().discoverInfo(to);
+
+ if (!discoverInfo.containsFeature(
+ ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_COIN))
+ {
+ logger.info(callPeer.getAddress() + " does not support COIN");
+ callPeerJabber.setConfInfoScheduled(false);
+ return;
+ }
+ }
+ catch (XMPPException xmppe)
+ {
+ logger.warn("Failed to retrieve DiscoverInfo for " + to, xmppe);
+ }
+
+ ConferenceInfoDocument currentConfInfo
+ = getCurrentConferenceInfo(callPeerJabber);
+ ConferenceInfoDocument lastSentConfInfo
+ = callPeerJabber.getLastConferenceInfoSent();
+
+ ConferenceInfoDocument diff;
+
+ if (lastSentConfInfo == null)
+ diff = currentConfInfo;
+ else
+ diff = getConferenceInfoDiff(lastSentConfInfo, currentConfInfo);
+
+ if (diff != null)
+ {
+ int newVersion
+ = lastSentConfInfo == null
+ ? 1
+ : lastSentConfInfo.getVersion() + 1;
+ diff.setVersion(newVersion);
+
+ IQ iq = getConferenceInfo(callPeerJabber, diff);
+
+ if (iq != null)
+ {
+ parentProvider.getConnection().sendPacket(iq);
+
+ // We save currentConfInfo, because it is of state "full", while
+ // diff could be a partial
+ currentConfInfo.setVersion(newVersion);
+ callPeerJabber.setLastConferenceInfoSent(currentConfInfo);
+ callPeerJabber.setLastConferenceInfoSentTimestamp(
+ System.currentTimeMillis());
+ }
+ }
+ callPeerJabber.setConfInfoScheduled(false);
+ }
+
+ /**
+ * Generates the conference-info IQ to be sent to a specific
+ * <tt>CallPeer</tt> in order to notify it of the current state of the
+ * conference managed by the local peer.
+ *
+ * @param callPeer the <tt>CallPeer</tt> to generate conference-info XML for
+ * @param confInfo the <tt>ConferenceInformationDocument</tt> which is to be
+ * included in the IQ
+ * @return the conference-info IQ to be sent to the specified
+ * <tt>callPeer</tt> in order to notify it of the current state of the
+ * conference managed by the local peer
+ */
+ private IQ getConferenceInfo(CallPeerJabberImpl callPeer,
+ final ConferenceInfoDocument confInfo)
+ {
+ String callPeerSID = callPeer.getSID();
+
+ if (callPeerSID == null)
+ return null;
+
+ IQ iq = new IQ(){
+ @Override
+ public String getChildElementXML()
+ {
+ return confInfo.toXml();
+ }
+ };
+
+ CallJabberImpl call = callPeer.getCall();
+
+ iq.setFrom(call.getProtocolProvider().getOurJID());
+ iq.setTo(callPeer.getAddress());
+ iq.setType(Type.SET);
+
+ return iq;
+ }
+
+ /**
+ * Implementation of method <tt>registrationStateChange</tt> from
+ * interface RegistrationStateChangeListener for setting up (or down)
+ * our <tt>JingleManager</tt> when an <tt>XMPPConnection</tt> is available
+ *
+ * @param evt the event received
+ */
+ @Override
+ public void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+ super.registrationStateChanged(evt);
+
+ RegistrationState registrationState = evt.getNewState();
+
+ if (RegistrationState.REGISTERED.equals(registrationState))
+ {
+ if(logger.isDebugEnabled())
+ logger.debug("Subscribes to Coin packets");
+ subscribeForCoinPackets();
+ }
+ else if (RegistrationState.UNREGISTERED.equals(registrationState))
+ {
+ if(logger.isDebugEnabled())
+ logger.debug("Unsubscribes to Coin packets");
+ unsubscribeForCoinPackets();
+ }
+ }
+
+ /**
+ * Creates a new outgoing <tt>Call</tt> into which conference callees are to
+ * be invited by this <tt>OperationSetTelephonyConferencing</tt>.
+ *
+ * @return a new outgoing <tt>Call</tt> into which conference callees are to
+ * be invited by this <tt>OperationSetTelephonyConferencing</tt>
+ * @throws OperationFailedException if anything goes wrong
+ */
+ @Override
+ protected CallJabberImpl createOutgoingCall()
+ throws OperationFailedException
+ {
+ return new CallJabberImpl(getBasicTelephony());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Implements the protocol-dependent part of the logic of inviting a callee
+ * to a <tt>Call</tt>. The protocol-independent part of that logic is
+ * implemented by
+ * {@link AbstractOperationSetTelephonyConferencing#inviteCalleeToCall(String,Call)}.
+ */
+ @Override
+ protected CallPeer doInviteCalleeToCall(
+ String calleeAddress,
+ CallJabberImpl call)
+ throws OperationFailedException
+ {
+ return
+ getBasicTelephony().createOutgoingCall(
+ call,
+ calleeAddress,
+ Arrays.asList(
+ new PacketExtension[]
+ {
+ new CoinPacketExtension(true)
+ }));
+ }
+
+ /**
+ * Parses a <tt>String</tt> value which represents a callee address
+ * specified by the user into an object which is to actually represent the
+ * callee during the invitation to a conference <tt>Call</tt>.
+ *
+ * @param calleeAddressString a <tt>String</tt> value which represents a
+ * callee address to be parsed into an object which is to actually represent
+ * the callee during the invitation to a conference <tt>Call</tt>
+ * @return an object which is to actually represent the specified
+ * <tt>calleeAddressString</tt> during the invitation to a conference
+ * <tt>Call</tt>
+ * @throws OperationFailedException if parsing the specified
+ * <tt>calleeAddressString</tt> fails
+ */
+ @Override
+ protected String parseAddressString(String calleeAddressString)
+ throws OperationFailedException
+ {
+ return getBasicTelephony().getFullCalleeURI(calleeAddressString);
+ }
+
+ /**
+ * Subscribes us to notifications about incoming Coin packets.
+ */
+ private void subscribeForCoinPackets()
+ {
+ parentProvider.getConnection().addPacketListener(this, this);
+ }
+
+ /**
+ * Unsubscribes us from notifications about incoming Coin packets.
+ */
+ private void unsubscribeForCoinPackets()
+ {
+ Connection connection = parentProvider.getConnection();
+
+ if (connection != null)
+ connection.removePacketListener(this);
+ }
+
+ /**
+ * Tests whether or not the specified packet should be handled by this
+ * operation set. This method is called by smack prior to packet delivery
+ * and it would only accept <tt>CoinIQ</tt>s.
+ *
+ * @param packet the packet to test.
+ * @return true if and only if <tt>packet</tt> passes the filter.
+ */
+ public boolean accept(Packet packet)
+ {
+ return (packet instanceof CoinIQ);
+ }
+
+ /**
+ * Handles incoming jingle packets and passes them to the corresponding
+ * method based on their action.
+ *
+ * @param packet the packet to process.
+ */
+ public void processPacket(Packet packet)
+ {
+ CoinIQ coinIQ = (CoinIQ) packet;
+ String errorMessage = null;
+
+ //first ack all "set" requests.
+ IQ.Type type = coinIQ.getType();
+ if (type == IQ.Type.SET)
+ {
+ IQ ack = IQ.createResultIQ(coinIQ);
+
+ parentProvider.getConnection().sendPacket(ack);
+ }
+ else if(type == IQ.Type.ERROR)
+ {
+ XMPPError error = coinIQ.getError();
+ if(error != null)
+ {
+ String msg = error.getMessage();
+ errorMessage = ((msg != null)? (msg + " ") : "")
+ + "Error code: " + error.getCode();
+ }
+
+ logger.error("Received error in COIN packet. "+errorMessage);
+ }
+
+ String sid = coinIQ.getSID();
+
+ if (sid != null)
+ {
+ CallPeerJabberImpl callPeer
+ = getBasicTelephony().getActiveCallsRepository().findCallPeer(
+ sid);
+
+
+ if (callPeer != null)
+ {
+ if(type == IQ.Type.ERROR)
+ {
+ callPeer.fireConferenceMemberErrorEvent(errorMessage);
+ return;
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Processing COIN from " + coinIQ.getFrom()
+ + " (version=" + coinIQ.getVersion() + ")");
+
+ handleCoin(callPeer, coinIQ);
+ }
+ }
+ }
+
+ /**
+ * Handles a specific <tt>CoinIQ</tt> sent from a specific
+ * <tt>CallPeer</tt>.
+ *
+ * @param callPeer the <tt>CallPeer</tt> from which the specified
+ * <tt>CoinIQ</tt> was sent
+ * @param coinIQ the <tt>CoinIQ</tt> which was sent from the specified
+ * <tt>callPeer</tt>
+ */
+ private void handleCoin(CallPeerJabberImpl callPeer, CoinIQ coinIQ)
+ {
+ try
+ {
+ setConferenceInfoXML(callPeer, coinIQ.getChildElementXML());
+ }
+ catch (XMLException e)
+ {
+ logger.error("Could not handle received COIN from " + callPeer
+ + ": " + coinIQ);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * For COINs (XEP-0298), we use the attributes of the
+ * <tt>conference-info</tt> element to piggyback a Jingle SID. This is
+ * temporary and should be removed once we choose a better way to pass the
+ * SID.
+ */
+ @Override
+ protected ConferenceInfoDocument getCurrentConferenceInfo(
+ MediaAwareCallPeer<?,?,?> callPeer)
+ {
+ ConferenceInfoDocument confInfo
+ = super.getCurrentConferenceInfo(callPeer);
+
+ if (callPeer instanceof CallPeerJabberImpl
+ && confInfo != null)
+ {
+ confInfo.setSid(((CallPeerJabberImpl)callPeer).getSID());
+ }
+ return confInfo;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getLocalEntity(CallPeer callPeer)
+ {
+ JingleIQ sessionIQ = ((CallPeerJabberImpl)callPeer).getSessionIQ();
+ String from = sessionIQ.getFrom();
+ String chatRoomName = StringUtils.parseBareAddress(from);
+ OperationSetMultiUserChatJabberImpl opSetMUC
+ = (OperationSetMultiUserChatJabberImpl)
+ parentProvider.getOperationSet(OperationSetMultiUserChat.class);
+ ChatRoom room = null;
+ if(opSetMUC != null)
+ room = opSetMUC.getChatRoom(chatRoomName);
+
+ if(room != null)
+ return "xmpp:" + chatRoomName + "/" + room.getUserNickname();
+
+ return "xmpp:" + parentProvider.getOurJID();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getLocalDisplayName()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The URI of the returned <tt>ConferenceDescription</tt> is the occupant
+ * JID with which we have joined the room.
+ *
+ * If a Videobridge is available for our <tt>ProtocolProviderService</tt>
+ * we use it. TODO: this should be relaxed when we refactor the Videobridge
+ * implementation, so that any Videobridge (on any protocol provider) can
+ * be used.
+ */
+ @Override
+ public ConferenceDescription setupConference(final ChatRoom chatRoom)
+ {
+ OperationSetVideoBridge videoBridge
+ = parentProvider.getOperationSet(OperationSetVideoBridge.class);
+ boolean isVideobridge = (videoBridge != null) && videoBridge.isActive();
+
+ CallJabberImpl call = new CallJabberImpl(getBasicTelephony());
+ call.setAutoAnswer(true);
+
+ String uri = "xmpp:" + chatRoom.getIdentifier() +
+ "/" + chatRoom.getUserNickname();
+
+ ConferenceDescription cd
+ = new ConferenceDescription(uri, call.getCallID());
+
+ call.addCallChangeListener(new CallChangeListener()
+ {
+ @Override
+ public void callStateChanged(CallChangeEvent ev)
+ {
+ if(CallState.CALL_ENDED.equals(ev.getNewValue()))
+ chatRoom.publishConference(null, null);
+ }
+
+ @Override
+ public void callPeerRemoved(CallPeerEvent ev)
+ {
+ }
+
+ @Override
+ public void callPeerAdded(CallPeerEvent ev)
+ {
+ }
+ });
+ if (isVideobridge)
+ {
+ call.setConference(new MediaAwareCallConference(true));
+
+ //For Jitsi Videobridge we set the transports to RAW-UDP, otherwise
+ //we leave them empty (meaning both RAW-UDP and ICE could be used)
+ cd.addTransport(
+ ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0);
+ }
+
+ if (logger.isInfoEnabled())
+ {
+ logger.info("Setup a conference with uri=" + uri + " and callid=" +
+ call.getCallID() + ". Videobridge in use: " + isVideobridge);
+ }
+
+ return cd;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java
index b7e13ea..5d3dd8b 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetVideoBridgeImpl.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,282 +15,282 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.jabber;
-
-import java.util.*;
-
-import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.service.protocol.media.*;
-import net.java.sip.communicator.util.*;
-
-import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.filter.*;
-import org.jivesoftware.smack.packet.*;
-
-/**
- * Implements <tt>OperationSetVideoBridge</tt> for Jabber.
- *
- * @author Yana Stamcheva
- * @author Lyubomir Marinov
- */
-public class OperationSetVideoBridgeImpl
- implements OperationSetVideoBridge,
- PacketFilter,
- PacketListener,
- RegistrationStateChangeListener
-{
- /**
- * The <tt>Logger</tt> used by the <tt>OperationSetVideoBridgeImpl</tt>
- * class and its instances for logging output.
- */
- private static final Logger logger
- = Logger.getLogger(OperationSetVideoBridgeImpl.class);
-
- /**
- * The <tt>ProtocolProviderService</tt> implementation which initialized
- * this instance, owns it and is often referred to as its parent.
- */
- private final ProtocolProviderServiceJabberImpl protocolProvider;
-
- /**
- * Creates an instance of <tt>OperationSetVideoBridgeImpl</tt> by
- * specifying the parent <tt>ProtocolProviderService</tt> announcing this
- * operation set.
- *
- * @param protocolProvider the parent Jabber protocol provider
- */
- public OperationSetVideoBridgeImpl(
- ProtocolProviderServiceJabberImpl protocolProvider)
- {
- this.protocolProvider = protocolProvider;
- this.protocolProvider.addRegistrationStateChangeListener(this);
- }
-
- /**
- * Implements {@link PacketFilter}. Determines whether this instance is
- * interested in a specific {@link Packet}.
- * <tt>OperationSetVideoBridgeImpl</tt> returns <tt>true</tt> if the
- * specified <tt>packet</tt> is a {@link ColibriConferenceIQ}; otherwise,
- * <tt>false</tt>.
- *
- * @param packet the <tt>Packet</tt> to be determined whether this instance
- * is interested in it
- * @return <tt>true</tt> if the specified <tt>packet</tt> is a
- * <tt>ColibriConferenceIQ</tt>; otherwise, <tt>false</tt>
- */
- public boolean accept(Packet packet)
- {
- return (packet instanceof ColibriConferenceIQ);
- }
-
- /**
- * Creates a conference call with the specified callees as call peers via a
- * video bridge provided by the parent Jabber provider.
- *
- * @param callees the list of addresses that we should call
- * @return the newly created conference call containing all CallPeers
- * @throws OperationFailedException if establishing the conference call
- * fails
- * @throws OperationNotSupportedException if the provider does not have any
- * conferencing features.
- */
- public Call createConfCall(String[] callees)
- throws OperationFailedException,
- OperationNotSupportedException
- {
- return
- protocolProvider
- .getOperationSet(OperationSetTelephonyConferencing.class)
- .createConfCall(
- callees,
- new MediaAwareCallConference(true));
- }
-
- /**
- * Invites the callee represented by the specified uri to an already
- * existing call using a video bridge provided by the parent Jabber provider.
- * The difference between this method and createConfCall is that
- * inviteCalleeToCall allows a user to add new peers to an already
- * established conference.
- *
- * @param uri the callee to invite to an existing conf call.
- * @param call the call that we should invite the callee to.
- * @return the CallPeer object corresponding to the callee represented by
- * the specified uri.
- * @throws OperationFailedException if inviting the specified callee to the
- * specified call fails
- * @throws OperationNotSupportedException if allowing additional callees to
- * a pre-established call is not supported.
- */
- public CallPeer inviteCalleeToCall(String uri, Call call)
- throws OperationFailedException,
- OperationNotSupportedException
- {
- return
- protocolProvider
- .getOperationSet(OperationSetTelephonyConferencing.class)
- .inviteCalleeToCall(uri, call);
- }
-
- /**
- * Indicates if there's an active video bridge available at this moment. The
- * Jabber provider may announce support for video bridge, but it should not
- * be used for calling until it becomes actually active.
- *
- * @return <tt>true</tt> to indicate that there's currently an active
- * available video bridge, <tt>false</tt> - otherwise
- */
- public boolean isActive()
- {
- String jitsiVideobridge = protocolProvider.getJitsiVideobridge();
-
- return ((jitsiVideobridge != null) && (jitsiVideobridge.length() > 0));
- }
-
- /**
- * Notifies this instance that a specific <tt>ColibriConferenceIQ</tt> has
- * been received.
- *
- * @param conferenceIQ the <tt>ColibriConferenceIQ</tt> which has been
- * received
- */
- private void processColibriConferenceIQ(ColibriConferenceIQ conferenceIQ)
- {
- /*
- * The application is not a Jitsi Videobridge server, it is a client.
- * Consequently, the specified ColibriConferenceIQ is sent to it in
- * relation to the part of the application's functionality which makes
- * requests to a Jitsi Videobridge server i.e. CallJabberImpl.
- *
- * Additionally, the method processColibriConferenceIQ is presently tasked
- * with processing ColibriConferenceIQ requests only. They are SET IQs
- * sent by the Jitsi Videobridge server to notify the application about
- * updates in the states of (colibri) conferences organized by the
- * application.
- */
- if (IQ.Type.SET.equals(conferenceIQ.getType())
- && conferenceIQ.getID() != null)
- {
- OperationSetBasicTelephony<?> basicTelephony
- = protocolProvider.getOperationSet(
- OperationSetBasicTelephony.class);
-
- if (basicTelephony != null)
- {
- Iterator<? extends Call> i = basicTelephony.getActiveCalls();
-
- while (i.hasNext())
- {
- Call call = i.next();
-
- if (call instanceof CallJabberImpl)
- {
- CallJabberImpl callJabberImpl = (CallJabberImpl) call;
- MediaAwareCallConference conference
- = callJabberImpl.getConference();
-
- if ((conference != null)
- && conference.isJitsiVideobridge())
- {
- /*
- * TODO We may want to disallow rogue CallJabberImpl
- * instances which may throw an exception to prevent
- * the conferenceIQ from reaching the CallJabberImpl
- * instance which it was meant for.
- */
- if (callJabberImpl.processColibriConferenceIQ(
- conferenceIQ))
- break;
- }
- }
- }
- }
- }
- }
-
- /**
- * Implements {@link PacketListener}. Notifies this instance that a specific
- * {@link Packet} (which this instance has already expressed interest into
- * by returning <tt>true</tt> from {@link #accept(Packet)}) has been
- * received.
- *
- * @param packet the <tt>Packet</tt> which has been received and which this
- * instance is given a chance to process
- */
- public void processPacket(Packet packet)
- {
- /*
- * As we do elsewhere, acknowledge the receipt of the Packet first and
- * then go about our business with it.
- */
- IQ iq = (IQ) packet;
-
- if (iq.getType() == IQ.Type.SET)
- protocolProvider.getConnection().sendPacket(IQ.createResultIQ(iq));
-
- /*
- * Now that the acknowledging is out of the way, do go about our
- * business with the Packet.
- */
- ColibriConferenceIQ conferenceIQ = (ColibriConferenceIQ) iq;
- boolean interrupted = false;
-
- try
- {
- processColibriConferenceIQ(conferenceIQ);
- }
- catch (Throwable t)
- {
- logger.error(
- "An error occurred during the processing of a "
- + packet.getClass().getName() + " packet",
- t);
-
- if (t instanceof InterruptedException)
- {
- /*
- * We cleared the interrupted state of the current Thread by
- * catching the InterruptedException. However, we do not really
- * care whether the current Thread has been interrupted - we
- * caught the InterruptedException because we want to swallow
- * any Throwable. Consequently, we should better restore the
- * interrupted state.
- */
- interrupted = true;
- }
- else if (t instanceof ThreadDeath)
- throw (ThreadDeath) t;
- }
- if (interrupted)
- Thread.currentThread().interrupt();
- }
-
- /**
- * {@inheritDoc}
- *
- * Implements {@link RegistrationStateChangeListener}. Notifies this
- * instance that there has been a change in the <tt>RegistrationState</tt>
- * of {@link #protocolProvider}. Subscribes this instance to
- * {@link ColibriConferenceIQ}s as soon as <tt>protocolProvider</tt> is
- * registered and unsubscribes it as soon as <tt>protocolProvider</tt> is
- * unregistered.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent ev)
- {
- RegistrationState registrationState = ev.getNewState();
-
- if (RegistrationState.REGISTERED.equals(registrationState))
- {
- protocolProvider.getConnection().addPacketListener(this, this);
- }
- else if (RegistrationState.UNREGISTERED.equals(registrationState))
- {
- XMPPConnection connection = protocolProvider.getConnection();
-
- if (connection != null)
- connection.removePacketListener(this);
- }
- }
-}
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import java.util.*;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.protocol.media.*;
+import net.java.sip.communicator.util.*;
+
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.*;
+
+/**
+ * Implements <tt>OperationSetVideoBridge</tt> for Jabber.
+ *
+ * @author Yana Stamcheva
+ * @author Lyubomir Marinov
+ */
+public class OperationSetVideoBridgeImpl
+ implements OperationSetVideoBridge,
+ PacketFilter,
+ PacketListener,
+ RegistrationStateChangeListener
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>OperationSetVideoBridgeImpl</tt>
+ * class and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(OperationSetVideoBridgeImpl.class);
+
+ /**
+ * The <tt>ProtocolProviderService</tt> implementation which initialized
+ * this instance, owns it and is often referred to as its parent.
+ */
+ private final ProtocolProviderServiceJabberImpl protocolProvider;
+
+ /**
+ * Creates an instance of <tt>OperationSetVideoBridgeImpl</tt> by
+ * specifying the parent <tt>ProtocolProviderService</tt> announcing this
+ * operation set.
+ *
+ * @param protocolProvider the parent Jabber protocol provider
+ */
+ public OperationSetVideoBridgeImpl(
+ ProtocolProviderServiceJabberImpl protocolProvider)
+ {
+ this.protocolProvider = protocolProvider;
+ this.protocolProvider.addRegistrationStateChangeListener(this);
+ }
+
+ /**
+ * Implements {@link PacketFilter}. Determines whether this instance is
+ * interested in a specific {@link Packet}.
+ * <tt>OperationSetVideoBridgeImpl</tt> returns <tt>true</tt> if the
+ * specified <tt>packet</tt> is a {@link ColibriConferenceIQ}; otherwise,
+ * <tt>false</tt>.
+ *
+ * @param packet the <tt>Packet</tt> to be determined whether this instance
+ * is interested in it
+ * @return <tt>true</tt> if the specified <tt>packet</tt> is a
+ * <tt>ColibriConferenceIQ</tt>; otherwise, <tt>false</tt>
+ */
+ public boolean accept(Packet packet)
+ {
+ return (packet instanceof ColibriConferenceIQ);
+ }
+
+ /**
+ * Creates a conference call with the specified callees as call peers via a
+ * video bridge provided by the parent Jabber provider.
+ *
+ * @param callees the list of addresses that we should call
+ * @return the newly created conference call containing all CallPeers
+ * @throws OperationFailedException if establishing the conference call
+ * fails
+ * @throws OperationNotSupportedException if the provider does not have any
+ * conferencing features.
+ */
+ public Call createConfCall(String[] callees)
+ throws OperationFailedException,
+ OperationNotSupportedException
+ {
+ return
+ protocolProvider
+ .getOperationSet(OperationSetTelephonyConferencing.class)
+ .createConfCall(
+ callees,
+ new MediaAwareCallConference(true));
+ }
+
+ /**
+ * Invites the callee represented by the specified uri to an already
+ * existing call using a video bridge provided by the parent Jabber provider.
+ * The difference between this method and createConfCall is that
+ * inviteCalleeToCall allows a user to add new peers to an already
+ * established conference.
+ *
+ * @param uri the callee to invite to an existing conf call.
+ * @param call the call that we should invite the callee to.
+ * @return the CallPeer object corresponding to the callee represented by
+ * the specified uri.
+ * @throws OperationFailedException if inviting the specified callee to the
+ * specified call fails
+ * @throws OperationNotSupportedException if allowing additional callees to
+ * a pre-established call is not supported.
+ */
+ public CallPeer inviteCalleeToCall(String uri, Call call)
+ throws OperationFailedException,
+ OperationNotSupportedException
+ {
+ return
+ protocolProvider
+ .getOperationSet(OperationSetTelephonyConferencing.class)
+ .inviteCalleeToCall(uri, call);
+ }
+
+ /**
+ * Indicates if there's an active video bridge available at this moment. The
+ * Jabber provider may announce support for video bridge, but it should not
+ * be used for calling until it becomes actually active.
+ *
+ * @return <tt>true</tt> to indicate that there's currently an active
+ * available video bridge, <tt>false</tt> - otherwise
+ */
+ public boolean isActive()
+ {
+ String jitsiVideobridge = protocolProvider.getJitsiVideobridge();
+
+ return ((jitsiVideobridge != null) && (jitsiVideobridge.length() > 0));
+ }
+
+ /**
+ * Notifies this instance that a specific <tt>ColibriConferenceIQ</tt> has
+ * been received.
+ *
+ * @param conferenceIQ the <tt>ColibriConferenceIQ</tt> which has been
+ * received
+ */
+ private void processColibriConferenceIQ(ColibriConferenceIQ conferenceIQ)
+ {
+ /*
+ * The application is not a Jitsi Videobridge server, it is a client.
+ * Consequently, the specified ColibriConferenceIQ is sent to it in
+ * relation to the part of the application's functionality which makes
+ * requests to a Jitsi Videobridge server i.e. CallJabberImpl.
+ *
+ * Additionally, the method processColibriConferenceIQ is presently tasked
+ * with processing ColibriConferenceIQ requests only. They are SET IQs
+ * sent by the Jitsi Videobridge server to notify the application about
+ * updates in the states of (colibri) conferences organized by the
+ * application.
+ */
+ if (IQ.Type.SET.equals(conferenceIQ.getType())
+ && conferenceIQ.getID() != null)
+ {
+ OperationSetBasicTelephony<?> basicTelephony
+ = protocolProvider.getOperationSet(
+ OperationSetBasicTelephony.class);
+
+ if (basicTelephony != null)
+ {
+ Iterator<? extends Call> i = basicTelephony.getActiveCalls();
+
+ while (i.hasNext())
+ {
+ Call call = i.next();
+
+ if (call instanceof CallJabberImpl)
+ {
+ CallJabberImpl callJabberImpl = (CallJabberImpl) call;
+ MediaAwareCallConference conference
+ = callJabberImpl.getConference();
+
+ if ((conference != null)
+ && conference.isJitsiVideobridge())
+ {
+ /*
+ * TODO We may want to disallow rogue CallJabberImpl
+ * instances which may throw an exception to prevent
+ * the conferenceIQ from reaching the CallJabberImpl
+ * instance which it was meant for.
+ */
+ if (callJabberImpl.processColibriConferenceIQ(
+ conferenceIQ))
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Implements {@link PacketListener}. Notifies this instance that a specific
+ * {@link Packet} (which this instance has already expressed interest into
+ * by returning <tt>true</tt> from {@link #accept(Packet)}) has been
+ * received.
+ *
+ * @param packet the <tt>Packet</tt> which has been received and which this
+ * instance is given a chance to process
+ */
+ public void processPacket(Packet packet)
+ {
+ /*
+ * As we do elsewhere, acknowledge the receipt of the Packet first and
+ * then go about our business with it.
+ */
+ IQ iq = (IQ) packet;
+
+ if (iq.getType() == IQ.Type.SET)
+ protocolProvider.getConnection().sendPacket(IQ.createResultIQ(iq));
+
+ /*
+ * Now that the acknowledging is out of the way, do go about our
+ * business with the Packet.
+ */
+ ColibriConferenceIQ conferenceIQ = (ColibriConferenceIQ) iq;
+ boolean interrupted = false;
+
+ try
+ {
+ processColibriConferenceIQ(conferenceIQ);
+ }
+ catch (Throwable t)
+ {
+ logger.error(
+ "An error occurred during the processing of a "
+ + packet.getClass().getName() + " packet",
+ t);
+
+ if (t instanceof InterruptedException)
+ {
+ /*
+ * We cleared the interrupted state of the current Thread by
+ * catching the InterruptedException. However, we do not really
+ * care whether the current Thread has been interrupted - we
+ * caught the InterruptedException because we want to swallow
+ * any Throwable. Consequently, we should better restore the
+ * interrupted state.
+ */
+ interrupted = true;
+ }
+ else if (t instanceof ThreadDeath)
+ throw (ThreadDeath) t;
+ }
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Implements {@link RegistrationStateChangeListener}. Notifies this
+ * instance that there has been a change in the <tt>RegistrationState</tt>
+ * of {@link #protocolProvider}. Subscribes this instance to
+ * {@link ColibriConferenceIQ}s as soon as <tt>protocolProvider</tt> is
+ * registered and unsubscribes it as soon as <tt>protocolProvider</tt> is
+ * unregistered.
+ */
+ public void registrationStateChanged(RegistrationStateChangeEvent ev)
+ {
+ RegistrationState registrationState = ev.getNewState();
+
+ if (RegistrationState.REGISTERED.equals(registrationState))
+ {
+ protocolProvider.getConnection().addPacketListener(this, this);
+ }
+ else if (RegistrationState.UNREGISTERED.equals(registrationState))
+ {
+ Connection connection = protocolProvider.getConnection();
+
+ if (connection != null)
+ connection.removePacketListener(this);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java
index f38d0bc..b219d68 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java
@@ -248,7 +248,7 @@ public class OutgoingFileTransferJabberImpl
ThumbnailIQ thumbnailIQ = (ThumbnailIQ) packet;
String thumbnailIQCid = thumbnailIQ.getCid();
- XMPPConnection connection = protocolProvider.getConnection();
+ Connection connection = protocolProvider.getConnection();
if ((thumbnailIQCid != null)
&& thumbnailIQCid.equals(thumbnailElement.getCid()))
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderFactoryJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderFactoryJabberImpl.java
index 4f9fc5f..86666f3 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderFactoryJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderFactoryJabberImpl.java
@@ -21,6 +21,7 @@ import java.util.*;
import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.jabber.*;
import org.jivesoftware.smack.provider.*;
import org.jivesoftware.smack.util.*;
import org.osgi.framework.*;
@@ -46,7 +47,14 @@ public class ProtocolProviderFactoryJabberImpl
{
try
{
+
+ // Set the extension provider manager for classes that use
+ // it directly
ProviderManager.setInstance(new ProviderManagerExt());
+ // Set the Smack interop implementation for the classes that need
+ // to support Smackv4 interoperation
+ AbstractSmackInteroperabilityLayer.setImplementationClass(
+ SmackV3InteroperabilityLayer.class);
}
catch(Throwable t)
{
@@ -179,7 +187,7 @@ public class ProtocolProviderFactoryJabberImpl
ProtocolProviderServiceJabberImpl service =
new ProtocolProviderServiceJabberImpl();
- service.initialize(userID, accountID);
+ service.initialize(userID, (JabberAccountID) accountID);
return service;
}
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 2ea5c9c..47b9b75 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
@@ -32,6 +32,7 @@ import net.java.sip.communicator.impl.protocol.jabber.extensions.carbon.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.coin.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.inputevt.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.jibri.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingleinfo.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.keepalive.*;
@@ -41,6 +42,7 @@ import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.dns.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.protocol.jabber.*;
import net.java.sip.communicator.service.protocol.jabberconstants.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
@@ -152,6 +154,14 @@ public class ProtocolProviderServiceJabberImpl
public static final String URN_IETF_RFC_3264 = "urn:ietf:rfc:3264";
/**
+ * http://xmpp.org/extensions/xep-0092.html Software Version.
+ *
+ */
+ // Used in JVB
+ @SuppressWarnings("unused")
+ public static final String URN_XMPP_IQ_VERSION = "jabber:iq:version";
+
+ /**
* Jingle's Discovery Info URN for "XEP-0294: Jingle RTP Header Extensions
* Negotiation" support.
*/
@@ -211,7 +221,7 @@ public class ProtocolProviderServiceJabberImpl
/**
* Used to connect to a XMPP server.
*/
- private XMPPConnection connection;
+ private Connection connection;
/**
* The socket address of the XMPP server.
@@ -231,7 +241,7 @@ public class ProtocolProviderServiceJabberImpl
/**
* The identifier of the account that this provider represents.
*/
- private AccountID accountID = null;
+ private JabberAccountID accountID = null;
/**
* Used when we need to re-register
@@ -598,7 +608,7 @@ public class ProtocolProviderServiceJabberImpl
*/
public boolean isSignalingTransportSecure()
{
- return connection != null && connection.isUsingTLS();
+ return connection.isSecureConnection();
}
/**
@@ -613,7 +623,7 @@ public class ProtocolProviderServiceJabberImpl
if(connection != null && connection.isConnected())
{
// Transport using a secure connection.
- if(connection.isUsingTLS())
+ if(isSignalingTransportSecure())
{
return TransportProtocol.TLS;
}
@@ -1112,11 +1122,24 @@ public class ProtocolProviderServiceJabberImpl
JabberLoginStrategy loginStrategy)
throws XMPPException
{
- ConnectionConfiguration confConn = new ConnectionConfiguration(
- address.getAddress().getHostAddress(),
- address.getPort(),
- serviceName, proxy
- );
+ // BOSH or TCP ?
+ ConnectionConfiguration confConn;
+ String boshURL = accountID.getBoshUrl();
+ boolean isBosh = !org.jitsi.util.StringUtils.isNullOrEmpty(boshURL);
+
+ if (isBosh)
+ {
+ confConn = new BOSHConfiguration(serviceName);
+ ((BOSHConfiguration)confConn).setBoshUrl(boshURL);
+ }
+ else
+ {
+ confConn
+ = new ConnectionConfiguration(
+ address.getAddress().getHostAddress(),
+ address.getPort(),
+ serviceName, proxy);
+ }
// if we have OperationSetPersistentPresence skip sending initial
// presence while login is executed, the OperationSet will take care
@@ -1144,7 +1167,11 @@ public class ProtocolProviderServiceJabberImpl
disconnectAndCleanConnection();
}
- connection = new XMPPConnection(confConn);
+ connection
+ = isBosh
+ ? new XMPPBOSHConnection((BOSHConfiguration)confConn)
+ : new XMPPConnection(confConn);
+
this.address = address;
try
@@ -1194,13 +1221,16 @@ public class ProtocolProviderServiceJabberImpl
throw new XMPPException("Error creating custom trust manager", e);
}
- if(debugger == null)
+ // FIXME rework debugger to work with Connection if possible
+ if(debugger == null && connection instanceof XMPPConnection)
+ {
debugger = new SmackPacketDebugger();
- // sets the debugger
- debugger.setConnection(connection);
- connection.addPacketListener(debugger, null);
- connection.addPacketInterceptor(debugger, null);
+ // sets the debugger
+ debugger.setConnection((XMPPConnection) connection);
+ connection.addPacketListener(debugger, null);
+ connection.addPacketInterceptor(debugger, null);
+ }
connection.connect();
@@ -1247,9 +1277,10 @@ public class ProtocolProviderServiceJabberImpl
}
else
{
- if (connection.getSocket() instanceof SSLSocket)
+ final SSLSocket sslSocket = getSSLSocket();
+
+ if (sslSocket != null)
{
- final SSLSocket sslSocket = (SSLSocket) connection.getSocket();
StringBuilder buff = new StringBuilder();
buff.append("Chosen TLS protocol and algorithm:\n")
.append("Protocol: ").append(sslSocket.getSession()
@@ -1538,7 +1569,7 @@ public class ProtocolProviderServiceJabberImpl
* @see net.java.sip.communicator.service.protocol.AccountID
*/
protected void initialize(String screenname,
- AccountID accountID)
+ JabberAccountID accountID)
{
synchronized(initializationLock)
{
@@ -1732,6 +1763,12 @@ public class ProtocolProviderServiceJabberImpl
ColibriConferenceIQ.NAMESPACE,
new ColibriIQProvider());
+ providerManager.addIQProvider(
+ JibriIq.ELEMENT_NAME,
+ JibriIq.NAMESPACE,
+ new JibriIqProvider()
+ );
+
providerManager.addExtensionProvider(
ConferenceDescriptionPacketExtension.ELEMENT_NAME,
ConferenceDescriptionPacketExtension.NAMESPACE,
@@ -2025,11 +2062,98 @@ public class ProtocolProviderServiceJabberImpl
}
/**
- * Returns the <tt>XMPPConnection</tt>opened by this provider
- * @return a reference to the <tt>XMPPConnection</tt> last opened by this
+ * Validates the node part of a JID and returns an error message if
+ * applicable and a suggested correction.
+ *
+ * @param contactId the contact identifier to validate
+ * @param result Must be supplied as an empty a list. Implementors add
+ * items:
+ * <ol>
+ * <li>is the error message if applicable
+ * <li>a suggested correction. Index 1 is optional and can only
+ * be present if there was a validation failure.
+ * </ol>
+ * @return true if the contact id is valid, false otherwise
+ */
+ @Override
+ public boolean validateContactAddress(String contactId, List<String> result)
+ {
+ if (result == null)
+ {
+ throw new IllegalArgumentException("result must be an empty list");
+ }
+
+ result.clear();
+ try
+ {
+ contactId = contactId.trim();
+ if (contactId.length() == 0)
+ {
+ result.add(JabberActivator.getResources().getI18NString(
+ "impl.protocol.jabber.INVALID_ADDRESS", new String[]
+ { contactId }));
+ // no suggestion for an empty id
+ return false;
+ }
+
+ String user = contactId;
+ String remainder = "";
+ int at = contactId.indexOf('@');
+ if (at > -1)
+ {
+ user = contactId.substring(0, at);
+ remainder = contactId.substring(at);
+ }
+
+ // <conforming-char> ::= #x21 | [#x23-#x25] | [#x28-#x2E] |
+ // [#x30-#x39] | #x3B | #x3D | #x3F |
+ // [#x41-#x7E] | [#x80-#xD7FF] |
+ // [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+ boolean valid = true;
+ String suggestion = "";
+ for (char c : user.toCharArray())
+ {
+ if (!(c == 0x21 || (c >= 0x23 && c <= 0x25)
+ || (c >= 0x28 && c <= 0x2e) || (c >= 0x30 && c <= 0x39)
+ || c == 0x3b || c == 0x3d || c == 0x3f
+ || (c >= 0x41 && c <= 0x7e) || (c >= 0x80 && c <= 0xd7ff)
+ || (c >= 0xe000 && c <= 0xfffd)))
+ {
+ valid = false;
+ }
+ else
+ {
+ suggestion += c;
+ }
+ }
+
+ if (!valid)
+ {
+ result.add(JabberActivator.getResources().getI18NString(
+ "impl.protocol.jabber.INVALID_ADDRESS", new String[]
+ { contactId }));
+ result.add(suggestion + remainder);
+ return false;
+ }
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ result.add(JabberActivator.getResources().getI18NString(
+ "impl.protocol.jabber.INVALID_ADDRESS", new String[]
+ { contactId }));
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the <tt>Connection</tt>opened by this provider
+ * @return a reference to the <tt>Connection</tt> last opened by this
* provider.
*/
- public XMPPConnection getConnection()
+ public Connection getConnection()
{
return connection;
}
@@ -2315,18 +2439,16 @@ public class ProtocolProviderServiceJabberImpl
*/
public boolean isFeatureListSupported(String jid, String... features)
{
- boolean isFeatureListSupported = true;
-
try
{
if(discoveryManager == null)
- return isFeatureListSupported;
+ return false;
DiscoverInfo featureInfo =
discoveryManager.discoverInfoNonBlocking(jid);
if(featureInfo == null)
- return isFeatureListSupported;
+ return false;
for (String feature : features)
{
@@ -2334,17 +2456,19 @@ public class ProtocolProviderServiceJabberImpl
{
// If one is not supported we return false and don't check
// the others.
- isFeatureListSupported = false;
- break;
+ return false;
}
}
+
+ return true;
}
catch (XMPPException e)
{
if (logger.isDebugEnabled())
logger.debug("Failed to retrive discovery info.", e);
}
- return isFeatureListSupported;
+
+ return false;
}
/**
@@ -2386,7 +2510,7 @@ public class ProtocolProviderServiceJabberImpl
*/
public String getFullJid(String bareJid)
{
- XMPPConnection connection = getConnection();
+ Connection connection = getConnection();
// when we are not connected there is no full jid
if (connection != null && connection.isConnected())
@@ -2590,12 +2714,21 @@ public class ProtocolProviderServiceJabberImpl
*/
public void startJingleNodesDiscovery()
{
+ if (!(connection instanceof XMPPConnection))
+ {
+ logger.warn(
+ "Jingle node discovery currently will work only with " +
+ "TCP XMPP connection");
+ return;
+ }
+
// Jingle Nodes Service Initialization
+ final XMPPConnection xmppConnection = (XMPPConnection) connection;
final JabberAccountIDImpl accID = (JabberAccountIDImpl)getAccountID();
- final SmackServiceNode service = new SmackServiceNode(connection,
- 60000);
+ final SmackServiceNode service
+ = new SmackServiceNode(xmppConnection, 60000);
// make sure SmackServiceNode will clean up when connection is closed
- connection.addConnectionListener(service);
+ xmppConnection.addConnectionListener(service);
for(JingleNodeDescriptor desc : accID.getJingleNodes())
{
@@ -2611,7 +2744,7 @@ public class ProtocolProviderServiceJabberImpl
new Thread(new JingleNodesServiceDiscovery(
service,
- connection,
+ xmppConnection,
accID,
jingleNodesSyncRoot))
.start();
@@ -2739,7 +2872,7 @@ public class ProtocolProviderServiceJabberImpl
*/
private void setTrafficClass()
{
- Socket s = connection.getSocket();
+ Socket s = getSocket();
if(s != null)
{
@@ -2774,7 +2907,7 @@ public class ProtocolProviderServiceJabberImpl
*/
public String getJitsiVideobridge()
{
- XMPPConnection connection = getConnection();
+ Connection connection = getConnection();
if (connection != null)
{
@@ -2865,21 +2998,23 @@ public class ProtocolProviderServiceJabberImpl
}
/**
+ * Obtains XMPP connection's socket.
+ * @return <tt>Socket</tt> instance used by the underlying XMPP connection
+ * or <tt>null</tt> if "non socket" type of transport is currently used.
+ */
+ private Socket getSocket()
+ {
+ return connection != null ? connection.getSocket() : null;
+ }
+
+ /**
* Return the SSL socket (if TLS used).
* @return The SSL socket or null if not used
*/
- public SSLSocket getSSLSocket()
+ SSLSocket getSSLSocket()
{
- final SSLSocket result;
- final Socket socket = connection.getSocket();
- if (socket instanceof SSLSocket)
- {
- result = (SSLSocket) socket;
- }
- else
- {
- result = null;
- }
- return result;
+ final Socket socket = getSocket();
+
+ return (socket instanceof SSLSocket) ? (SSLSocket) socket : null;
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
index 0aa4fb6..4bd49a9 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,529 +15,529 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.jabber;
-
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
-import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
-import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
-import net.java.sip.communicator.service.protocol.*;
-
-import org.jitsi.service.neomedia.*;
-import org.jivesoftware.smack.packet.*;
-
-/**
- * A {@link TransportManagerJabberImpl} implementation that would only gather a
- * single candidate pair (i.e. RTP and RTCP).
- *
- * @author Emil Ivov
- * @author Lyubomir Marinov
- * @author Hristo Terezov
- */
-public class RawUdpTransportManager
- extends TransportManagerJabberImpl
-{
- /**
- * The list of <tt>ContentPacketExtension</tt>s which represents the local
- * counterpart of the negotiation between the local and the remote peers.
- */
- private List<ContentPacketExtension> local;
-
- /**
- * The collection of <tt>ContentPacketExtension</tt>s which represents the
- * remote counterpart of the negotiation between the local and the remote
- * peers.
- */
- private final List<Iterable<ContentPacketExtension>> remotes
- = new LinkedList<Iterable<ContentPacketExtension>>();
-
- /**
- * Creates a new instance of this transport manager, binding it to the
- * specified peer.
- *
- * @param callPeer the {@link CallPeer} whose traffic we will be taking
- * care of.
- */
- public RawUdpTransportManager(CallPeerJabberImpl callPeer)
- {
- super(callPeer);
- }
-
- /**
- * {@inheritDoc}
- */
- protected PacketExtension createTransport(String media)
- throws OperationFailedException
- {
- MediaType mediaType = MediaType.parseString(media);
-
- return createTransport(mediaType, getStreamConnector(mediaType));
- }
-
- /**
- * Creates a raw UDP transport element according to a specific
- * <tt>StreamConnector</tt>.
- *
- * @param mediaType the <tt>MediaType</tt> of the <tt>MediaStream</tt> which
- * uses the specified <tt>connector</tt> or <tt>channel</tt>
- * @param connector the <tt>StreamConnector</tt> to be described within the
- * transport element
- * @return a {@link RawUdpTransportPacketExtension} containing the RTP and
- * RTCP candidates of the specified <tt>connector</tt>
- */
- private RawUdpTransportPacketExtension createTransport(
- MediaType mediaType,
- StreamConnector connector)
- {
- RawUdpTransportPacketExtension ourTransport
- = new RawUdpTransportPacketExtension();
- int generation = getCurrentGeneration();
-
- // create and add candidates that correspond to the stream connector
- // RTP
- CandidatePacketExtension rtpCand = new CandidatePacketExtension();
-
- rtpCand.setComponent(CandidatePacketExtension.RTP_COMPONENT_ID);
- rtpCand.setGeneration(generation);
- rtpCand.setID(getNextID());
- rtpCand.setType(CandidateType.host);
-
- DatagramSocket dataSocket = connector.getDataSocket();
-
- rtpCand.setIP(dataSocket.getLocalAddress().getHostAddress());
- rtpCand.setPort(dataSocket.getLocalPort());
-
- ourTransport.addCandidate(rtpCand);
-
- // RTCP
- CandidatePacketExtension rtcpCand = new CandidatePacketExtension();
-
- rtcpCand.setComponent(CandidatePacketExtension.RTCP_COMPONENT_ID);
- rtcpCand.setGeneration(generation);
- rtcpCand.setID(getNextID());
- rtcpCand.setType(CandidateType.host);
-
- DatagramSocket controlSocket = connector.getControlSocket();
-
- rtcpCand.setIP(controlSocket.getLocalAddress().getHostAddress());
- rtcpCand.setPort(controlSocket.getLocalPort());
-
- ourTransport.addCandidate(rtcpCand);
-
- return ourTransport;
- }
-
- /**
- * {@inheritDoc}
- */
- protected PacketExtension createTransportPacketExtension()
- {
- return new RawUdpTransportPacketExtension();
- }
-
- /**
- * Implements {@link TransportManagerJabberImpl#getStreamTarget(MediaType)}.
- * Gets the <tt>MediaStreamTarget</tt> to be used as the <tt>target</tt> of
- * the <tt>MediaStream</tt> with a specific <tt>MediaType</tt>.
- *
- * @param mediaType the <tt>MediaType</tt> of the <tt>MediaStream</tt> which
- * is to have its <tt>target</tt> set to the returned
- * <tt>MediaStreamTarget</tt>
- * @return the <tt>MediaStreamTarget</tt> to be used as the <tt>target</tt>
- * of the <tt>MediaStream</tt> with the specified <tt>MediaType</tt>
- * @see TransportManagerJabberImpl#getStreamTarget(MediaType)
- */
- @Override
- public MediaStreamTarget getStreamTarget(MediaType mediaType)
- {
- ColibriConferenceIQ.Channel channel
- = getColibriChannel(mediaType, true /* local */);
- MediaStreamTarget streamTarget = null;
-
- if (channel == null)
- {
- String media = mediaType.toString();
-
- for (Iterable<ContentPacketExtension> remote : remotes)
- {
- for (ContentPacketExtension content : remote)
- {
- RtpDescriptionPacketExtension rtpDescription
- = content.getFirstChildOfType(
- RtpDescriptionPacketExtension.class);
-
- if (media.equals(rtpDescription.getMedia()))
- {
- streamTarget
- = JingleUtils.extractDefaultTarget(content);
- break;
- }
- }
- }
- }
- else
- {
- IceUdpTransportPacketExtension transport = channel.getTransport();
-
- if (transport != null)
- streamTarget = JingleUtils.extractDefaultTarget(transport);
- if (streamTarget == null)
- {
- /*
- * For the purposes of compatibility with legacy Jitsi
- * Videobridge, support the channel attributes host, rtpPort and
- * rtcpPort.
- */
- @SuppressWarnings("deprecation")
- String host = channel.getHost();
-
- if (host != null)
- {
- @SuppressWarnings("deprecation")
- int rtpPort = channel.getRTPPort();
- @SuppressWarnings("deprecation")
- int rtcpPort = channel.getRTCPPort();
-
- streamTarget
- = new MediaStreamTarget(
- new InetSocketAddress(host, rtpPort),
- new InetSocketAddress(host, rtcpPort));
- }
- }
- }
- return streamTarget;
- }
-
- /**
- * Implements {@link TransportManagerJabberImpl#getXmlNamespace()}. Gets the
- * XML namespace of the Jingle transport implemented by this
- * <tt>TransportManagerJabberImpl</tt>.
- *
- * @return the XML namespace of the Jingle transport implemented by this
- * <tt>TransportManagerJabberImpl</tt>
- * @see TransportManagerJabberImpl#getXmlNamespace()
- */
- @Override
- public String getXmlNamespace()
- {
- return ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0;
- }
-
- /**
- * Removes a content with a specific name from the transport-related part of
- * the session represented by this <tt>TransportManagerJabberImpl</tt> which
- * may have been reported through previous calls to the
- * <tt>startCandidateHarvest</tt> and
- * <tt>startConnectivityEstablishment</tt> methods.
- *
- * @param name the name of the content to be removed from the
- * transport-related part of the session represented by this
- * <tt>TransportManagerJabberImpl</tt>
- * @see TransportManagerJabberImpl#removeContent(String)
- */
- @Override
- public void removeContent(String name)
- {
- if (local != null)
- removeContent(local, name);
-
- removeRemoteContent(name);
- }
-
- /**
- * Removes a content with a specific name from the remote counterpart of the
- * negotiation between the local and the remote peers.
- *
- * @param name the name of the content to be removed from the remote
- * counterpart of the negotiation between the local and the remote peers
- */
- private void removeRemoteContent(String name)
- {
- for (Iterator<Iterable<ContentPacketExtension>> remoteIter
- = remotes.iterator();
- remoteIter.hasNext();)
- {
- Iterable<ContentPacketExtension> remote = remoteIter.next();
-
- /*
- * Once the remote content is removed, make sure that we are not
- * retaining sets which do not have any contents.
- */
- if ((removeContent(remote, name) != null)
- && !remote.iterator().hasNext())
- {
- remoteIter.remove();
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- protected PacketExtension startCandidateHarvest(
- ContentPacketExtension theirContent,
- ContentPacketExtension ourContent,
- TransportInfoSender transportInfoSender,
- String media)
- throws OperationFailedException
- {
- return createTransportForStartCandidateHarvest(media);
- }
-
- /**
- * Starts transport candidate harvest. This method should complete rapidly
- * and, in case of lengthy procedures like STUN/TURN/UPnP candidate harvests
- * are necessary, they should be executed in a separate thread. Candidate
- * harvest would then need to be concluded in the
- * {@link #wrapupCandidateHarvest()} method which would be called once we
- * absolutely need the candidates.
- *
- * @param theirOffer a media description offer that we've received from the
- * remote party and that we should use in case we need to know what
- * transports our peer is using.
- * @param ourAnswer the content descriptions that we should be adding our
- * transport lists to (although not necessarily in this very instance).
- * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by
- * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt>
- * <tt>JingleIQ</tt>s from the local peer to the remote peer if this
- * <tt>TransportManagerJabberImpl</tt> wishes to utilize
- * <tt>transport-info</tt>. Local candidate addresses sent by this
- * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are
- * expected to not be included in the result of
- * {@link #wrapupCandidateHarvest()}.
- *
- * @throws OperationFailedException if we fail to allocate a port number.
- * @see TransportManagerJabberImpl#startCandidateHarvest(List, List,
- * TransportInfoSender)
- */
- @Override
- public void startCandidateHarvest(
- List<ContentPacketExtension> theirOffer,
- List<ContentPacketExtension> ourAnswer,
- TransportInfoSender transportInfoSender)
- throws OperationFailedException
- {
- this.local = ourAnswer;
-
- super.startCandidateHarvest(theirOffer, ourAnswer, transportInfoSender);
- }
-
- /**
- * Overrides the super implementation in order to remember the remote
- * counterpart of the negotiation between the local and the remote peer for
- * subsequent calls to {@link #getStreamTarget(MediaType)}.
- *
- * @param remote the collection of <tt>ContentPacketExtension</tt>s which
- * represents the remote counterpart of the negotiation between the local
- * and the remote peer
- * @return <tt>true</tt> because <tt>RawUdpTransportManager</tt> does not
- * perform connectivity checks
- * @see TransportManagerJabberImpl#startConnectivityEstablishment(Iterable)
- */
- @Override
- public boolean startConnectivityEstablishment(
- Iterable<ContentPacketExtension> remote)
- {
- if ((remote != null) && !remotes.contains(remote))
- {
- /*
- * The state of the session in Jingle is maintained by each peer and
- * is modified by content-add and content-remove. The remotes field
- * of this RawUdpTransportManager represents the state of the
- * session with respect to the remote peer. When the remote peer
- * tells us about a specific set of contents, make sure that it is
- * the only record we will have with respect to the specified set of
- * contents.
- */
- for (ContentPacketExtension content : remote)
- removeRemoteContent(content.getName());
-
- remotes.add(remote);
- }
-
- return super.startConnectivityEstablishment(remote);
- }
-
- /**
- * Simply returns the list of local candidates that we gathered during the
- * harvest. This is a raw UDP transport manager so there's no real wrapping
- * up to do.
- *
- * @return the list of local candidates that we gathered during the harvest
- * @see TransportManagerJabberImpl#wrapupCandidateHarvest()
- */
- @Override
- public List<ContentPacketExtension> wrapupCandidateHarvest()
- {
- return local;
- }
-
- /**
- * Returns the extended type of the candidate selected if this transport
- * manager is using ICE.
- *
- * @param streamName The stream name (AUDIO, VIDEO);
- *
- * @return The extended type of the candidate selected if this transport
- * manager is using ICE. Otherwise, returns null.
- */
- @Override
- public String getICECandidateExtendedType(String streamName)
- {
- return null;
- }
-
- /**
- * Returns the current state of ICE processing.
- *
- * @return the current state of ICE processing.
- */
- @Override
- public String getICEState()
- {
- return null;
- }
-
- /**
- * Returns the ICE local host address.
- *
- * @param streamName The stream name (AUDIO, VIDEO);
- *
- * @return the ICE local host address if this transport
- * manager is using ICE. Otherwise, returns null.
- */
- @Override
- public InetSocketAddress getICELocalHostAddress(String streamName)
- {
- return null;
- }
-
- /**
- * Returns the ICE remote host address.
- *
- * @param streamName The stream name (AUDIO, VIDEO);
- *
- * @return the ICE remote host address if this transport
- * manager is using ICE. Otherwise, returns null.
- */
- @Override
- public InetSocketAddress getICERemoteHostAddress(String streamName)
- {
- return null;
- }
-
- /**
- * Returns the ICE local reflexive address (server or peer reflexive).
- *
- * @param streamName The stream name (AUDIO, VIDEO);
- *
- * @return the ICE local reflexive address. May be null if this transport
- * manager is not using ICE or if there is no reflexive address for the
- * local candidate used.
- */
- @Override
- public InetSocketAddress getICELocalReflexiveAddress(String streamName)
- {
- return null;
- }
-
- /**
- * Returns the ICE remote reflexive address (server or peer reflexive).
- *
- * @param streamName The stream name (AUDIO, VIDEO);
- *
- * @return the ICE remote reflexive address. May be null if this transport
- * manager is not using ICE or if there is no reflexive address for the
- * remote candidate used.
- */
- @Override
- public InetSocketAddress getICERemoteReflexiveAddress(String streamName)
- {
- return null;
- }
-
- /**
- * Returns the ICE local relayed address (server or peer relayed).
- *
- * @param streamName The stream name (AUDIO, VIDEO);
- *
- * @return the ICE local relayed address. May be null if this transport
- * manager is not using ICE or if there is no relayed address for the
- * local candidate used.
- */
- @Override
- public InetSocketAddress getICELocalRelayedAddress(String streamName)
- {
- return null;
- }
-
- /**
- * Returns the ICE remote relayed address (server or peer relayed).
- *
- * @param streamName The stream name (AUDIO, VIDEO);
- *
- * @return the ICE remote relayed address. May be null if this transport
- * manager is not using ICE or if there is no relayed address for the
- * remote candidate used.
- */
- @Override
- public InetSocketAddress getICERemoteRelayedAddress(String streamName)
- {
- return null;
- }
-
- /**
- * Returns the total harvesting time (in ms) for all harvesters.
- *
- * @return The total harvesting time (in ms) for all the harvesters. 0 if
- * the ICE agent is null, or if the agent has nevers harvested.
- */
- @Override
- public long getTotalHarvestingTime()
- {
- return 0;
- }
-
- /**
- * Returns the harvesting time (in ms) for the harvester given in parameter.
- *
- * @param harvesterName The class name if the harvester.
- *
- * @return The harvesting time (in ms) for the harvester given in parameter.
- * 0 if this harvester does not exists, if the ICE agent is null, or if the
- * agent has never harvested with this harvester.
- */
- @Override
- public long getHarvestingTime(String harvesterName)
- {
- return 0;
- }
-
- /**
- * Returns the number of harvesting for this agent.
- *
- * @return The number of harvesting for this agent.
- */
- @Override
- public int getNbHarvesting()
- {
- return 0;
- }
-
- /**
- * Returns the number of harvesting time for the harvester given in
- * parameter.
- *
- * @param harvesterName The class name if the harvester.
- *
- * @return The number of harvesting time for the harvester given in
- * parameter.
- */
- @Override
- public int getNbHarvesting(String harvesterName)
- {
- return 0;
- }
-}
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import java.net.*;
+import java.util.*;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
+import net.java.sip.communicator.service.protocol.*;
+
+import org.jitsi.service.neomedia.*;
+import org.jivesoftware.smack.packet.*;
+
+/**
+ * A {@link TransportManagerJabberImpl} implementation that would only gather a
+ * single candidate pair (i.e. RTP and RTCP).
+ *
+ * @author Emil Ivov
+ * @author Lyubomir Marinov
+ * @author Hristo Terezov
+ */
+public class RawUdpTransportManager
+ extends TransportManagerJabberImpl
+{
+ /**
+ * The list of <tt>ContentPacketExtension</tt>s which represents the local
+ * counterpart of the negotiation between the local and the remote peers.
+ */
+ private List<ContentPacketExtension> local;
+
+ /**
+ * The collection of <tt>ContentPacketExtension</tt>s which represents the
+ * remote counterpart of the negotiation between the local and the remote
+ * peers.
+ */
+ private final List<Iterable<ContentPacketExtension>> remotes
+ = new LinkedList<Iterable<ContentPacketExtension>>();
+
+ /**
+ * Creates a new instance of this transport manager, binding it to the
+ * specified peer.
+ *
+ * @param callPeer the {@link CallPeer} whose traffic we will be taking
+ * care of.
+ */
+ public RawUdpTransportManager(CallPeerJabberImpl callPeer)
+ {
+ super(callPeer);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected PacketExtension createTransport(String media)
+ throws OperationFailedException
+ {
+ MediaType mediaType = MediaType.parseString(media);
+
+ return createTransport(mediaType, getStreamConnector(mediaType));
+ }
+
+ /**
+ * Creates a raw UDP transport element according to a specific
+ * <tt>StreamConnector</tt>.
+ *
+ * @param mediaType the <tt>MediaType</tt> of the <tt>MediaStream</tt> which
+ * uses the specified <tt>connector</tt> or <tt>channel</tt>
+ * @param connector the <tt>StreamConnector</tt> to be described within the
+ * transport element
+ * @return a {@link RawUdpTransportPacketExtension} containing the RTP and
+ * RTCP candidates of the specified <tt>connector</tt>
+ */
+ private RawUdpTransportPacketExtension createTransport(
+ MediaType mediaType,
+ StreamConnector connector)
+ {
+ RawUdpTransportPacketExtension ourTransport
+ = new RawUdpTransportPacketExtension();
+ int generation = getCurrentGeneration();
+
+ // create and add candidates that correspond to the stream connector
+ // RTP
+ CandidatePacketExtension rtpCand = new CandidatePacketExtension();
+
+ rtpCand.setComponent(CandidatePacketExtension.RTP_COMPONENT_ID);
+ rtpCand.setGeneration(generation);
+ rtpCand.setID(getNextID());
+ rtpCand.setType(CandidateType.host);
+
+ DatagramSocket dataSocket = connector.getDataSocket();
+
+ rtpCand.setIP(dataSocket.getLocalAddress().getHostAddress());
+ rtpCand.setPort(dataSocket.getLocalPort());
+
+ ourTransport.addCandidate(rtpCand);
+
+ // RTCP
+ CandidatePacketExtension rtcpCand = new CandidatePacketExtension();
+
+ rtcpCand.setComponent(CandidatePacketExtension.RTCP_COMPONENT_ID);
+ rtcpCand.setGeneration(generation);
+ rtcpCand.setID(getNextID());
+ rtcpCand.setType(CandidateType.host);
+
+ DatagramSocket controlSocket = connector.getControlSocket();
+
+ rtcpCand.setIP(controlSocket.getLocalAddress().getHostAddress());
+ rtcpCand.setPort(controlSocket.getLocalPort());
+
+ ourTransport.addCandidate(rtcpCand);
+
+ return ourTransport;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected PacketExtension createTransportPacketExtension()
+ {
+ return new RawUdpTransportPacketExtension();
+ }
+
+ /**
+ * Implements {@link TransportManagerJabberImpl#getStreamTarget(MediaType)}.
+ * Gets the <tt>MediaStreamTarget</tt> to be used as the <tt>target</tt> of
+ * the <tt>MediaStream</tt> with a specific <tt>MediaType</tt>.
+ *
+ * @param mediaType the <tt>MediaType</tt> of the <tt>MediaStream</tt> which
+ * is to have its <tt>target</tt> set to the returned
+ * <tt>MediaStreamTarget</tt>
+ * @return the <tt>MediaStreamTarget</tt> to be used as the <tt>target</tt>
+ * of the <tt>MediaStream</tt> with the specified <tt>MediaType</tt>
+ * @see TransportManagerJabberImpl#getStreamTarget(MediaType)
+ */
+ @Override
+ public MediaStreamTarget getStreamTarget(MediaType mediaType)
+ {
+ ColibriConferenceIQ.Channel channel
+ = getColibriChannel(mediaType, true /* local */);
+ MediaStreamTarget streamTarget = null;
+
+ if (channel == null)
+ {
+ String media = mediaType.toString();
+
+ for (Iterable<ContentPacketExtension> remote : remotes)
+ {
+ for (ContentPacketExtension content : remote)
+ {
+ RtpDescriptionPacketExtension rtpDescription
+ = content.getFirstChildOfType(
+ RtpDescriptionPacketExtension.class);
+
+ if (media.equals(rtpDescription.getMedia()))
+ {
+ streamTarget
+ = JingleUtils.extractDefaultTarget(content);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ IceUdpTransportPacketExtension transport = channel.getTransport();
+
+ if (transport != null)
+ streamTarget = JingleUtils.extractDefaultTarget(transport);
+ if (streamTarget == null)
+ {
+ /*
+ * For the purposes of compatibility with legacy Jitsi
+ * Videobridge, support the channel attributes host, rtpPort and
+ * rtcpPort.
+ */
+ @SuppressWarnings("deprecation")
+ String host = channel.getHost();
+
+ if (host != null)
+ {
+ @SuppressWarnings("deprecation")
+ int rtpPort = channel.getRTPPort();
+ @SuppressWarnings("deprecation")
+ int rtcpPort = channel.getRTCPPort();
+
+ streamTarget
+ = new MediaStreamTarget(
+ new InetSocketAddress(host, rtpPort),
+ new InetSocketAddress(host, rtcpPort));
+ }
+ }
+ }
+ return streamTarget;
+ }
+
+ /**
+ * Implements {@link TransportManagerJabberImpl#getXmlNamespace()}. Gets the
+ * XML namespace of the Jingle transport implemented by this
+ * <tt>TransportManagerJabberImpl</tt>.
+ *
+ * @return the XML namespace of the Jingle transport implemented by this
+ * <tt>TransportManagerJabberImpl</tt>
+ * @see TransportManagerJabberImpl#getXmlNamespace()
+ */
+ @Override
+ public String getXmlNamespace()
+ {
+ return ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RAW_UDP_0;
+ }
+
+ /**
+ * Removes a content with a specific name from the transport-related part of
+ * the session represented by this <tt>TransportManagerJabberImpl</tt> which
+ * may have been reported through previous calls to the
+ * <tt>startCandidateHarvest</tt> and
+ * <tt>startConnectivityEstablishment</tt> methods.
+ *
+ * @param name the name of the content to be removed from the
+ * transport-related part of the session represented by this
+ * <tt>TransportManagerJabberImpl</tt>
+ * @see TransportManagerJabberImpl#removeContent(String)
+ */
+ @Override
+ public void removeContent(String name)
+ {
+ if (local != null)
+ removeContent(local, name);
+
+ removeRemoteContent(name);
+ }
+
+ /**
+ * Removes a content with a specific name from the remote counterpart of the
+ * negotiation between the local and the remote peers.
+ *
+ * @param name the name of the content to be removed from the remote
+ * counterpart of the negotiation between the local and the remote peers
+ */
+ private void removeRemoteContent(String name)
+ {
+ for (Iterator<Iterable<ContentPacketExtension>> remoteIter
+ = remotes.iterator();
+ remoteIter.hasNext();)
+ {
+ Iterable<ContentPacketExtension> remote = remoteIter.next();
+
+ /*
+ * Once the remote content is removed, make sure that we are not
+ * retaining sets which do not have any contents.
+ */
+ if ((removeContent(remote, name) != null)
+ && !remote.iterator().hasNext())
+ {
+ remoteIter.remove();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected PacketExtension startCandidateHarvest(
+ ContentPacketExtension theirContent,
+ ContentPacketExtension ourContent,
+ TransportInfoSender transportInfoSender,
+ String media)
+ throws OperationFailedException
+ {
+ return createTransportForStartCandidateHarvest(media);
+ }
+
+ /**
+ * Starts transport candidate harvest. This method should complete rapidly
+ * and, in case of lengthy procedures like STUN/TURN/UPnP candidate harvests
+ * are necessary, they should be executed in a separate thread. Candidate
+ * harvest would then need to be concluded in the
+ * {@link #wrapupCandidateHarvest()} method which would be called once we
+ * absolutely need the candidates.
+ *
+ * @param theirOffer a media description offer that we've received from the
+ * remote party and that we should use in case we need to know what
+ * transports our peer is using.
+ * @param ourAnswer the content descriptions that we should be adding our
+ * transport lists to (although not necessarily in this very instance).
+ * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by
+ * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt>
+ * <tt>JingleIQ</tt>s from the local peer to the remote peer if this
+ * <tt>TransportManagerJabberImpl</tt> wishes to utilize
+ * <tt>transport-info</tt>. Local candidate addresses sent by this
+ * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are
+ * expected to not be included in the result of
+ * {@link #wrapupCandidateHarvest()}.
+ *
+ * @throws OperationFailedException if we fail to allocate a port number.
+ * @see TransportManagerJabberImpl#startCandidateHarvest(List, List,
+ * TransportInfoSender)
+ */
+ @Override
+ public void startCandidateHarvest(
+ List<ContentPacketExtension> theirOffer,
+ List<ContentPacketExtension> ourAnswer,
+ TransportInfoSender transportInfoSender)
+ throws OperationFailedException
+ {
+ this.local = ourAnswer;
+
+ super.startCandidateHarvest(theirOffer, ourAnswer, transportInfoSender);
+ }
+
+ /**
+ * Overrides the super implementation in order to remember the remote
+ * counterpart of the negotiation between the local and the remote peer for
+ * subsequent calls to {@link #getStreamTarget(MediaType)}.
+ *
+ * @param remote the collection of <tt>ContentPacketExtension</tt>s which
+ * represents the remote counterpart of the negotiation between the local
+ * and the remote peer
+ * @return <tt>true</tt> because <tt>RawUdpTransportManager</tt> does not
+ * perform connectivity checks
+ * @see TransportManagerJabberImpl#startConnectivityEstablishment(Iterable)
+ */
+ @Override
+ public boolean startConnectivityEstablishment(
+ Iterable<ContentPacketExtension> remote)
+ {
+ if ((remote != null) && !remotes.contains(remote))
+ {
+ /*
+ * The state of the session in Jingle is maintained by each peer and
+ * is modified by content-add and content-remove. The remotes field
+ * of this RawUdpTransportManager represents the state of the
+ * session with respect to the remote peer. When the remote peer
+ * tells us about a specific set of contents, make sure that it is
+ * the only record we will have with respect to the specified set of
+ * contents.
+ */
+ for (ContentPacketExtension content : remote)
+ removeRemoteContent(content.getName());
+
+ remotes.add(remote);
+ }
+
+ return super.startConnectivityEstablishment(remote);
+ }
+
+ /**
+ * Simply returns the list of local candidates that we gathered during the
+ * harvest. This is a raw UDP transport manager so there's no real wrapping
+ * up to do.
+ *
+ * @return the list of local candidates that we gathered during the harvest
+ * @see TransportManagerJabberImpl#wrapupCandidateHarvest()
+ */
+ @Override
+ public List<ContentPacketExtension> wrapupCandidateHarvest()
+ {
+ return local;
+ }
+
+ /**
+ * Returns the extended type of the candidate selected if this transport
+ * manager is using ICE.
+ *
+ * @param streamName The stream name (AUDIO, VIDEO);
+ *
+ * @return The extended type of the candidate selected if this transport
+ * manager is using ICE. Otherwise, returns null.
+ */
+ @Override
+ public String getICECandidateExtendedType(String streamName)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the current state of ICE processing.
+ *
+ * @return the current state of ICE processing.
+ */
+ @Override
+ public String getICEState()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the ICE local host address.
+ *
+ * @param streamName The stream name (AUDIO, VIDEO);
+ *
+ * @return the ICE local host address if this transport
+ * manager is using ICE. Otherwise, returns null.
+ */
+ @Override
+ public InetSocketAddress getICELocalHostAddress(String streamName)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the ICE remote host address.
+ *
+ * @param streamName The stream name (AUDIO, VIDEO);
+ *
+ * @return the ICE remote host address if this transport
+ * manager is using ICE. Otherwise, returns null.
+ */
+ @Override
+ public InetSocketAddress getICERemoteHostAddress(String streamName)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the ICE local reflexive address (server or peer reflexive).
+ *
+ * @param streamName The stream name (AUDIO, VIDEO);
+ *
+ * @return the ICE local reflexive address. May be null if this transport
+ * manager is not using ICE or if there is no reflexive address for the
+ * local candidate used.
+ */
+ @Override
+ public InetSocketAddress getICELocalReflexiveAddress(String streamName)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the ICE remote reflexive address (server or peer reflexive).
+ *
+ * @param streamName The stream name (AUDIO, VIDEO);
+ *
+ * @return the ICE remote reflexive address. May be null if this transport
+ * manager is not using ICE or if there is no reflexive address for the
+ * remote candidate used.
+ */
+ @Override
+ public InetSocketAddress getICERemoteReflexiveAddress(String streamName)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the ICE local relayed address (server or peer relayed).
+ *
+ * @param streamName The stream name (AUDIO, VIDEO);
+ *
+ * @return the ICE local relayed address. May be null if this transport
+ * manager is not using ICE or if there is no relayed address for the
+ * local candidate used.
+ */
+ @Override
+ public InetSocketAddress getICELocalRelayedAddress(String streamName)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the ICE remote relayed address (server or peer relayed).
+ *
+ * @param streamName The stream name (AUDIO, VIDEO);
+ *
+ * @return the ICE remote relayed address. May be null if this transport
+ * manager is not using ICE or if there is no relayed address for the
+ * remote candidate used.
+ */
+ @Override
+ public InetSocketAddress getICERemoteRelayedAddress(String streamName)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the total harvesting time (in ms) for all harvesters.
+ *
+ * @return The total harvesting time (in ms) for all the harvesters. 0 if
+ * the ICE agent is null, or if the agent has nevers harvested.
+ */
+ @Override
+ public long getTotalHarvestingTime()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the harvesting time (in ms) for the harvester given in parameter.
+ *
+ * @param harvesterName The class name if the harvester.
+ *
+ * @return The harvesting time (in ms) for the harvester given in parameter.
+ * 0 if this harvester does not exists, if the ICE agent is null, or if the
+ * agent has never harvested with this harvester.
+ */
+ @Override
+ public long getHarvestingTime(String harvesterName)
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the number of harvesting for this agent.
+ *
+ * @return The number of harvesting for this agent.
+ */
+ @Override
+ public int getNbHarvesting()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the number of harvesting time for the harvester given in
+ * parameter.
+ *
+ * @param harvesterName The class name if the harvester.
+ *
+ * @return The number of harvesting time for the harvester given in
+ * parameter.
+ */
+ @Override
+ public int getNbHarvesting(String harvesterName)
+ {
+ return 0;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ScServiceDiscoveryManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/ScServiceDiscoveryManager.java
index 9fdbea5..de2ce3e 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ScServiceDiscoveryManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ScServiceDiscoveryManager.java
@@ -27,6 +27,7 @@ import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.filter.*;
import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.*;
import org.jivesoftware.smackx.packet.*;
@@ -79,9 +80,9 @@ public class ScServiceDiscoveryManager
private final ProtocolProviderService parentProvider;
/**
- * The {@link XMPPConnection} that this manager is responsible for.
+ * The {@link Connection} that this manager is responsible for.
*/
- private final XMPPConnection connection;
+ private final Connection connection;
/**
* A local copy that we keep in sync with {@link ServiceDiscoveryManager}'s
@@ -129,7 +130,7 @@ public class ScServiceDiscoveryManager
*/
public ScServiceDiscoveryManager(
ProtocolProviderService parentProvider,
- XMPPConnection connection,
+ Connection connection,
String[] featuresToRemove,
String[] featuresToAdd,
boolean cacheNonCaps)
@@ -791,7 +792,11 @@ public class ScServiceDiscoveryManager
// fire event
if(fireEvent && capabilitiesOpSet != null)
{
- capabilitiesOpSet.fireContactCapabilitiesChanged(entityID);
+ capabilitiesOpSet.fireContactCapabilitiesChanged(
+ entityID,
+ capsManager.getFullJidsByBareJid(
+ StringUtils.parseBareAddress(entityID))
+ );
}
}
catch(XMPPException ex)
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/SmackV3InteroperabilityLayer.java b/src/net/java/sip/communicator/impl/protocol/jabber/SmackV3InteroperabilityLayer.java
new file mode 100644
index 0000000..d5af26f
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/SmackV3InteroperabilityLayer.java
@@ -0,0 +1,91 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import net.java.sip.communicator.service.protocol.jabber.*;
+import org.jivesoftware.smack.provider.*;
+
+/**
+ * Smack v3 interoperation layer
+ *
+ * @author Maksym Kulish
+ */
+public class SmackV3InteroperabilityLayer
+ extends AbstractSmackInteroperabilityLayer
+{
+
+ /**
+ * A SmackV3 ProviderManager instance
+ */
+ private ProviderManager providerManager = ProviderManager.getInstance();
+
+ /**
+ * A default constructor
+ */
+ public SmackV3InteroperabilityLayer() {}
+
+ /**
+ * Add <tt>PacketExtensionProvider</tt> to the list of known
+ * providers
+ *
+ * @param elementName The element name where the matching is happening
+ * @param namespace The XML namespace used in that element
+ * @param provider <tt>PacketExtensionProvider</tt> implementation to be
+ * used
+ */
+ @Override
+ public void addExtensionProvider(
+ String elementName, String namespace, Object provider)
+ {
+ providerManager.addExtensionProvider(elementName, namespace, provider);
+ }
+
+ /**
+ * Add <tt>IQProvider</tt> to the list of known
+ * providers
+ *
+ * @param elementName The element name where the matching is happening
+ * @param namespace The XML namespace used in that element
+ * @param provider <tt>IQProvider</tt> implementation to be
+ * used
+ */
+ @Override
+ public void addIQProvider(
+ String elementName, String namespace, Object provider)
+ {
+ providerManager.addIQProvider(elementName, namespace, provider);
+ }
+
+ /**
+ * Get the <tt>PacketExtensionProvider</tt> for given element name and XML
+ * namespace
+ *
+ * @param elementName The element name where the matching is happening
+ * @param namespace The XML namespace used in that element
+ * @return <tt>PacketExtensionProvider</tt> implementation to be
+ * used
+ */
+ @Override
+ public PacketExtensionProvider getExtensionProvider(
+ String elementName, String namespace)
+ {
+ return (PacketExtensionProvider)providerManager
+ .getExtensionProvider(elementName, namespace);
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java
index f7f47c6..41e8c05 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/TransportManagerJabberImpl.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,963 +15,963 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.jabber;
-
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
-import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
-import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.media.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.neomedia.*;
-import org.jivesoftware.smack.packet.*;
-
-/**
- * <tt>TransportManager</tt>s gather local candidates for incoming and outgoing
- * calls. Their work starts by calling a start method which, using the remote
- * peer's session description, would start the harvest. Calling a second wrapup
- * method would deliver the candidate harvest, possibly after blocking if it has
- * not yet completed.
- *
- * @author Emil Ivov
- * @author Lyubomir Marinov
- */
-public abstract class TransportManagerJabberImpl
- extends TransportManager<CallPeerJabberImpl>
-{
- /**
- * The <tt>Logger</tt> used by the <tt>TransportManagerJabberImpl</tt> class
- * and its instances to print debug messages.
- */
- private static final Logger logger
- = Logger.getLogger(TransportManagerJabberImpl.class);
-
- /**
- * The ID that we will be assigning to our next candidate. We use
- * <tt>int</tt>s for interoperability reasons (Emil: I believe that GTalk
- * uses <tt>int</tt>s. If that turns out not to be the case we can stop
- * using <tt>int</tt>s here if that's an issue).
- */
- private static int nextID = 1;
-
- /**
- * The information pertaining to the Jisti Videobridge conference which the
- * local peer represented by this instance is a focus of. It gives a view of
- * the whole Jitsi Videobridge conference managed by the associated
- * <tt>CallJabberImpl</tt> which provides information specific to this
- * <tt>TransportManager</tt> only.
- */
- private ColibriConferenceIQ colibri;
-
- /**
- * The generation of the candidates we are currently generating
- */
- private int currentGeneration = 0;
-
- /**
- * The indicator which determines whether this <tt>TransportManager</tt>
- * instance is responsible to establish the connectivity with the associated
- * Jitsi Videobridge (in case it is being employed at all).
- */
- boolean isEstablishingConnectivityWithJitsiVideobridge = false;
-
- /**
- * The indicator which determines whether this <tt>TransportManager</tt>
- * instance is yet to start establishing the connectivity with the
- * associated Jitsi Videobridge (in case it is being employed at all).
- */
- boolean startConnectivityEstablishmentWithJitsiVideobridge = false;
-
- /**
- * Creates a new instance of this transport manager, binding it to the
- * specified peer.
- *
- * @param callPeer the {@link CallPeer} whose traffic we will be taking
- * care of.
- */
- protected TransportManagerJabberImpl(CallPeerJabberImpl callPeer)
- {
- super(callPeer);
- }
-
- /**
- * Returns the <tt>InetAddress</tt> that is most likely to be to be used
- * as a next hop when contacting the specified <tt>destination</tt>. This is
- * an utility method that is used whenever we have to choose one of our
- * local addresses to put in the Via, Contact or (in the case of no
- * registrar accounts) From headers.
- *
- * @param peer the CallPeer that we would contact.
- *
- * @return the <tt>InetAddress</tt> that is most likely to be to be used
- * as a next hop when contacting the specified <tt>destination</tt>.
- *
- * @throws IllegalArgumentException if <tt>destination</tt> is not a valid
- * host/IP/FQDN
- */
- @Override
- protected InetAddress getIntendedDestination(CallPeerJabberImpl peer)
- {
- return peer.getProtocolProvider().getNextHop();
- }
-
- /**
- * Returns the ID that we will be assigning to the next candidate we create.
- *
- * @return the next ID to use with a candidate.
- */
- protected String getNextID()
- {
- int nextID;
-
- synchronized (TransportManagerJabberImpl.class)
- {
- nextID = TransportManagerJabberImpl.nextID++;
- }
- return Integer.toString(nextID);
- }
-
- /**
- * Gets the <tt>MediaStreamTarget</tt> to be used as the <tt>target</tt> of
- * the <tt>MediaStream</tt> with a specific <tt>MediaType</tt>.
- *
- * @param mediaType the <tt>MediaType</tt> of the <tt>MediaStream</tt> which
- * is to have its <tt>target</tt> set to the returned
- * <tt>MediaStreamTarget</tt>
- * @return the <tt>MediaStreamTarget</tt> to be used as the <tt>target</tt>
- * of the <tt>MediaStream</tt> with the specified <tt>MediaType</tt>
- */
- public abstract MediaStreamTarget getStreamTarget(MediaType mediaType);
-
- /**
- * Gets the XML namespace of the Jingle transport implemented by this
- * <tt>TransportManagerJabberImpl</tt>.
- *
- * @return the XML namespace of the Jingle transport implemented by this
- * <tt>TransportManagerJabberImpl</tt>
- */
- public abstract String getXmlNamespace();
-
- /**
- * Returns the generation that our current candidates belong to.
- *
- * @return the generation that we should assign to candidates that we are
- * currently advertising.
- */
- protected int getCurrentGeneration()
- {
- return currentGeneration;
- }
-
- /**
- * Increments the generation that we are assigning candidates.
- */
- protected void incrementGeneration()
- {
- currentGeneration++;
- }
-
- /**
- * Sends transport-related information received from the remote peer to the
- * associated Jiitsi Videobridge in order to update the (remote)
- * <tt>ColibriConferenceIQ.Channel</tt> associated with this
- * <tt>TransportManager</tt> instance.
- *
- * @param map a <tt>Map</tt> of media-IceUdpTransportPacketExtension pairs
- * which represents the transport-related information which has been
- * received from the remote peer and which is to be sent to the associated
- * Jitsi Videobridge
- */
- protected void sendTransportInfoToJitsiVideobridge(
- Map<String,IceUdpTransportPacketExtension> map)
- {
- CallPeerJabberImpl peer = getCallPeer();
- boolean initiator = !peer.isInitiator();
- ColibriConferenceIQ conferenceRequest = null;
-
- for (Map.Entry<String,IceUdpTransportPacketExtension> e
- : map.entrySet())
- {
- String media = e.getKey();
- MediaType mediaType = MediaType.parseString(media);
- ColibriConferenceIQ.Channel channel
- = getColibriChannel(mediaType, false /* remote */);
-
- if (channel != null)
- {
- IceUdpTransportPacketExtension transport;
-
- try
- {
- transport = cloneTransportAndCandidates(e.getValue());
- }
- catch (OperationFailedException ofe)
- {
- transport = null;
- }
- if (transport == null)
- continue;
-
- ColibriConferenceIQ.Channel channelRequest
- = new ColibriConferenceIQ.Channel();
-
- channelRequest.setID(channel.getID());
- channelRequest.setInitiator(initiator);
- channelRequest.setTransport(transport);
-
- if (conferenceRequest == null)
- {
- if (colibri == null)
- break;
- else
- {
- String id = colibri.getID();
-
- if ((id == null) || (id.length() == 0))
- break;
- else
- {
- conferenceRequest = new ColibriConferenceIQ();
- conferenceRequest.setID(id);
- conferenceRequest.setTo(colibri.getFrom());
- conferenceRequest.setType(IQ.Type.SET);
- }
- }
- }
- conferenceRequest.getOrCreateContent(media).addChannel(
- channelRequest);
- }
- }
- if (conferenceRequest != null)
- {
- peer.getProtocolProvider().getConnection().sendPacket(
- conferenceRequest);
- }
- }
-
- /**
- * Starts transport candidate harvest for a specific
- * <tt>ContentPacketExtension</tt> that we are going to offer or answer
- * with.
- *
- * @param theirContent the <tt>ContentPacketExtension</tt> offered by the
- * remote peer to which we are going to answer with <tt>ourContent</tt> or
- * <tt>null</tt> if <tt>ourContent</tt> will be an offer to the remote peer
- * @param ourContent the <tt>ContentPacketExtension</tt> for which transport
- * candidate harvest is to be started
- * @param transportInfoSender a <tt>TransportInfoSender</tt> if the
- * harvested transport candidates are to be sent in a
- * <tt>transport-info</tt> rather than in <tt>ourContent</tt>; otherwise,
- * <tt>null</tt>
- * @param media the media of the <tt>RtpDescriptionPacketExtension</tt>
- * child of <tt>ourContent</tt>
- * @return a <tt>PacketExtension</tt> to be added as a child to
- * <tt>ourContent</tt>; otherwise, <tt>null</tt>
- * @throws OperationFailedException if anything goes wrong while starting
- * transport candidate harvest for the specified <tt>ourContent</tt>
- */
- protected abstract PacketExtension startCandidateHarvest(
- ContentPacketExtension theirContent,
- ContentPacketExtension ourContent,
- TransportInfoSender transportInfoSender,
- String media)
- throws OperationFailedException;
-
- /**
- * Starts transport candidate harvest. This method should complete rapidly
- * and, in case of lengthy procedures like STUN/TURN/UPnP candidate harvests
- * are necessary, they should be executed in a separate thread. Candidate
- * harvest would then need to be concluded in the
- * {@link #wrapupCandidateHarvest()} method which would be called once we
- * absolutely need the candidates.
- *
- * @param theirOffer a media description offer that we've received from the
- * remote party and that we should use in case we need to know what
- * transports our peer is using.
- * @param ourAnswer the content descriptions that we should be adding our
- * transport lists to (although not necessarily in this very instance).
- * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by
- * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt>
- * <tt>JingleIQ</tt>s from the local peer to the remote peer if this
- * <tt>TransportManagerJabberImpl</tt> wishes to utilize
- * <tt>transport-info</tt>. Local candidate addresses sent by this
- * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are
- * expected to not be included in the result of
- * {@link #wrapupCandidateHarvest()}.
- *
- * @throws OperationFailedException if we fail to allocate a port number.
- */
- public void startCandidateHarvest(
- List<ContentPacketExtension> theirOffer,
- List<ContentPacketExtension> ourAnswer,
- TransportInfoSender transportInfoSender)
- throws OperationFailedException
- {
- CallPeerJabberImpl peer = getCallPeer();
- CallJabberImpl call = peer.getCall();
- boolean isJitsiVideobridge = call.getConference().isJitsiVideobridge();
- List<ContentPacketExtension> cpes
- = (theirOffer == null) ? ourAnswer : theirOffer;
-
- /*
- * If Jitsi Videobridge is to be used, determine which channels are to
- * be allocated and attempt to allocate them now.
- */
- if (isJitsiVideobridge)
- {
- Map<ContentPacketExtension,ContentPacketExtension> contentMap
- = new LinkedHashMap
- <ContentPacketExtension,ContentPacketExtension>();
-
- for (ContentPacketExtension cpe : cpes)
- {
- MediaType mediaType = JingleUtils.getMediaType(cpe);
-
- /*
- * The existence of a content for the mediaType and regardless
- * of the existence of channels in it signals that a channel
- * allocation request has already been sent for that mediaType.
- */
- if ((colibri == null)
- || (colibri.getContent(mediaType.toString()) == null))
- {
- ContentPacketExtension local, remote;
-
- if (cpes == ourAnswer)
- {
- local = cpe;
- remote
- = (theirOffer == null)
- ? null
- : findContentByName(theirOffer, cpe.getName());
- }
- else
- {
- local = findContentByName(ourAnswer, cpe.getName());
- remote = cpe;
- }
- contentMap.put(local, remote);
- }
- }
- if (!contentMap.isEmpty())
- {
- /*
- * We are about to request the channel allocations for the media
- * types found in contentMap. Regardless of the response, we do
- * not want to repeat these requests.
- */
- if (colibri == null)
- colibri = new ColibriConferenceIQ();
- for (Map.Entry<ContentPacketExtension,ContentPacketExtension> e
- : contentMap.entrySet())
- {
- ContentPacketExtension cpe = e.getValue();
-
- if (cpe == null)
- cpe = e.getKey();
-
- colibri.getOrCreateContent(
- JingleUtils.getMediaType(cpe).toString());
- }
-
- ColibriConferenceIQ conferenceResult
- = call.createColibriChannels(peer, contentMap);
-
- if (conferenceResult != null)
- {
- String videobridgeID = colibri.getID();
- String conferenceResultID = conferenceResult.getID();
-
- if (videobridgeID == null)
- colibri.setID(conferenceResultID);
- else if (!videobridgeID.equals(conferenceResultID))
- throw new IllegalStateException("conference.id");
-
- String videobridgeFrom = conferenceResult.getFrom();
-
- if ((videobridgeFrom != null)
- && (videobridgeFrom.length() != 0))
- {
- colibri.setFrom(videobridgeFrom);
- }
-
- for (ColibriConferenceIQ.Content contentResult
- : conferenceResult.getContents())
- {
- ColibriConferenceIQ.Content content
- = colibri.getOrCreateContent(
- contentResult.getName());
-
- for (ColibriConferenceIQ.Channel channelResult
- : contentResult.getChannels())
- {
- if (content.getChannel(channelResult.getID())
- == null)
- {
- content.addChannel(channelResult);
- }
- }
- }
- }
- else
- {
- /*
- * The call fails if the createColibriChannels method fails
- * which may happen if the conference packet times out or it
- * can't be built.
- */
- ProtocolProviderServiceJabberImpl
- .throwOperationFailedException(
- "Failed to allocate colibri channel.",
- OperationFailedException.GENERAL_ERROR,
- null,
- logger);
- }
- }
- }
-
- for (ContentPacketExtension cpe : cpes)
- {
- String contentName = cpe.getName();
- ContentPacketExtension ourContent
- = findContentByName(ourAnswer, contentName);
-
- //it might be that we decided not to reply to this content
- if (ourContent != null)
- {
- ContentPacketExtension theirContent
- = (theirOffer == null)
- ? null
- : findContentByName(theirOffer, contentName);
- RtpDescriptionPacketExtension rtpDesc
- = ourContent.getFirstChildOfType(
- RtpDescriptionPacketExtension.class);
- String media = rtpDesc.getMedia();
- PacketExtension pe
- = startCandidateHarvest(
- theirContent,
- ourContent,
- transportInfoSender,
- media);
-
- if (pe != null)
- ourContent.addChildExtension(pe);
- }
- }
- }
-
- /**
- * Starts transport candidate harvest. This method should complete rapidly
- * and, in case of lengthy procedures like STUN/TURN/UPnP candidate harvests
- * are necessary, they should be executed in a separate thread. Candidate
- * harvest would then need to be concluded in the
- * {@link #wrapupCandidateHarvest()} method which would be called once we
- * absolutely need the candidates.
- *
- * @param ourOffer the content descriptions that we should be adding our
- * transport lists to (although not necessarily in this very instance).
- * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by
- * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt>
- * <tt>JingleIQ</tt>s from the local peer to the remote peer if this
- * <tt>TransportManagerJabberImpl</tt> wishes to utilize
- * <tt>transport-info</tt>. Local candidate addresses sent by this
- * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are
- * expected to not be included in the result of
- * {@link #wrapupCandidateHarvest()}.
- * @throws OperationFailedException if we fail to allocate a port number.
- */
- public void startCandidateHarvest(
- List<ContentPacketExtension> ourOffer,
- TransportInfoSender transportInfoSender)
- throws OperationFailedException
- {
- startCandidateHarvest(
- /* theirOffer */ null,
- ourOffer,
- transportInfoSender);
- }
-
- /**
- * Notifies the transport manager that it should conclude candidate
- * harvesting as soon as possible and return the lists of candidates
- * gathered so far.
- *
- * @return the content list that we received earlier (possibly cloned into
- * a new instance) and that we have updated with transport lists.
- */
- public abstract List<ContentPacketExtension> wrapupCandidateHarvest();
-
- /**
- * Looks through the <tt>cpExtList</tt> and returns the {@link
- * ContentPacketExtension} with the specified name.
- *
- * @param cpExtList the list that we will be searching for a specific
- * content.
- * @param name the name of the content element we are looking for.
- * @return the {@link ContentPacketExtension} with the specified name or
- * <tt>null</tt> if no such content element exists.
- */
- public static ContentPacketExtension findContentByName(
- Iterable<ContentPacketExtension> cpExtList,
- String name)
- {
- for(ContentPacketExtension cpExt : cpExtList)
- {
- if(cpExt.getName().equals(name))
- return cpExt;
- }
- return null;
- }
-
- /**
- * Starts the connectivity establishment of this
- * <tt>TransportManagerJabberImpl</tt> i.e. checks the connectivity between
- * the local and the remote peers given the remote counterpart of the
- * negotiation between them.
- *
- * @param remote the collection of <tt>ContentPacketExtension</tt>s which
- * represents the remote counterpart of the negotiation between the local
- * and the remote peer
- * @return <tt>true</tt> if connectivity establishment has been started in
- * response to the call; otherwise, <tt>false</tt>.
- * <tt>TransportManagerJabberImpl</tt> implementations which do not perform
- * connectivity checks (e.g. raw UDP) should return <tt>true</tt>. The
- * default implementation does not perform connectivity checks and always
- * returns <tt>true</tt>.
- */
- public boolean startConnectivityEstablishment(
- Iterable<ContentPacketExtension> remote)
- {
- return true;
- }
-
- /**
- * Starts the connectivity establishment of this
- * <tt>TransportManagerJabberImpl</tt> i.e. checks the connectivity between
- * the local and the remote peers given the remote counterpart of the
- * negotiation between them.
- *
- * @param remote a <tt>Map</tt> of
- * media-<tt>IceUdpTransportPacketExtension</tt> pairs which represents the
- * remote counterpart of the negotiation between the local and the remote
- * peers
- * @return <tt>true</tt> if connectivity establishment has been started in
- * response to the call; otherwise, <tt>false</tt>.
- * <tt>TransportManagerJabberImpl</tt> implementations which do not perform
- * connectivity checks (e.g. raw UDP) should return <tt>true</tt>. The
- * default implementation does not perform connectivity checks and always
- * returns <tt>true</tt>.
- */
- protected boolean startConnectivityEstablishment(
- Map<String,IceUdpTransportPacketExtension> remote)
- {
- return true;
- }
-
- /**
- * Notifies this <tt>TransportManagerJabberImpl</tt> that it should conclude
- * any started connectivity establishment.
- *
- * @throws OperationFailedException if anything goes wrong with connectivity
- * establishment (i.e. ICE failed, ...)
- */
- public void wrapupConnectivityEstablishment()
- throws OperationFailedException
- {
- }
-
- /**
- * Removes a content with a specific name from the transport-related part of
- * the session represented by this <tt>TransportManagerJabberImpl</tt> which
- * may have been reported through previous calls to the
- * <tt>startCandidateHarvest</tt> and
- * <tt>startConnectivityEstablishment</tt> methods.
- * <p>
- * <b>Note</b>: Because <tt>TransportManager</tt> deals with
- * <tt>MediaType</tt>s, not content names and
- * <tt>TransportManagerJabberImpl</tt> does not implement translating from
- * content name to <tt>MediaType</tt>, implementers are expected to call
- * {@link TransportManager#closeStreamConnector(MediaType)}.
- * </p>
- *
- * @param name the name of the content to be removed from the
- * transport-related part of the session represented by this
- * <tt>TransportManagerJabberImpl</tt>
- */
- public abstract void removeContent(String name);
-
- /**
- * Removes a content with a specific name from a specific collection of
- * contents and closes any associated <tt>StreamConnector</tt>.
- *
- * @param contents the collection of contents to remove the content with the
- * specified name from
- * @param name the name of the content to remove
- * @return the removed <tt>ContentPacketExtension</tt> if any; otherwise,
- * <tt>null</tt>
- */
- protected ContentPacketExtension removeContent(
- Iterable<ContentPacketExtension> contents,
- String name)
- {
- for (Iterator<ContentPacketExtension> contentIter = contents.iterator();
- contentIter.hasNext();)
- {
- ContentPacketExtension content = contentIter.next();
-
- if (name.equals(content.getName()))
- {
- contentIter.remove();
-
- // closeStreamConnector
- MediaType mediaType = JingleUtils.getMediaType(content);
- if (mediaType != null)
- {
- closeStreamConnector(mediaType);
- }
-
- return content;
- }
- }
- return null;
- }
-
- /**
- * Clones a specific <tt>IceUdpTransportPacketExtension</tt> and its
- * candidates.
- *
- * @param src the <tt>IceUdpTransportPacketExtension</tt> to be cloned
- * @return a new <tt>IceUdpTransportPacketExtension</tt> instance which has
- * the same run-time type, attributes, namespace, text and candidates as the
- * specified <tt>src</tt>
- * @throws OperationFailedException if an error occurs during the cloing of
- * the specified <tt>src</tt> and its candidates
- */
- static IceUdpTransportPacketExtension cloneTransportAndCandidates(
- IceUdpTransportPacketExtension src)
- throws OperationFailedException
- {
- try
- {
- return IceUdpTransportPacketExtension
- .cloneTransportAndCandidates(src);
- }
- catch (Exception e)
- {
- ProtocolProviderServiceJabberImpl
- .throwOperationFailedException(
- "Failed to close transport and candidates.",
- OperationFailedException.GENERAL_ERROR,
- e,
- logger);
-
- }
- return null;
- }
-
- /**
- * Releases the resources acquired by this <tt>TransportManager</tt> and
- * prepares it for garbage collection.
- */
- public void close()
- {
- for (MediaType mediaType : MediaType.values())
- closeStreamConnector(mediaType);
- }
-
- /**
- * Closes a specific <tt>StreamConnector</tt> associated with a specific
- * <tt>MediaType</tt>. If this <tt>TransportManager</tt> has a reference to
- * the specified <tt>streamConnector</tt>, it remains.
- * Also expires the <tt>ColibriConferenceIQ.Channel</tt> associated with
- * the closed <tt>StreamConnector</tt>.
- *
- * @param mediaType the <tt>MediaType</tt> associated with the specified
- * <tt>streamConnector</tt>
- * @param streamConnector the <tt>StreamConnector</tt> to be closed
- */
- @Override
- protected void closeStreamConnector(
- MediaType mediaType,
- StreamConnector streamConnector)
- {
- try
- {
- boolean superCloseStreamConnector = true;
-
- if (streamConnector instanceof ColibriStreamConnector)
- {
- CallPeerJabberImpl peer = getCallPeer();
-
- if (peer != null)
- {
- CallJabberImpl call = peer.getCall();
-
- if (call != null)
- {
- superCloseStreamConnector = false;
- call.closeColibriStreamConnector(
- peer,
- mediaType,
- (ColibriStreamConnector) streamConnector);
- }
- }
- }
- if (superCloseStreamConnector)
- super.closeStreamConnector(mediaType, streamConnector);
- }
- finally
- {
- /*
- * Expire the ColibriConferenceIQ.Channel associated with the closed
- * StreamConnector.
- */
- if (colibri != null)
- {
- ColibriConferenceIQ.Content content
- = colibri.getContent(mediaType.toString());
-
- if (content != null)
- {
- List<ColibriConferenceIQ.Channel> channels
- = content.getChannels();
-
- if (channels.size() == 2)
- {
- ColibriConferenceIQ requestConferenceIQ
- = new ColibriConferenceIQ();
-
- requestConferenceIQ.setID(colibri.getID());
-
- ColibriConferenceIQ.Content requestContent
- = requestConferenceIQ.getOrCreateContent(
- content.getName());
-
- requestContent.addChannel(channels.get(1 /* remote */));
-
- /*
- * Regardless of whether the request to expire the
- * Channel associated with mediaType succeeds, consider
- * the Channel in question expired. Since
- * RawUdpTransportManager allocates a single channel per
- * MediaType, consider the whole Content expired.
- */
- colibri.removeContent(content);
-
- CallPeerJabberImpl peer = getCallPeer();
-
- if (peer != null)
- {
- CallJabberImpl call = peer.getCall();
-
- if (call != null)
- {
- call.expireColibriChannels(
- peer,
- requestConferenceIQ);
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * Adds support for telephony conferences utilizing the Jitsi Videobridge
- * server-side technology.
- *
- * @see #doCreateStreamConnector(MediaType)
- */
- @Override
- protected StreamConnector createStreamConnector(final MediaType mediaType)
- throws OperationFailedException
- {
- ColibriConferenceIQ.Channel channel
- = getColibriChannel(mediaType, true /* local */);
-
- if (channel != null)
- {
- CallPeerJabberImpl peer = getCallPeer();
- CallJabberImpl call = peer.getCall();
- StreamConnector streamConnector
- = call.createColibriStreamConnector(
- peer,
- mediaType,
- channel,
- new StreamConnectorFactory()
- {
- public StreamConnector createStreamConnector()
- {
- try
- {
- return doCreateStreamConnector(mediaType);
- }
- catch (OperationFailedException ofe)
- {
- return null;
- }
- }
- });
-
- if (streamConnector != null)
- return streamConnector;
- }
-
- return doCreateStreamConnector(mediaType);
- }
-
- protected abstract PacketExtension createTransport(String media)
- throws OperationFailedException;
-
- protected PacketExtension createTransportForStartCandidateHarvest(
- String media)
- throws OperationFailedException
- {
- PacketExtension pe = null;
-
- if (getCallPeer().isJitsiVideobridge())
- {
- MediaType mediaType = MediaType.parseString(media);
- ColibriConferenceIQ.Channel channel
- = getColibriChannel(mediaType, false /* remote */);
-
- if (channel != null)
- pe = cloneTransportAndCandidates(channel.getTransport());
- }
- else
- pe = createTransport(media);
- return pe;
- }
-
- /**
- * Initializes a new <tt>PacketExtension</tt> instance appropriate to the
- * type of Jingle transport represented by this <tt>TransportManager</tt>.
- * The new instance is not initialized with any attributes or child
- * extensions.
- *
- * @return a new <tt>PacketExtension</tt> instance appropriate to the type
- * of Jingle transport represented by this <tt>TransportManager</tt>
- */
- protected abstract PacketExtension createTransportPacketExtension();
-
- /**
- * Creates a media <tt>StreamConnector</tt> for a stream of a specific
- * <tt>MediaType</tt>. The minimum and maximum of the media port boundaries
- * are taken into account.
- *
- * @param mediaType the <tt>MediaType</tt> of the stream for which a
- * <tt>StreamConnector</tt> is to be created
- * @return a <tt>StreamConnector</tt> for the stream of the specified
- * <tt>mediaType</tt>
- * @throws OperationFailedException if the binding of the sockets fails
- */
- protected StreamConnector doCreateStreamConnector(MediaType mediaType)
- throws OperationFailedException
- {
- return super.createStreamConnector(mediaType);
- }
-
- /**
- * Finds a <tt>TransportManagerJabberImpl</tt> participating in a telephony
- * conference utilizing the Jitsi Videobridge server-side technology that
- * this instance is participating in which is establishing the connectivity
- * with the Jitsi Videobridge server (as opposed to a <tt>CallPeer</tt>).
- *
- * @return a <tt>TransportManagerJabberImpl</tt> which is participating in
- * a telephony conference utilizing the Jitsi Videobridge server-side
- * technology that this instance is participating in which is establishing
- * the connectivity with the Jitsi Videobridge server (as opposed to a
- * <tt>CallPeer</tt>).
- */
- TransportManagerJabberImpl
- findTransportManagerEstablishingConnectivityWithJitsiVideobridge()
- {
- Call call = getCallPeer().getCall();
- TransportManagerJabberImpl transportManager = null;
-
- if (call != null)
- {
- CallConference conference = call.getConference();
-
- if ((conference != null) && conference.isJitsiVideobridge())
- {
- for (Call aCall : conference.getCalls())
- {
- Iterator<? extends CallPeer> callPeerIter
- = aCall.getCallPeers();
-
- while (callPeerIter.hasNext())
- {
- CallPeer aCallPeer = callPeerIter.next();
-
- if (aCallPeer instanceof CallPeerJabberImpl)
- {
- TransportManagerJabberImpl aTransportManager
- = ((CallPeerJabberImpl) aCallPeer)
- .getMediaHandler()
- .getTransportManager();
-
- if (aTransportManager
- .isEstablishingConnectivityWithJitsiVideobridge)
- {
- transportManager = aTransportManager;
- break;
- }
- }
- }
- }
- }
- }
- return transportManager;
- }
-
- /**
- * Gets the {@link ColibriConferenceIQ.Channel} which belongs to a content
- * associated with a specific <tt>MediaType</tt> and is to be either locally
- * or remotely used.
- * <p>
- * <b>Note</b>: Modifications to the <tt>ColibriConferenceIQ.Channel</tt>
- * instance returned by the method propagate to (the state of) this
- * instance.
- * </p>
- *
- * @param mediaType the <tt>MediaType</tt> associated with the content which
- * contains the <tt>ColibriConferenceIQ.Channel</tt> to get
- * @param local <tt>true</tt> if the <tt>ColibriConferenceIQ.Channel</tt>
- * which is to be used locally is to be returned or <tt>false</tt> for the
- * one which is to be used remotely
- * @return the <tt>ColibriConferenceIQ.Channel</tt> which belongs to a
- * content associated with the specified <tt>mediaType</tt> and which is to
- * be used in accord with the specified <tt>local</tt> indicator if such a
- * channel exists; otherwise, <tt>null</tt>
- */
- ColibriConferenceIQ.Channel getColibriChannel(
- MediaType mediaType,
- boolean local)
- {
- ColibriConferenceIQ.Channel channel = null;
-
- if (colibri != null)
- {
- ColibriConferenceIQ.Content content
- = colibri.getContent(mediaType.toString());
-
- if (content != null)
- {
- List<ColibriConferenceIQ.Channel> channels
- = content.getChannels();
-
- if (channels.size() == 2)
- channel = channels.get(local ? 0 : 1);
- }
- }
- return channel;
- }
-}
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import java.net.*;
+import java.util.*;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.media.*;
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.neomedia.*;
+import org.jivesoftware.smack.packet.*;
+
+/**
+ * <tt>TransportManager</tt>s gather local candidates for incoming and outgoing
+ * calls. Their work starts by calling a start method which, using the remote
+ * peer's session description, would start the harvest. Calling a second wrapup
+ * method would deliver the candidate harvest, possibly after blocking if it has
+ * not yet completed.
+ *
+ * @author Emil Ivov
+ * @author Lyubomir Marinov
+ */
+public abstract class TransportManagerJabberImpl
+ extends TransportManager<CallPeerJabberImpl>
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>TransportManagerJabberImpl</tt> class
+ * and its instances to print debug messages.
+ */
+ private static final Logger logger
+ = Logger.getLogger(TransportManagerJabberImpl.class);
+
+ /**
+ * The ID that we will be assigning to our next candidate. We use
+ * <tt>int</tt>s for interoperability reasons (Emil: I believe that GTalk
+ * uses <tt>int</tt>s. If that turns out not to be the case we can stop
+ * using <tt>int</tt>s here if that's an issue).
+ */
+ private static int nextID = 1;
+
+ /**
+ * The information pertaining to the Jisti Videobridge conference which the
+ * local peer represented by this instance is a focus of. It gives a view of
+ * the whole Jitsi Videobridge conference managed by the associated
+ * <tt>CallJabberImpl</tt> which provides information specific to this
+ * <tt>TransportManager</tt> only.
+ */
+ private ColibriConferenceIQ colibri;
+
+ /**
+ * The generation of the candidates we are currently generating
+ */
+ private int currentGeneration = 0;
+
+ /**
+ * The indicator which determines whether this <tt>TransportManager</tt>
+ * instance is responsible to establish the connectivity with the associated
+ * Jitsi Videobridge (in case it is being employed at all).
+ */
+ boolean isEstablishingConnectivityWithJitsiVideobridge = false;
+
+ /**
+ * The indicator which determines whether this <tt>TransportManager</tt>
+ * instance is yet to start establishing the connectivity with the
+ * associated Jitsi Videobridge (in case it is being employed at all).
+ */
+ boolean startConnectivityEstablishmentWithJitsiVideobridge = false;
+
+ /**
+ * Creates a new instance of this transport manager, binding it to the
+ * specified peer.
+ *
+ * @param callPeer the {@link CallPeer} whose traffic we will be taking
+ * care of.
+ */
+ protected TransportManagerJabberImpl(CallPeerJabberImpl callPeer)
+ {
+ super(callPeer);
+ }
+
+ /**
+ * Returns the <tt>InetAddress</tt> that is most likely to be to be used
+ * as a next hop when contacting the specified <tt>destination</tt>. This is
+ * an utility method that is used whenever we have to choose one of our
+ * local addresses to put in the Via, Contact or (in the case of no
+ * registrar accounts) From headers.
+ *
+ * @param peer the CallPeer that we would contact.
+ *
+ * @return the <tt>InetAddress</tt> that is most likely to be to be used
+ * as a next hop when contacting the specified <tt>destination</tt>.
+ *
+ * @throws IllegalArgumentException if <tt>destination</tt> is not a valid
+ * host/IP/FQDN
+ */
+ @Override
+ protected InetAddress getIntendedDestination(CallPeerJabberImpl peer)
+ {
+ return peer.getProtocolProvider().getNextHop();
+ }
+
+ /**
+ * Returns the ID that we will be assigning to the next candidate we create.
+ *
+ * @return the next ID to use with a candidate.
+ */
+ protected String getNextID()
+ {
+ int nextID;
+
+ synchronized (TransportManagerJabberImpl.class)
+ {
+ nextID = TransportManagerJabberImpl.nextID++;
+ }
+ return Integer.toString(nextID);
+ }
+
+ /**
+ * Gets the <tt>MediaStreamTarget</tt> to be used as the <tt>target</tt> of
+ * the <tt>MediaStream</tt> with a specific <tt>MediaType</tt>.
+ *
+ * @param mediaType the <tt>MediaType</tt> of the <tt>MediaStream</tt> which
+ * is to have its <tt>target</tt> set to the returned
+ * <tt>MediaStreamTarget</tt>
+ * @return the <tt>MediaStreamTarget</tt> to be used as the <tt>target</tt>
+ * of the <tt>MediaStream</tt> with the specified <tt>MediaType</tt>
+ */
+ public abstract MediaStreamTarget getStreamTarget(MediaType mediaType);
+
+ /**
+ * Gets the XML namespace of the Jingle transport implemented by this
+ * <tt>TransportManagerJabberImpl</tt>.
+ *
+ * @return the XML namespace of the Jingle transport implemented by this
+ * <tt>TransportManagerJabberImpl</tt>
+ */
+ public abstract String getXmlNamespace();
+
+ /**
+ * Returns the generation that our current candidates belong to.
+ *
+ * @return the generation that we should assign to candidates that we are
+ * currently advertising.
+ */
+ protected int getCurrentGeneration()
+ {
+ return currentGeneration;
+ }
+
+ /**
+ * Increments the generation that we are assigning candidates.
+ */
+ protected void incrementGeneration()
+ {
+ currentGeneration++;
+ }
+
+ /**
+ * Sends transport-related information received from the remote peer to the
+ * associated Jiitsi Videobridge in order to update the (remote)
+ * <tt>ColibriConferenceIQ.Channel</tt> associated with this
+ * <tt>TransportManager</tt> instance.
+ *
+ * @param map a <tt>Map</tt> of media-IceUdpTransportPacketExtension pairs
+ * which represents the transport-related information which has been
+ * received from the remote peer and which is to be sent to the associated
+ * Jitsi Videobridge
+ */
+ protected void sendTransportInfoToJitsiVideobridge(
+ Map<String,IceUdpTransportPacketExtension> map)
+ {
+ CallPeerJabberImpl peer = getCallPeer();
+ boolean initiator = !peer.isInitiator();
+ ColibriConferenceIQ conferenceRequest = null;
+
+ for (Map.Entry<String,IceUdpTransportPacketExtension> e
+ : map.entrySet())
+ {
+ String media = e.getKey();
+ MediaType mediaType = MediaType.parseString(media);
+ ColibriConferenceIQ.Channel channel
+ = getColibriChannel(mediaType, false /* remote */);
+
+ if (channel != null)
+ {
+ IceUdpTransportPacketExtension transport;
+
+ try
+ {
+ transport = cloneTransportAndCandidates(e.getValue());
+ }
+ catch (OperationFailedException ofe)
+ {
+ transport = null;
+ }
+ if (transport == null)
+ continue;
+
+ ColibriConferenceIQ.Channel channelRequest
+ = new ColibriConferenceIQ.Channel();
+
+ channelRequest.setID(channel.getID());
+ channelRequest.setInitiator(initiator);
+ channelRequest.setTransport(transport);
+
+ if (conferenceRequest == null)
+ {
+ if (colibri == null)
+ break;
+ else
+ {
+ String id = colibri.getID();
+
+ if ((id == null) || (id.length() == 0))
+ break;
+ else
+ {
+ conferenceRequest = new ColibriConferenceIQ();
+ conferenceRequest.setID(id);
+ conferenceRequest.setTo(colibri.getFrom());
+ conferenceRequest.setType(IQ.Type.SET);
+ }
+ }
+ }
+ conferenceRequest.getOrCreateContent(media).addChannel(
+ channelRequest);
+ }
+ }
+ if (conferenceRequest != null)
+ {
+ peer.getProtocolProvider().getConnection().sendPacket(
+ conferenceRequest);
+ }
+ }
+
+ /**
+ * Starts transport candidate harvest for a specific
+ * <tt>ContentPacketExtension</tt> that we are going to offer or answer
+ * with.
+ *
+ * @param theirContent the <tt>ContentPacketExtension</tt> offered by the
+ * remote peer to which we are going to answer with <tt>ourContent</tt> or
+ * <tt>null</tt> if <tt>ourContent</tt> will be an offer to the remote peer
+ * @param ourContent the <tt>ContentPacketExtension</tt> for which transport
+ * candidate harvest is to be started
+ * @param transportInfoSender a <tt>TransportInfoSender</tt> if the
+ * harvested transport candidates are to be sent in a
+ * <tt>transport-info</tt> rather than in <tt>ourContent</tt>; otherwise,
+ * <tt>null</tt>
+ * @param media the media of the <tt>RtpDescriptionPacketExtension</tt>
+ * child of <tt>ourContent</tt>
+ * @return a <tt>PacketExtension</tt> to be added as a child to
+ * <tt>ourContent</tt>; otherwise, <tt>null</tt>
+ * @throws OperationFailedException if anything goes wrong while starting
+ * transport candidate harvest for the specified <tt>ourContent</tt>
+ */
+ protected abstract PacketExtension startCandidateHarvest(
+ ContentPacketExtension theirContent,
+ ContentPacketExtension ourContent,
+ TransportInfoSender transportInfoSender,
+ String media)
+ throws OperationFailedException;
+
+ /**
+ * Starts transport candidate harvest. This method should complete rapidly
+ * and, in case of lengthy procedures like STUN/TURN/UPnP candidate harvests
+ * are necessary, they should be executed in a separate thread. Candidate
+ * harvest would then need to be concluded in the
+ * {@link #wrapupCandidateHarvest()} method which would be called once we
+ * absolutely need the candidates.
+ *
+ * @param theirOffer a media description offer that we've received from the
+ * remote party and that we should use in case we need to know what
+ * transports our peer is using.
+ * @param ourAnswer the content descriptions that we should be adding our
+ * transport lists to (although not necessarily in this very instance).
+ * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by
+ * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt>
+ * <tt>JingleIQ</tt>s from the local peer to the remote peer if this
+ * <tt>TransportManagerJabberImpl</tt> wishes to utilize
+ * <tt>transport-info</tt>. Local candidate addresses sent by this
+ * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are
+ * expected to not be included in the result of
+ * {@link #wrapupCandidateHarvest()}.
+ *
+ * @throws OperationFailedException if we fail to allocate a port number.
+ */
+ public void startCandidateHarvest(
+ List<ContentPacketExtension> theirOffer,
+ List<ContentPacketExtension> ourAnswer,
+ TransportInfoSender transportInfoSender)
+ throws OperationFailedException
+ {
+ CallPeerJabberImpl peer = getCallPeer();
+ CallJabberImpl call = peer.getCall();
+ boolean isJitsiVideobridge = call.getConference().isJitsiVideobridge();
+ List<ContentPacketExtension> cpes
+ = (theirOffer == null) ? ourAnswer : theirOffer;
+
+ /*
+ * If Jitsi Videobridge is to be used, determine which channels are to
+ * be allocated and attempt to allocate them now.
+ */
+ if (isJitsiVideobridge)
+ {
+ Map<ContentPacketExtension,ContentPacketExtension> contentMap
+ = new LinkedHashMap
+ <ContentPacketExtension,ContentPacketExtension>();
+
+ for (ContentPacketExtension cpe : cpes)
+ {
+ MediaType mediaType = JingleUtils.getMediaType(cpe);
+
+ /*
+ * The existence of a content for the mediaType and regardless
+ * of the existence of channels in it signals that a channel
+ * allocation request has already been sent for that mediaType.
+ */
+ if ((colibri == null)
+ || (colibri.getContent(mediaType.toString()) == null))
+ {
+ ContentPacketExtension local, remote;
+
+ if (cpes == ourAnswer)
+ {
+ local = cpe;
+ remote
+ = (theirOffer == null)
+ ? null
+ : findContentByName(theirOffer, cpe.getName());
+ }
+ else
+ {
+ local = findContentByName(ourAnswer, cpe.getName());
+ remote = cpe;
+ }
+ contentMap.put(local, remote);
+ }
+ }
+ if (!contentMap.isEmpty())
+ {
+ /*
+ * We are about to request the channel allocations for the media
+ * types found in contentMap. Regardless of the response, we do
+ * not want to repeat these requests.
+ */
+ if (colibri == null)
+ colibri = new ColibriConferenceIQ();
+ for (Map.Entry<ContentPacketExtension,ContentPacketExtension> e
+ : contentMap.entrySet())
+ {
+ ContentPacketExtension cpe = e.getValue();
+
+ if (cpe == null)
+ cpe = e.getKey();
+
+ colibri.getOrCreateContent(
+ JingleUtils.getMediaType(cpe).toString());
+ }
+
+ ColibriConferenceIQ conferenceResult
+ = call.createColibriChannels(peer, contentMap);
+
+ if (conferenceResult != null)
+ {
+ String videobridgeID = colibri.getID();
+ String conferenceResultID = conferenceResult.getID();
+
+ if (videobridgeID == null)
+ colibri.setID(conferenceResultID);
+ else if (!videobridgeID.equals(conferenceResultID))
+ throw new IllegalStateException("conference.id");
+
+ String videobridgeFrom = conferenceResult.getFrom();
+
+ if ((videobridgeFrom != null)
+ && (videobridgeFrom.length() != 0))
+ {
+ colibri.setFrom(videobridgeFrom);
+ }
+
+ for (ColibriConferenceIQ.Content contentResult
+ : conferenceResult.getContents())
+ {
+ ColibriConferenceIQ.Content content
+ = colibri.getOrCreateContent(
+ contentResult.getName());
+
+ for (ColibriConferenceIQ.Channel channelResult
+ : contentResult.getChannels())
+ {
+ if (content.getChannel(channelResult.getID())
+ == null)
+ {
+ content.addChannel(channelResult);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * The call fails if the createColibriChannels method fails
+ * which may happen if the conference packet times out or it
+ * can't be built.
+ */
+ ProtocolProviderServiceJabberImpl
+ .throwOperationFailedException(
+ "Failed to allocate colibri channel.",
+ OperationFailedException.GENERAL_ERROR,
+ null,
+ logger);
+ }
+ }
+ }
+
+ for (ContentPacketExtension cpe : cpes)
+ {
+ String contentName = cpe.getName();
+ ContentPacketExtension ourContent
+ = findContentByName(ourAnswer, contentName);
+
+ //it might be that we decided not to reply to this content
+ if (ourContent != null)
+ {
+ ContentPacketExtension theirContent
+ = (theirOffer == null)
+ ? null
+ : findContentByName(theirOffer, contentName);
+ RtpDescriptionPacketExtension rtpDesc
+ = ourContent.getFirstChildOfType(
+ RtpDescriptionPacketExtension.class);
+ String media = rtpDesc.getMedia();
+ PacketExtension pe
+ = startCandidateHarvest(
+ theirContent,
+ ourContent,
+ transportInfoSender,
+ media);
+
+ if (pe != null)
+ ourContent.addChildExtension(pe);
+ }
+ }
+ }
+
+ /**
+ * Starts transport candidate harvest. This method should complete rapidly
+ * and, in case of lengthy procedures like STUN/TURN/UPnP candidate harvests
+ * are necessary, they should be executed in a separate thread. Candidate
+ * harvest would then need to be concluded in the
+ * {@link #wrapupCandidateHarvest()} method which would be called once we
+ * absolutely need the candidates.
+ *
+ * @param ourOffer the content descriptions that we should be adding our
+ * transport lists to (although not necessarily in this very instance).
+ * @param transportInfoSender the <tt>TransportInfoSender</tt> to be used by
+ * this <tt>TransportManagerJabberImpl</tt> to send <tt>transport-info</tt>
+ * <tt>JingleIQ</tt>s from the local peer to the remote peer if this
+ * <tt>TransportManagerJabberImpl</tt> wishes to utilize
+ * <tt>transport-info</tt>. Local candidate addresses sent by this
+ * <tt>TransportManagerJabberImpl</tt> in <tt>transport-info</tt> are
+ * expected to not be included in the result of
+ * {@link #wrapupCandidateHarvest()}.
+ * @throws OperationFailedException if we fail to allocate a port number.
+ */
+ public void startCandidateHarvest(
+ List<ContentPacketExtension> ourOffer,
+ TransportInfoSender transportInfoSender)
+ throws OperationFailedException
+ {
+ startCandidateHarvest(
+ /* theirOffer */ null,
+ ourOffer,
+ transportInfoSender);
+ }
+
+ /**
+ * Notifies the transport manager that it should conclude candidate
+ * harvesting as soon as possible and return the lists of candidates
+ * gathered so far.
+ *
+ * @return the content list that we received earlier (possibly cloned into
+ * a new instance) and that we have updated with transport lists.
+ */
+ public abstract List<ContentPacketExtension> wrapupCandidateHarvest();
+
+ /**
+ * Looks through the <tt>cpExtList</tt> and returns the {@link
+ * ContentPacketExtension} with the specified name.
+ *
+ * @param cpExtList the list that we will be searching for a specific
+ * content.
+ * @param name the name of the content element we are looking for.
+ * @return the {@link ContentPacketExtension} with the specified name or
+ * <tt>null</tt> if no such content element exists.
+ */
+ public static ContentPacketExtension findContentByName(
+ Iterable<ContentPacketExtension> cpExtList,
+ String name)
+ {
+ for(ContentPacketExtension cpExt : cpExtList)
+ {
+ if(cpExt.getName().equals(name))
+ return cpExt;
+ }
+ return null;
+ }
+
+ /**
+ * Starts the connectivity establishment of this
+ * <tt>TransportManagerJabberImpl</tt> i.e. checks the connectivity between
+ * the local and the remote peers given the remote counterpart of the
+ * negotiation between them.
+ *
+ * @param remote the collection of <tt>ContentPacketExtension</tt>s which
+ * represents the remote counterpart of the negotiation between the local
+ * and the remote peer
+ * @return <tt>true</tt> if connectivity establishment has been started in
+ * response to the call; otherwise, <tt>false</tt>.
+ * <tt>TransportManagerJabberImpl</tt> implementations which do not perform
+ * connectivity checks (e.g. raw UDP) should return <tt>true</tt>. The
+ * default implementation does not perform connectivity checks and always
+ * returns <tt>true</tt>.
+ */
+ public boolean startConnectivityEstablishment(
+ Iterable<ContentPacketExtension> remote)
+ {
+ return true;
+ }
+
+ /**
+ * Starts the connectivity establishment of this
+ * <tt>TransportManagerJabberImpl</tt> i.e. checks the connectivity between
+ * the local and the remote peers given the remote counterpart of the
+ * negotiation between them.
+ *
+ * @param remote a <tt>Map</tt> of
+ * media-<tt>IceUdpTransportPacketExtension</tt> pairs which represents the
+ * remote counterpart of the negotiation between the local and the remote
+ * peers
+ * @return <tt>true</tt> if connectivity establishment has been started in
+ * response to the call; otherwise, <tt>false</tt>.
+ * <tt>TransportManagerJabberImpl</tt> implementations which do not perform
+ * connectivity checks (e.g. raw UDP) should return <tt>true</tt>. The
+ * default implementation does not perform connectivity checks and always
+ * returns <tt>true</tt>.
+ */
+ protected boolean startConnectivityEstablishment(
+ Map<String,IceUdpTransportPacketExtension> remote)
+ {
+ return true;
+ }
+
+ /**
+ * Notifies this <tt>TransportManagerJabberImpl</tt> that it should conclude
+ * any started connectivity establishment.
+ *
+ * @throws OperationFailedException if anything goes wrong with connectivity
+ * establishment (i.e. ICE failed, ...)
+ */
+ public void wrapupConnectivityEstablishment()
+ throws OperationFailedException
+ {
+ }
+
+ /**
+ * Removes a content with a specific name from the transport-related part of
+ * the session represented by this <tt>TransportManagerJabberImpl</tt> which
+ * may have been reported through previous calls to the
+ * <tt>startCandidateHarvest</tt> and
+ * <tt>startConnectivityEstablishment</tt> methods.
+ * <p>
+ * <b>Note</b>: Because <tt>TransportManager</tt> deals with
+ * <tt>MediaType</tt>s, not content names and
+ * <tt>TransportManagerJabberImpl</tt> does not implement translating from
+ * content name to <tt>MediaType</tt>, implementers are expected to call
+ * {@link TransportManager#closeStreamConnector(MediaType)}.
+ * </p>
+ *
+ * @param name the name of the content to be removed from the
+ * transport-related part of the session represented by this
+ * <tt>TransportManagerJabberImpl</tt>
+ */
+ public abstract void removeContent(String name);
+
+ /**
+ * Removes a content with a specific name from a specific collection of
+ * contents and closes any associated <tt>StreamConnector</tt>.
+ *
+ * @param contents the collection of contents to remove the content with the
+ * specified name from
+ * @param name the name of the content to remove
+ * @return the removed <tt>ContentPacketExtension</tt> if any; otherwise,
+ * <tt>null</tt>
+ */
+ protected ContentPacketExtension removeContent(
+ Iterable<ContentPacketExtension> contents,
+ String name)
+ {
+ for (Iterator<ContentPacketExtension> contentIter = contents.iterator();
+ contentIter.hasNext();)
+ {
+ ContentPacketExtension content = contentIter.next();
+
+ if (name.equals(content.getName()))
+ {
+ contentIter.remove();
+
+ // closeStreamConnector
+ MediaType mediaType = JingleUtils.getMediaType(content);
+ if (mediaType != null)
+ {
+ closeStreamConnector(mediaType);
+ }
+
+ return content;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Clones a specific <tt>IceUdpTransportPacketExtension</tt> and its
+ * candidates.
+ *
+ * @param src the <tt>IceUdpTransportPacketExtension</tt> to be cloned
+ * @return a new <tt>IceUdpTransportPacketExtension</tt> instance which has
+ * the same run-time type, attributes, namespace, text and candidates as the
+ * specified <tt>src</tt>
+ * @throws OperationFailedException if an error occurs during the cloing of
+ * the specified <tt>src</tt> and its candidates
+ */
+ static IceUdpTransportPacketExtension cloneTransportAndCandidates(
+ IceUdpTransportPacketExtension src)
+ throws OperationFailedException
+ {
+ try
+ {
+ return IceUdpTransportPacketExtension
+ .cloneTransportAndCandidates(src);
+ }
+ catch (Exception e)
+ {
+ ProtocolProviderServiceJabberImpl
+ .throwOperationFailedException(
+ "Failed to close transport and candidates.",
+ OperationFailedException.GENERAL_ERROR,
+ e,
+ logger);
+
+ }
+ return null;
+ }
+
+ /**
+ * Releases the resources acquired by this <tt>TransportManager</tt> and
+ * prepares it for garbage collection.
+ */
+ public void close()
+ {
+ for (MediaType mediaType : MediaType.values())
+ closeStreamConnector(mediaType);
+ }
+
+ /**
+ * Closes a specific <tt>StreamConnector</tt> associated with a specific
+ * <tt>MediaType</tt>. If this <tt>TransportManager</tt> has a reference to
+ * the specified <tt>streamConnector</tt>, it remains.
+ * Also expires the <tt>ColibriConferenceIQ.Channel</tt> associated with
+ * the closed <tt>StreamConnector</tt>.
+ *
+ * @param mediaType the <tt>MediaType</tt> associated with the specified
+ * <tt>streamConnector</tt>
+ * @param streamConnector the <tt>StreamConnector</tt> to be closed
+ */
+ @Override
+ protected void closeStreamConnector(
+ MediaType mediaType,
+ StreamConnector streamConnector)
+ {
+ try
+ {
+ boolean superCloseStreamConnector = true;
+
+ if (streamConnector instanceof ColibriStreamConnector)
+ {
+ CallPeerJabberImpl peer = getCallPeer();
+
+ if (peer != null)
+ {
+ CallJabberImpl call = peer.getCall();
+
+ if (call != null)
+ {
+ superCloseStreamConnector = false;
+ call.closeColibriStreamConnector(
+ peer,
+ mediaType,
+ (ColibriStreamConnector) streamConnector);
+ }
+ }
+ }
+ if (superCloseStreamConnector)
+ super.closeStreamConnector(mediaType, streamConnector);
+ }
+ finally
+ {
+ /*
+ * Expire the ColibriConferenceIQ.Channel associated with the closed
+ * StreamConnector.
+ */
+ if (colibri != null)
+ {
+ ColibriConferenceIQ.Content content
+ = colibri.getContent(mediaType.toString());
+
+ if (content != null)
+ {
+ List<ColibriConferenceIQ.Channel> channels
+ = content.getChannels();
+
+ if (channels.size() == 2)
+ {
+ ColibriConferenceIQ requestConferenceIQ
+ = new ColibriConferenceIQ();
+
+ requestConferenceIQ.setID(colibri.getID());
+
+ ColibriConferenceIQ.Content requestContent
+ = requestConferenceIQ.getOrCreateContent(
+ content.getName());
+
+ requestContent.addChannel(channels.get(1 /* remote */));
+
+ /*
+ * Regardless of whether the request to expire the
+ * Channel associated with mediaType succeeds, consider
+ * the Channel in question expired. Since
+ * RawUdpTransportManager allocates a single channel per
+ * MediaType, consider the whole Content expired.
+ */
+ colibri.removeContent(content);
+
+ CallPeerJabberImpl peer = getCallPeer();
+
+ if (peer != null)
+ {
+ CallJabberImpl call = peer.getCall();
+
+ if (call != null)
+ {
+ call.expireColibriChannels(
+ peer,
+ requestConferenceIQ);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Adds support for telephony conferences utilizing the Jitsi Videobridge
+ * server-side technology.
+ *
+ * @see #doCreateStreamConnector(MediaType)
+ */
+ @Override
+ protected StreamConnector createStreamConnector(final MediaType mediaType)
+ throws OperationFailedException
+ {
+ ColibriConferenceIQ.Channel channel
+ = getColibriChannel(mediaType, true /* local */);
+
+ if (channel != null)
+ {
+ CallPeerJabberImpl peer = getCallPeer();
+ CallJabberImpl call = peer.getCall();
+ StreamConnector streamConnector
+ = call.createColibriStreamConnector(
+ peer,
+ mediaType,
+ channel,
+ new StreamConnectorFactory()
+ {
+ public StreamConnector createStreamConnector()
+ {
+ try
+ {
+ return doCreateStreamConnector(mediaType);
+ }
+ catch (OperationFailedException ofe)
+ {
+ return null;
+ }
+ }
+ });
+
+ if (streamConnector != null)
+ return streamConnector;
+ }
+
+ return doCreateStreamConnector(mediaType);
+ }
+
+ protected abstract PacketExtension createTransport(String media)
+ throws OperationFailedException;
+
+ protected PacketExtension createTransportForStartCandidateHarvest(
+ String media)
+ throws OperationFailedException
+ {
+ PacketExtension pe = null;
+
+ if (getCallPeer().isJitsiVideobridge())
+ {
+ MediaType mediaType = MediaType.parseString(media);
+ ColibriConferenceIQ.Channel channel
+ = getColibriChannel(mediaType, false /* remote */);
+
+ if (channel != null)
+ pe = cloneTransportAndCandidates(channel.getTransport());
+ }
+ else
+ pe = createTransport(media);
+ return pe;
+ }
+
+ /**
+ * Initializes a new <tt>PacketExtension</tt> instance appropriate to the
+ * type of Jingle transport represented by this <tt>TransportManager</tt>.
+ * The new instance is not initialized with any attributes or child
+ * extensions.
+ *
+ * @return a new <tt>PacketExtension</tt> instance appropriate to the type
+ * of Jingle transport represented by this <tt>TransportManager</tt>
+ */
+ protected abstract PacketExtension createTransportPacketExtension();
+
+ /**
+ * Creates a media <tt>StreamConnector</tt> for a stream of a specific
+ * <tt>MediaType</tt>. The minimum and maximum of the media port boundaries
+ * are taken into account.
+ *
+ * @param mediaType the <tt>MediaType</tt> of the stream for which a
+ * <tt>StreamConnector</tt> is to be created
+ * @return a <tt>StreamConnector</tt> for the stream of the specified
+ * <tt>mediaType</tt>
+ * @throws OperationFailedException if the binding of the sockets fails
+ */
+ protected StreamConnector doCreateStreamConnector(MediaType mediaType)
+ throws OperationFailedException
+ {
+ return super.createStreamConnector(mediaType);
+ }
+
+ /**
+ * Finds a <tt>TransportManagerJabberImpl</tt> participating in a telephony
+ * conference utilizing the Jitsi Videobridge server-side technology that
+ * this instance is participating in which is establishing the connectivity
+ * with the Jitsi Videobridge server (as opposed to a <tt>CallPeer</tt>).
+ *
+ * @return a <tt>TransportManagerJabberImpl</tt> which is participating in
+ * a telephony conference utilizing the Jitsi Videobridge server-side
+ * technology that this instance is participating in which is establishing
+ * the connectivity with the Jitsi Videobridge server (as opposed to a
+ * <tt>CallPeer</tt>).
+ */
+ TransportManagerJabberImpl
+ findTransportManagerEstablishingConnectivityWithJitsiVideobridge()
+ {
+ Call call = getCallPeer().getCall();
+ TransportManagerJabberImpl transportManager = null;
+
+ if (call != null)
+ {
+ CallConference conference = call.getConference();
+
+ if ((conference != null) && conference.isJitsiVideobridge())
+ {
+ for (Call aCall : conference.getCalls())
+ {
+ Iterator<? extends CallPeer> callPeerIter
+ = aCall.getCallPeers();
+
+ while (callPeerIter.hasNext())
+ {
+ CallPeer aCallPeer = callPeerIter.next();
+
+ if (aCallPeer instanceof CallPeerJabberImpl)
+ {
+ TransportManagerJabberImpl aTransportManager
+ = ((CallPeerJabberImpl) aCallPeer)
+ .getMediaHandler()
+ .getTransportManager();
+
+ if (aTransportManager
+ .isEstablishingConnectivityWithJitsiVideobridge)
+ {
+ transportManager = aTransportManager;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return transportManager;
+ }
+
+ /**
+ * Gets the {@link ColibriConferenceIQ.Channel} which belongs to a content
+ * associated with a specific <tt>MediaType</tt> and is to be either locally
+ * or remotely used.
+ * <p>
+ * <b>Note</b>: Modifications to the <tt>ColibriConferenceIQ.Channel</tt>
+ * instance returned by the method propagate to (the state of) this
+ * instance.
+ * </p>
+ *
+ * @param mediaType the <tt>MediaType</tt> associated with the content which
+ * contains the <tt>ColibriConferenceIQ.Channel</tt> to get
+ * @param local <tt>true</tt> if the <tt>ColibriConferenceIQ.Channel</tt>
+ * which is to be used locally is to be returned or <tt>false</tt> for the
+ * one which is to be used remotely
+ * @return the <tt>ColibriConferenceIQ.Channel</tt> which belongs to a
+ * content associated with the specified <tt>mediaType</tt> and which is to
+ * be used in accord with the specified <tt>local</tt> indicator if such a
+ * channel exists; otherwise, <tt>null</tt>
+ */
+ ColibriConferenceIQ.Channel getColibriChannel(
+ MediaType mediaType,
+ boolean local)
+ {
+ ColibriConferenceIQ.Channel channel = null;
+
+ if (colibri != null)
+ {
+ ColibriConferenceIQ.Content content
+ = colibri.getContent(mediaType.toString());
+
+ if (content != null)
+ {
+ List<ColibriConferenceIQ.Channel> channels
+ = content.getChannels();
+
+ if (channels.size() == 2)
+ channel = channels.get(local ? 0 : 1);
+ }
+ }
+ return channel;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/DefaultPacketExtensionProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/DefaultPacketExtensionProvider.java
index 1285581..778d086 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/DefaultPacketExtensionProvider.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/DefaultPacketExtensionProvider.java
@@ -19,6 +19,7 @@ package net.java.sip.communicator.impl.protocol.jabber.extensions;
import java.util.logging.*;
+import net.java.sip.communicator.service.protocol.jabber.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.xmlpull.v1.*;
@@ -41,6 +42,13 @@ public class DefaultPacketExtensionProvider<C extends AbstractPacketExtension>
.getLogger(DefaultPacketExtensionProvider.class.getName());
/**
+ * The <tt>AbstractSmackInteroperabilityLayer</tt> instance implementing
+ * necessary methods
+ */
+ private AbstractSmackInteroperabilityLayer smackInteroperabilityLayer =
+ AbstractSmackInteroperabilityLayer.getInstance();
+
+ /**
* The {@link Class} that the packets we will be parsing here belong to.
*/
private final Class<C> packetClass;
@@ -100,8 +108,7 @@ public class DefaultPacketExtensionProvider<C extends AbstractPacketExtension>
if (eventType == XmlPullParser.START_TAG)
{
- PacketExtensionProvider provider
- = (PacketExtensionProvider)ProviderManager.getInstance()
+ PacketExtensionProvider provider = smackInteroperabilityLayer
.getExtensionProvider( elementName, namespace );
if(provider == null)
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java
index ebdcbb0..97d9ff8 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/EntityCapsManager.java
@@ -243,6 +243,7 @@ public class EntityCapsManager
if ((user != null) && (node != null) && (hash != null) && (ver != null))
{
Caps caps = userCaps.get(user);
+ String bareJid=StringUtils.parseBareAddress(user);
if ((caps == null)
|| !caps.node.equals(node)
@@ -270,7 +271,9 @@ public class EntityCapsManager
String nodeVer = caps.getNodeVer();
for (UserCapsNodeListener listener : listeners)
- listener.userCapsNodeAdded(user, nodeVer, online);
+ listener.userCapsNodeAdded(user,
+ getFullJidsByBareJid(bareJid),
+ nodeVer, online);
}
}
}
@@ -305,6 +308,8 @@ public class EntityCapsManager
{
Caps caps = null;
String lastRemovedJid = null;
+ String bareJid=StringUtils.parseBareAddress(
+ contact.getAddress());
Iterator<String> iter = userCaps.keySet().iterator();
while(iter.hasNext())
@@ -337,7 +342,9 @@ public class EntityCapsManager
for (UserCapsNodeListener listener : listeners)
listener.userCapsNodeRemoved(
- lastRemovedJid, nodeVer, false);
+ lastRemovedJid,
+ getFullJidsByBareJid(bareJid),
+ nodeVer, false);
}
}
}
@@ -350,6 +357,7 @@ public class EntityCapsManager
public void removeUserCapsNode(String user)
{
Caps caps = userCaps.remove(user);
+ String bareJid=StringUtils.parseBareAddress(user);
// Fire userCapsNodeRemoved.
if (caps != null)
@@ -367,7 +375,9 @@ public class EntityCapsManager
String nodeVer = caps.getNodeVer();
for (UserCapsNodeListener listener : listeners)
- listener.userCapsNodeRemoved(user, nodeVer, false);
+ listener.userCapsNodeRemoved(user,
+ getFullJidsByBareJid(bareJid),
+ nodeVer, false);
}
}
}
@@ -404,6 +414,24 @@ public class EntityCapsManager
{
return userCaps.get(user);
}
+
+ /**
+ * Gets the full Jids (with resources) as Strings.
+ *
+ * @param the bare Jid
+ * @return the full Jids as an ArrayList <tt>user</tt>
+ */
+ public ArrayList<String> getFullJidsByBareJid(String bareJid)
+ {
+ ArrayList<String> jids = new ArrayList<String>();
+ for(String jid: userCaps.keySet())
+ {
+ if(bareJid.equals(StringUtils.parseBareAddress(jid))){
+ jids.add(jid);
+ }
+ }
+ return jids;
+ }
/**
* Get the discover info given a user name. The discover info is returned if
@@ -605,14 +633,9 @@ public class EntityCapsManager
* @param connection the connection that we'd like this manager to register
* with.
*/
- public void addPacketListener(XMPPConnection connection)
+ public void addPacketListener(Connection connection)
{
- PacketFilter filter
- = new AndFilter(
- new PacketTypeFilter(Presence.class),
- new PacketExtensionFilter(
- CapsPacketExtension.ELEMENT_NAME,
- CapsPacketExtension.NAMESPACE));
+ PacketFilter filter = new PacketTypeFilter(Presence.class);
connection.addPacketListener(new CapsPacketListener(), filter);
}
@@ -913,48 +936,48 @@ public class EntityCapsManager
*/
public void processPacket(Packet packet)
{
+ // Check it the packet indicates that the user is online. We
+ // will use this information to decide if we're going to send
+ // the discover info request.
+ boolean online
+ = (packet instanceof Presence)
+ && ((Presence) packet).isAvailable();
+
CapsPacketExtension ext
= (CapsPacketExtension)
packet.getExtension(
CapsPacketExtension.ELEMENT_NAME,
CapsPacketExtension.NAMESPACE);
- /*
- * Before Version 1.4 of XEP-0115: Entity Capabilities, the 'ver'
- * attribute was generated differently and the 'hash' attribute was
- * absent. The 'ver' attribute in Version 1.3 represents the
- * specific version of the client and thus does not provide a way to
- * validate the DiscoverInfo sent by the client. If
- * EntityCapsManager receives no 'hash' attribute, it will assume
- * the legacy format and will not cache it because the DiscoverInfo
- * to be received from the client later on will not be trustworthy.
- */
- String hash = ext.getHash();
-
- /* Google Talk web does not set hash but we need it to be cached */
- if(hash == null)
- hash = "";
-
- if (hash != null)
+ if(ext != null && online)
{
- // Check it the packet indicates that the user is online. We
- // will use this information to decide if we're going to send
- // the discover info request.
- boolean online
- = (packet instanceof Presence)
- && ((Presence) packet).isAvailable();
-
- if(online)
- {
- addUserCapsNode(
- packet.getFrom(),
- ext.getNode(), hash, ext.getVersion(),
- ext.getExtensions(), online);
- }
- else
- {
- removeUserCapsNode(packet.getFrom());
- }
+ /*
+ * Before Version 1.4 of XEP-0115: Entity Capabilities,
+ * the 'ver' attribute was generated differently and the 'hash'
+ * attribute was absent. The 'ver' attribute in Version 1.3
+ * represents the specific version of the client and thus does
+ * not provide a way to validate the DiscoverInfo sent by
+ * the client. If EntityCapsManager receives no 'hash'
+ * attribute, it will assume the legacy format and will not
+ * cache it because the DiscoverInfo to be received from
+ * the client later on will not be trustworthy.
+ */
+ String hash = ext.getHash();
+
+ /* Google Talk web does not set hash, but we need it to
+ * be cached
+ */
+ if (hash == null)
+ hash = "";
+
+ addUserCapsNode(
+ packet.getFrom(),
+ ext.getNode(), hash, ext.getVersion(),
+ ext.getExtensions(), online);
+ }
+ else if (!online)
+ {
+ removeUserCapsNode(packet.getFrom());
}
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/UserCapsNodeListener.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/UserCapsNodeListener.java
index 5ee38b0..eda921f 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/UserCapsNodeListener.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/caps/UserCapsNodeListener.java
@@ -17,6 +17,8 @@
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.caps;
+import java.util.ArrayList;
+
/**
* Represents a listener of events notifying about changes in the list of user
* caps nodes of <tt>EntityCapsManager</tt>.
@@ -30,18 +32,22 @@ public interface UserCapsNodeListener
* record for a specific user about the caps node the user has.
*
* @param user the user (full JID)
+ * @param fullJids a list of all resources of the user (full JIDs)
* @param node the entity caps node#ver
* @param online indicates if the user for which we're notified is online
*/
- public void userCapsNodeAdded(String user, String node, boolean online);
+ public void userCapsNodeAdded(String user, ArrayList<String> fullJids,
+ String node, boolean online);
/**
* Notifies this listener that an <tt>EntityCapsManager</tt> has removed a
* record for a specific user about the caps node the user has.
*
* @param user the user (full JID)
+ * @param fullJids a list of all resources of the user (full JIDs)
* @param node the entity caps node#ver
* @param online indicates if the user for which we're notified is online
*/
- public void userCapsNodeRemoved(String user, String node, boolean online);
+ public void userCapsNodeRemoved(String user, ArrayList<String> fullJids,
+ String node, boolean online);
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriBuilder.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriBuilder.java
index 547ebe8..48207c2 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriBuilder.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriBuilder.java
@@ -37,9 +37,9 @@ import java.util.*;
* Add one or multiple requests of the same type by calling
* {@link #addAllocateChannelsReq(boolean, String, boolean, java.util.List)}}
* or {@link #addExpireChannelsReq(ColibriConferenceIQ)}
- * or {@link #addTransportUpdateReq(boolean, java.util.Map, ColibriConferenceIQ)}
- * or {@link #addBundleTransportUpdateReq(
- * boolean, IceUdpTransportPacketExtension, ColibriConferenceIQ)}.
+ * or {@link #addRtpDescription(Map, ColibriConferenceIQ)}
+ * and {@link #addSSSRCGroupsInfo(Map, ColibriConferenceIQ)}
+ * and {@link #addSSSRCInfo(Map, ColibriConferenceIQ)}.
* </li>
* <li>
* Compile the request by calling {@link #getRequest(String)}. Then send it to
@@ -119,6 +119,20 @@ public class ColibriBuilder
private SimulcastMode simulcastMode;
/**
+ * Specifies the audio packet delay that will be set on all created audio
+ * channels. When set to <tt>null</tt> the builder will clear the attribute
+ * which stands for 'undefined'.
+ **/
+ private Integer audioPacketDelay;
+
+ /**
+ * Channel 'rtp-level-relay-type' option that will be used with all created
+ * audio channel. Possible values: mixer or translator (default).
+ *
+ */
+ private RTPLevelRelayType rtpLevelRelayType;
+
+ /**
* Creates new instance of {@link ColibriBuilder} for given
* <tt>conferenceState</tt>.
*
@@ -161,18 +175,26 @@ public class ColibriBuilder
* @param contents the list of {@link ContentPacketExtension} describing
* channels media.
*
- * @return this instance fo calls chaining purpose.
+ * @return <tt>true</tt> if the request yields any changes in Colibri
+ * channels state on the bridge or <tt>false</tt> otherwise.
+ * In general when <tt>false</tt> is returned for all
+ * combined requests it makes no sense to send it.
*/
- public ColibriBuilder addAllocateChannelsReq(
- boolean useBundle,
- String endpointName,
- boolean peerIsInitiator,
+ public boolean addAllocateChannelsReq(
+ boolean useBundle,
+ String endpointName,
+ boolean peerIsInitiator,
List<ContentPacketExtension> contents)
{
+ Objects.requireNonNull(endpointName, "endpointName");
+ Objects.requireNonNull(contents, "contents");
+
assertRequestType(RequestType.ALLOCATE_CHANNELS);
request.setType(IQ.Type.GET);
+ boolean hasAnyChanges = false;
+
for (ContentPacketExtension cpe : contents)
{
MediaType mediaType = JingleUtils.getMediaType(cpe);
@@ -193,7 +215,7 @@ public class ColibriBuilder
remoteChannelRequest.setChannelBundleId(endpointName);
}
- if (mediaType != MediaType.DATA)
+ if (remoteChannelRequest instanceof ColibriConferenceIQ.Channel)
{
RtpDescriptionPacketExtension rdpe
= cpe.getFirstChildOfType(
@@ -213,6 +235,13 @@ public class ColibriBuilder
remoteRtpChannelRequest.setAdaptiveLastN(adaptiveLastN);
remoteRtpChannelRequest.setAdaptiveSimulcast(adaptiveSimulcast);
remoteRtpChannelRequest.setSimulcastMode(simulcastMode);
+ if (MediaType.AUDIO.equals(mediaType))
+ {
+ // When audioPacketDelay is null it will clear the attribute
+ remoteRtpChannelRequest.setPacketDelay(audioPacketDelay);
+ // Set rtp packet relay type for this channel
+ remoteRtpChannelRequest.setRTPLevelRelayType(rtpLevelRelayType);
+ }
}
// Copy transport
@@ -221,13 +250,17 @@ public class ColibriBuilder
copyTransportOnChannel(cpe, remoteChannelRequest);
}
- if (mediaType != MediaType.DATA)
+ if (remoteChannelRequest instanceof ColibriConferenceIQ.Channel)
{
+ hasAnyChanges = true;
+
contentRequest.addChannel(
(ColibriConferenceIQ.Channel) remoteChannelRequest);
}
else
{
+ hasAnyChanges = true;
+
contentRequest.addSctpConnection(
(ColibriConferenceIQ.SctpConnection) remoteChannelRequest);
}
@@ -246,6 +279,8 @@ public class ColibriBuilder
IceUdpTransportPacketExtension.class);
if (transport != null)
{
+ hasAnyChanges = true;
+
bundle.setTransport(
IceUdpTransportPacketExtension
.cloneTransportAndCandidates(transport, true));
@@ -254,106 +289,38 @@ public class ColibriBuilder
request.addChannelBundle(bundle);
}
- return this;
- }
-
- /**
- * Adds next ICE transport update request to
- * {@link RequestType#TRANSPORT_UPDATE} query currently being built.
- *
- * @param initiator the value that will be set in 'initiator'
- * attribute({@link ColibriConferenceIQ.Channel#initiator}).
- * @param map the map of content name to transport extensions. Maps
- * transport to media types.
- * @param localChannelsInfo {@link ColibriConferenceIQ} holding info about
- * Colibri channels to be updated.
- *
- * @return this instance fo calls chaining purpose.
- */
- public ColibriBuilder addTransportUpdateReq(
- boolean initiator,
- Map<String, IceUdpTransportPacketExtension> map,
- ColibriConferenceIQ localChannelsInfo)
- {
- if (conferenceState == null
- || StringUtils.isNullOrEmpty(conferenceState.getID()))
- {
- // We are not initialized yet
- return null;
- }
-
- assertRequestType(RequestType.TRANSPORT_UPDATE);
-
- request.setType(IQ.Type.SET);
-
- for (Map.Entry<String,IceUdpTransportPacketExtension> e
- : map.entrySet())
- {
- String contentName = e.getKey();
- ColibriConferenceIQ.ChannelCommon channel
- = getColibriChannel(localChannelsInfo, contentName);
-
- if (channel != null)
- {
- IceUdpTransportPacketExtension transport
- = IceUdpTransportPacketExtension
- .cloneTransportAndCandidates(e.getValue(), true);
-
- ColibriConferenceIQ.ChannelCommon channelRequest
- = channel instanceof ColibriConferenceIQ.Channel
- ? new ColibriConferenceIQ.Channel()
- : new ColibriConferenceIQ.SctpConnection();
-
- channelRequest.setID(channel.getID());
- channelRequest.setEndpoint(channel.getEndpoint());
- channelRequest.setInitiator(initiator);
- channelRequest.setTransport(transport);
-
- if (channelRequest instanceof ColibriConferenceIQ.Channel)
- {
- request.getOrCreateContent(contentName)
- .addChannel(
- (ColibriConferenceIQ.Channel) channelRequest);
- }
- else
- {
- request.getOrCreateContent(contentName)
- .addSctpConnection(
- (ColibriConferenceIQ.SctpConnection) channelRequest);
- }
- }
- }
- return this;
+ return hasAnyChanges;
}
/**
- * Adds next request to {@link RequestType#BUNDLE_TRANSPORT_UPDATE} query.
- * @param initiator the value that will be set in 'initiator'
- * attribute({@link ColibriConferenceIQ.Channel#initiator}).
+ * Adds next request to {@link RequestType#CHANNEL_INFO_UPDATE} query.
* @param localChannelsInfo the {@link ColibriConferenceIQ} instance that
* describes the channel for which bundle transport will be updated.
* It should contain the description of only one "channel bundle".
* If it contains more than one then the first one will be used.
- * @return this instance for calls chaining purpose.
+ * @return <tt>true</tt> if the request yields any changes in Colibri
+ * channels state on the bridge or <tt>false</tt> otherwise.
+ * In general when <tt>false</tt> is returned for all
+ * combined requests it makes no sense to send it.
* @throws IllegalArgumentException if <tt>localChannelsInfo</tt> does not
* describe any channel bundles.
*/
- public ColibriBuilder addBundleTransportUpdateReq(
- boolean initiator,
- IceUdpTransportPacketExtension transport,
- ColibriConferenceIQ localChannelsInfo)
+ public boolean addBundleTransportUpdateReq(
+ IceUdpTransportPacketExtension transport,
+ ColibriConferenceIQ localChannelsInfo)
throws IllegalArgumentException
{
- // FIXME:'initiator' not used on bundle transport update ?
+ Objects.requireNonNull(transport, "transport");
+ Objects.requireNonNull(localChannelsInfo, "localChannelsInfo");
if (conferenceState == null
|| StringUtils.isNullOrEmpty(conferenceState.getID()))
{
// We are not initialized yet
- return null;
+ return false;
}
- assertRequestType(RequestType.BUNDLE_TRANSPORT_UPDATE);
+ assertRequestType(RequestType.CHANNEL_INFO_UPDATE);
request.setType(IQ.Type.SET);
@@ -371,7 +338,7 @@ public class ColibriBuilder
else
{
throw new IllegalArgumentException(
- "Expected ChannelBundle as not found");
+ "Expected ChannelBundle as not found");
}
ColibriConferenceIQ.ChannelBundle bundleUpdate
@@ -387,7 +354,7 @@ public class ColibriBuilder
request.addChannelBundle(bundleUpdate);
- return this;
+ return true;
}
/**
@@ -395,15 +362,20 @@ public class ColibriBuilder
* {@link RequestType#EXPIRE_CHANNELS} query currently being built.
* @param channelInfo the {@link ColibriConferenceIQ} instance that contains
* info about the channels to be expired.
- * @return this instance for the purpose of calls chaining.
+ * @return <tt>true</tt> if the request yields any changes in Colibri
+ * channels state on the bridge or <tt>false</tt> otherwise.
+ * In general when <tt>false</tt> is returned for all
+ * combined requests it makes no sense to send it.
*/
- public ColibriBuilder addExpireChannelsReq(ColibriConferenceIQ channelInfo)
+ public boolean addExpireChannelsReq(ColibriConferenceIQ channelInfo)
{
+ Objects.requireNonNull(channelInfo, "channelInfo");
+
// Formulate the ColibriConferenceIQ request which is to be sent.
if (conferenceState == null
|| StringUtils.isNullOrEmpty(conferenceState.getID()))
{
- return null;
+ return false;
}
assertRequestType(RequestType.EXPIRE_CHANNELS);
@@ -411,7 +383,7 @@ public class ColibriBuilder
request.setType(IQ.Type.SET);
for (ColibriConferenceIQ.Content expiredContent
- : channelInfo.getContents())
+ : channelInfo.getContents())
{
ColibriConferenceIQ.Content stateContent
= conferenceState.getContent(expiredContent.getName());
@@ -420,7 +392,7 @@ public class ColibriBuilder
{
ColibriConferenceIQ.Content requestContent
= request.getOrCreateContent(
- stateContent.getName());
+ stateContent.getName());
for (ColibriConferenceIQ.Channel expiredChannel
: expiredContent.getChannels())
@@ -490,7 +462,7 @@ public class ColibriBuilder
*/
/*if (stateContent.getChannelCount() == 1)
{
- stateChannel = stateContent.getChannel(0);
+ stateChannel = stateContent.getRtpChannel(0);
ColibriConferenceIQ.Channel channelRequest
= new ColibriConferenceIQ.Channel();
@@ -537,7 +509,294 @@ public class ColibriBuilder
}
}
- return this;
+ return hasAnyChannelsToExpire;
+ }
+
+ /**
+ * Adds next payload type information update request to
+ * {@link RequestType#CHANNEL_INFO_UPDATE} query currently being built.
+ *
+ * @param map the map of content name to RTP description packet extension.
+ * @param localChannelsInfo {@link ColibriConferenceIQ} holding info about
+ * Colibri channels to be updated.
+ *
+ * @return <tt>true</tt> if the request yields any changes in Colibri
+ * channels state on the bridge or <tt>false</tt> otherwise.
+ * In general when <tt>false</tt> is returned for all
+ * combined requests it makes no sense to send it.
+ */
+ public boolean addRtpDescription(
+ Map<String, RtpDescriptionPacketExtension> map,
+ ColibriConferenceIQ localChannelsInfo)
+ {
+ Objects.requireNonNull(map, "map");
+ Objects.requireNonNull(localChannelsInfo, "localChannelsInfo");
+
+ if (conferenceState == null
+ || StringUtils.isNullOrEmpty(conferenceState.getID()))
+ {
+ // We are not initialized yet
+ return false;
+ }
+
+ assertRequestType(RequestType.CHANNEL_INFO_UPDATE);
+
+ request.setType(IQ.Type.SET);
+
+ boolean anyUpdates = false;
+
+ for (Map.Entry<String, RtpDescriptionPacketExtension> e
+ : map.entrySet())
+ {
+ String contentName = e.getKey();
+ ColibriConferenceIQ.ChannelCommon channel
+ = getColibriChannel(localChannelsInfo, contentName);
+
+ if (channel != null
+ && channel instanceof ColibriConferenceIQ.Channel)
+ {
+ RtpDescriptionPacketExtension rtpPE = e.getValue();
+ if (rtpPE == null)
+ {
+ continue;
+ }
+
+ List<PayloadTypePacketExtension> pts = rtpPE.getPayloadTypes();
+ if (pts == null || pts.isEmpty())
+ {
+ continue;
+ }
+
+ anyUpdates = true;
+
+ ColibriConferenceIQ.Channel channelRequest
+ = (ColibriConferenceIQ.Channel) getRequestChannel(
+ request.getOrCreateContent(contentName),
+ channel);
+ if (channelRequest == null)
+ {
+ channelRequest = new ColibriConferenceIQ.Channel();
+ channelRequest.setID(channel.getID());
+ }
+
+ for (PayloadTypePacketExtension ptPE : pts)
+ {
+ channelRequest.addPayloadType(ptPE);
+ }
+ }
+ }
+
+ return anyUpdates;
+ }
+
+ /**
+ * Adds next SSRC information update request to
+ * {@link RequestType#CHANNEL_INFO_UPDATE} query currently being built.
+ *
+ * @param ssrcMap the map of content name to the list of
+ * <tt>SourcePacketExtension</tt>.
+ * @param localChannelsInfo {@link ColibriConferenceIQ} holding info about
+ * Colibri channels to be updated.
+ *
+ * @return <tt>true</tt> if the request yields any changes in Colibri
+ * channels state on the bridge or <tt>false</tt> otherwise.
+ * In general when <tt>false</tt> is returned for all
+ * combined requests it makes no sense to send it.
+ */
+ public boolean addSSSRCInfo(
+ Map<String, List<SourcePacketExtension>> ssrcMap,
+ ColibriConferenceIQ localChannelsInfo)
+ {
+ Objects.requireNonNull(ssrcMap, "ssrcMap");
+ Objects.requireNonNull(localChannelsInfo, "localChannelsInfo");
+
+ if (conferenceState == null
+ || StringUtils.isNullOrEmpty(conferenceState.getID()))
+ {
+ // We are not initialized yet
+ return false;
+ }
+
+ assertRequestType(RequestType.CHANNEL_INFO_UPDATE);
+
+ request.setType(IQ.Type.SET);
+
+ boolean anyUpdates = false;
+
+ // Go over SSRCs
+ for (String contentName : ssrcMap.keySet())
+ {
+ // Get channel from local channel info
+ ColibriConferenceIQ.ChannelCommon rtpChanel
+ = getRtpChannel(localChannelsInfo, contentName);
+ if (rtpChanel == null)
+ {
+ // There's no channel for this content name in localChannelsInfo
+ continue;
+ }
+
+ anyUpdates = true;
+
+ // Ok we have channel for this content, let's add SSRCs
+ ColibriConferenceIQ.Channel reqChannel
+ = (ColibriConferenceIQ.Channel) getRequestChannel(
+ request.getOrCreateContent(contentName), rtpChanel);
+
+ for (SourcePacketExtension ssrc : ssrcMap.get(contentName))
+ {
+ reqChannel.addSource(ssrc.copy());
+ }
+
+ if (reqChannel.getSources() == null
+ || reqChannel.getSources().isEmpty())
+ {
+ // Put an empty source to remove all sources
+ SourcePacketExtension emptySource = new SourcePacketExtension();
+ emptySource.setSSRC(-1L);
+ reqChannel.addSource(emptySource);
+ }
+ }
+
+ return anyUpdates;
+ }
+
+ /**
+ * Adds next SSRC group information update request to
+ * {@link RequestType#CHANNEL_INFO_UPDATE} query currently being built.
+ *
+ * @param ssrcGroupMap the map of content name to the list of
+ * <tt>SourceGroupPacketExtension</tt>.
+ * @param localChannelsInfo {@link ColibriConferenceIQ} holding info about
+ * Colibri channels to be updated.
+ *
+ * @return <tt>true</tt> if the request yields any changes in Colibri
+ * channels state on the bridge or <tt>false</tt> otherwise.
+ * In general when <tt>false</tt> is returned for all
+ * combined requests it makes no sense to send it.
+ */
+ public boolean addSSSRCGroupsInfo(
+ Map<String, List<SourceGroupPacketExtension>> ssrcGroupMap,
+ ColibriConferenceIQ localChannelsInfo)
+ {
+ Objects.requireNonNull(ssrcGroupMap, "ssrcGroupMap");
+ Objects.requireNonNull(localChannelsInfo, "localChannelsInfo");
+
+ if (conferenceState == null
+ || StringUtils.isNullOrEmpty(conferenceState.getID()))
+ {
+ // We are not initialized yet
+ return false;
+ }
+
+ assertRequestType(RequestType.CHANNEL_INFO_UPDATE);
+
+ request.setType(IQ.Type.SET);
+
+ boolean anyUpdates = false;
+
+ // Go over SSRC groups
+ for (String contentName : ssrcGroupMap.keySet())
+ {
+ // Get channel from local channel info
+ ColibriConferenceIQ.Channel rtpChannel
+ = getRtpChannel(localChannelsInfo, contentName);
+ if (rtpChannel == null)
+ {
+ // There's no channel for this content name in localChannelsInfo
+ continue;
+ }
+
+ List<SourceGroupPacketExtension> groups
+ = ssrcGroupMap.get(contentName);
+
+ // Ok we have channel for this content, let's add SSRCs
+ ColibriConferenceIQ.Channel reqChannel
+ = (ColibriConferenceIQ.Channel) getRequestChannel(
+ request.getOrCreateContent(contentName), rtpChannel);
+
+ if (groups.isEmpty() && "video".equalsIgnoreCase(contentName))
+ {
+ anyUpdates = true;
+
+ // Put empty source group to turn off simulcast layers
+ reqChannel.addSourceGroup(
+ SourceGroupPacketExtension.createSimulcastGroup());
+ }
+
+ for (SourceGroupPacketExtension group : groups)
+ {
+ anyUpdates = true;
+
+ reqChannel.addSourceGroup(group);
+ }
+ }
+
+ return anyUpdates;
+ }
+
+ /**
+ * Adds next ICE transport update request to
+ * {@link RequestType#CHANNEL_INFO_UPDATE} query currently being built.
+ *
+ * @param map the map of content name to transport extensions. Maps
+ * transport to media types.
+ * @param localChannelsInfo {@link ColibriConferenceIQ} holding info about
+ * Colibri channels to be updated.
+ *
+ * @return <tt>true</tt> if the request yields any changes in Colibri
+ * channels state on the bridge or <tt>false</tt> otherwise.
+ * In general when <tt>false</tt> is returned for all
+ * combined requests it makes no sense to send it.
+ */
+ public boolean addTransportUpdateReq(
+ Map<String, IceUdpTransportPacketExtension> map,
+ ColibriConferenceIQ localChannelsInfo)
+ {
+ Objects.requireNonNull(map, "map");
+ Objects.requireNonNull(localChannelsInfo, "localChannelsInfo");
+
+ if (conferenceState == null
+ || StringUtils.isNullOrEmpty(conferenceState.getID()))
+ {
+ // We are not initialized yet
+ return false;
+ }
+
+ boolean hasAnyChanges = false;
+
+ assertRequestType(RequestType.CHANNEL_INFO_UPDATE);
+
+ request.setType(IQ.Type.SET);
+
+ for (Map.Entry<String,IceUdpTransportPacketExtension> e
+ : map.entrySet())
+ {
+ String contentName = e.getKey();
+ ColibriConferenceIQ.ChannelCommon channel
+ = getColibriChannel(localChannelsInfo, contentName);
+
+ if (channel != null)
+ {
+ IceUdpTransportPacketExtension transport
+ = IceUdpTransportPacketExtension
+ .cloneTransportAndCandidates(e.getValue(), true);
+
+ ColibriConferenceIQ.ChannelCommon channelRequest
+ = channel instanceof ColibriConferenceIQ.Channel
+ ? new ColibriConferenceIQ.Channel()
+ : new ColibriConferenceIQ.SctpConnection();
+
+ channelRequest.setID(channel.getID());
+ channelRequest.setEndpoint(channel.getEndpoint());
+ channelRequest.setTransport(transport);
+
+ request.getOrCreateContent(contentName)
+ .addChannelCommon(channelRequest);
+
+ hasAnyChanges = true;
+ }
+ }
+ return hasAnyChanges;
}
/**
@@ -583,10 +842,12 @@ public class ColibriBuilder
request.setTo(videobridge);
- if (requestType == RequestType.EXPIRE_CHANNELS
- && !hasAnyChannelsToExpire)
+ if (requestType == RequestType.EXPIRE_CHANNELS)
{
- return null;
+ if (!hasAnyChannelsToExpire)
+ return null;
+
+ hasAnyChannelsToExpire = false;
}
return request;
@@ -720,6 +981,28 @@ public class ColibriBuilder
}
/**
+ * Returns an <tt>Integer</tt> which stands for the audio packet delay
+ * that will be set on all created audio channels or <tt>null</tt> if
+ * the builder should leave not include the XML attribute at all.
+ */
+ public Integer getAudioPacketDelay()
+ {
+ return audioPacketDelay;
+ }
+
+ /**
+ * Configures audio channels packet delay.
+ * @param audioPacketDelay an <tt>Integer</tt> value which stands for
+ * the audio packet delay that will be set on all created audio channels or
+ * <tt>null</tt> if the builder should not set that channel property to any
+ * value.
+ */
+ public void setAudioPacketDelay(Integer audioPacketDelay)
+ {
+ this.audioPacketDelay = audioPacketDelay;
+ }
+
+ /**
* Sets channel 'simulcast-mode' option that will be added to the
* request when channels are created.
* @param simulcastMode a <tt>SimulcastMode</tt> value to specify
@@ -732,69 +1015,64 @@ public class ColibriBuilder
}
/**
- * Adds next payload type information update request to
- * {@link RequestType#RTP_DESCRIPTION_UPDATE} query currently being built.
+ * Creates a new instance of <tt>localChannelInfo</tt> and initializes only
+ * the fields required to identify particular Colibri channel on the bridge.
+ * This instance is meant to be used in Colibri
+ * {@link RequestType#CHANNEL_INFO_UPDATE} requests. This instance is also
+ * added to given <tt>requestContent</tt> which used to construct current
+ * request.
*
- * @param map the map of content name to RTP description packet extension.
- * @param localChannelsInfo {@link ColibriConferenceIQ} holding info about
- * Colibri channels to be updated.
+ * @param requestContent <tt>Content</tt> of Colibri update request to which
+ * new instance wil be automatically added after has been created.
+ * @param localChannelInfo the original channel for which "update request"
+ * equivalent is to be created with this call.
*
- * @return this instance for calls chaining purpose.
+ * @return new instance of <tt>localChannelInfo</tt> and initialized with
+ * only those fields required to identify particular Colibri channel on
+ * the bridge.
*/
- public ColibriBuilder addRtpDescription(
- Map<String, RtpDescriptionPacketExtension> map,
- ColibriConferenceIQ localChannelsInfo) {
-
- if (conferenceState == null
- || StringUtils.isNullOrEmpty(conferenceState.getID()))
- {
- // We are not initialized yet
- return null;
- }
-
- assertRequestType(RequestType.RTP_DESCRIPTION_UPDATE);
-
- request.setType(IQ.Type.SET);
-
- for (Map.Entry<String, RtpDescriptionPacketExtension> e
- : map.entrySet())
+ private ColibriConferenceIQ.ChannelCommon getRequestChannel(
+ ColibriConferenceIQ.Content requestContent,
+ ColibriConferenceIQ.ChannelCommon localChannelInfo)
+ {
+ ColibriConferenceIQ.ChannelCommon reqChannel
+ = requestContent.getChannel(localChannelInfo.getID());
+ if (reqChannel == null)
{
- String contentName = e.getKey();
- ColibriConferenceIQ.ChannelCommon channel
- = getColibriChannel(localChannelsInfo, contentName);
-
- if (channel != null
- && channel instanceof ColibriConferenceIQ.Channel)
+ if (localChannelInfo instanceof ColibriConferenceIQ.Channel)
{
- RtpDescriptionPacketExtension rtpPE = e.getValue();
- if (rtpPE == null)
- {
- continue;
- }
-
- List<PayloadTypePacketExtension> pts = rtpPE.getPayloadTypes();
- if (pts == null || pts.isEmpty())
- {
- continue;
- }
-
- ColibriConferenceIQ.Channel channelRequest
- = new ColibriConferenceIQ.Channel();
+ reqChannel = new ColibriConferenceIQ.Channel();
+ }
+ else if (
+ localChannelInfo instanceof ColibriConferenceIQ.SctpConnection)
+ {
+ reqChannel = new ColibriConferenceIQ.SctpConnection();
+ }
+ else
+ {
+ throw new RuntimeException(
+ "Unsupported ChannelCommon class: "
+ + localChannelInfo.getClass());
+ }
- channelRequest.setID(channel.getID());
+ reqChannel.setID(localChannelInfo.getID());
- for (PayloadTypePacketExtension ptPE : rtpPE.getPayloadTypes())
- {
- channelRequest.addPayloadType(ptPE);
- }
+ requestContent.addChannelCommon(reqChannel);
+ }
+ return reqChannel;
+ }
- request.getOrCreateContent(contentName)
- .addChannel(channelRequest);
- }
+ private ColibriConferenceIQ.Channel getRtpChannel(
+ ColibriConferenceIQ localChannelsInfo,
+ String contentName)
+ {
+ ColibriConferenceIQ.Content content
+ = localChannelsInfo.getContent(contentName);
- }
+ if (content == null)
+ return null;
- return this;
+ return content.getChannelCount() > 0 ? content.getChannel(0) : null;
}
/**
@@ -808,19 +1086,10 @@ public class ColibriBuilder
ALLOCATE_CHANNELS,
/**
- * Updates transport information for channels that use RTP bundle.
- */
- BUNDLE_TRANSPORT_UPDATE,
-
- /**
- * Updates channel transport information(ICE transport candidates).
+ * An update request which is meant to modify some values of existing
+ * Colibri channels on the bridge.
*/
- TRANSPORT_UPDATE,
-
- /**
- * Updates the RTP description of a channel (payload types).
- */
- RTP_DESCRIPTION_UPDATE,
+ CHANNEL_INFO_UPDATE,
/**
* Expires specified Colibri channels.
@@ -833,4 +1102,28 @@ public class ColibriBuilder
*/
UNDEFINED;
}
+
+ /**
+ * Configures RTP-level relay (RFC 3550, section 2.3).
+ * @param rtpLevelRelayType an <tt>RTPLevelRelayType</tt> value which
+ * stands for the rtp level relay type that will be set on all created
+ * audio channels.
+ */
+ public void setRTPLevelRelayType(RTPLevelRelayType rtpLevelRelayType)
+ {
+ this.rtpLevelRelayType = rtpLevelRelayType;
+ }
+
+ /**
+ * Configures RTP-level relay (RFC 3550, section 2.3).
+ * @param rtpLevelRelayType a <tt>String</tt> value which
+ * stands for the rtp level relay type that will be set on all created
+ * audio channels.
+ */
+ public void setRTPLevelRelayType(String rtpLevelRelayType)
+ {
+ setRTPLevelRelayType
+ (RTPLevelRelayType.parseRTPLevelRelayType(rtpLevelRelayType));
+ }
+
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriConferenceIQ.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriConferenceIQ.java
index 52368bf..d5cf175 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriConferenceIQ.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriConferenceIQ.java
@@ -161,7 +161,7 @@ public class ColibriConferenceIQ
throw new NullPointerException("channelBundle");
return
- channelBundles.contains(channelBundles)
+ channelBundles.contains(channelBundle)
? false
: channelBundles.add(channelBundle);
}
@@ -543,6 +543,14 @@ public class ColibriConferenceIQ
= "receive-simulcast-layer";
/**
+ * The XML name of the <tt>packet-delay</tt> attribute of
+ * a <tt>channel</tt> of a <tt>content</tt> of a <tt>conference</tt> IQ
+ * which represents the value of the {@link #packetDelay} property of
+ * <tt>ColibriConferenceIQ.Channel</tt>.
+ */
+ public static final String PACKET_DELAY_ATTR_NAME = "packet-delay";
+
+ /**
* The XML name of the <tt>rtcpport</tt> attribute of a <tt>channel</tt>
* of a <tt>content</tt> of a <tt>conference</tt> IQ which represents
* the value of the <tt>rtcpPort</tt> property of
@@ -613,6 +621,11 @@ public class ColibriConferenceIQ
private SimulcastMode simulcastMode;
/**
+ * The amount of delay added to the RTP stream in a number of packets.
+ */
+ private Integer packetDelay;
+
+ /**
* The <tt>payload-type</tt> elements defined by XEP-0167: Jingle RTP
* Sessions associated with this <tt>channel</tt>.
*/
@@ -893,6 +906,18 @@ public class ColibriConferenceIQ
}
/**
+ * Returns an <tt>Integer</tt> which stands for the amount of delay
+ * added to the RTP stream in a number of packets.
+ *
+ * @return <tt>Integer</tt> with the value or <tt>null</tt> if
+ * unspecified.
+ */
+ public Integer getPacketDelay()
+ {
+ return packetDelay;
+ }
+
+ /**
* Gets a list of <tt>payload-type</tt> elements defined by XEP-0167:
* Jingle RTP Sessions added to this <tt>channel</tt>.
*
@@ -1077,8 +1102,16 @@ public class ColibriConferenceIQ
if (adaptiveSimulcast != null)
{
- xml.append(' ').append(adaptiveSimulcast).append("='")
- .append(adaptiveSimulcast).append('\'');
+ xml.append(' ').append(ADAPTIVE_SIMULCAST_ATTR_NAME)
+ .append("='").append(adaptiveSimulcast).append('\'');
+ }
+
+ // packet-delay
+ Integer packetDelay = getPacketDelay();
+ if (packetDelay != null)
+ {
+ xml.append(' ').append(PACKET_DELAY_ATTR_NAME).append("='")
+ .append(packetDelay).append('\'');
}
// simulcastMode
@@ -1314,6 +1347,17 @@ public class ColibriConferenceIQ
}
/**
+ * Configures channel's packet delay which tells by how many packets
+ * the RTP streams will be delayed.
+ * @param packetDelay an <tt>Integer</tt> value which stands for
+ * the packet delay that will be set or <tt>null</tt> to leave undefined
+ */
+ public void setPacketDelay(Integer packetDelay)
+ {
+ this.packetDelay = packetDelay;
+ }
+
+ /**
* Sets the value of the 'simulcast-mode' flag.
* @param simulcastMode the value to set.
*/
@@ -1925,6 +1969,25 @@ public class ColibriConferenceIQ
}
/**
+ * Adds <tt>ChannelCommon</tt> to this <tt>Content</tt>.
+ * @param channelCommon {@link ChannelCommon} instance to be added to
+ * this content.
+ * @return <tt>true</tt> if given <tt>channelCommon</tt> has been
+ * actually added to this <tt>Content</tt> instance.
+ */
+ public boolean addChannelCommon(ChannelCommon channelCommon)
+ {
+ if (channelCommon instanceof Channel)
+ {
+ return addChannel((Channel) channelCommon);
+ }
+ else
+ {
+ return addSctpConnection((SctpConnection) channelCommon);
+ }
+ }
+
+ /**
* Adds a specific <tt>SctpConnection</tt> to the list of
* <tt>SctpConnection</tt>s included into this <tt>Content</tt>.
*
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriIQProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriIQProvider.java
index 39e299f..ce676ef 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriIQProvider.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriIQProvider.java
@@ -20,6 +20,7 @@ package net.java.sip.communicator.impl.protocol.jabber.extensions.colibri;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+import net.java.sip.communicator.service.protocol.jabber.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.util.*;
import org.jivesoftware.smack.packet.*;
@@ -36,89 +37,101 @@ import org.xmlpull.v1.*;
public class ColibriIQProvider
implements IQProvider
{
+
+ /**
+ * Smack interoperation layer
+ */
+ private AbstractSmackInteroperabilityLayer smackInteroperabilityLayer =
+ AbstractSmackInteroperabilityLayer.getInstance();
+
/** Initializes a new <tt>ColibriIQProvider</tt> instance. */
public ColibriIQProvider()
{
- ProviderManager providerManager = ProviderManager.getInstance();
-
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
PayloadTypePacketExtension.ELEMENT_NAME,
ColibriConferenceIQ.NAMESPACE,
new DefaultPacketExtensionProvider<PayloadTypePacketExtension>(
PayloadTypePacketExtension.class));
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
RtcpFbPacketExtension.ELEMENT_NAME,
RtcpFbPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<RtcpFbPacketExtension>(
RtcpFbPacketExtension.class));
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
RTPHdrExtPacketExtension.ELEMENT_NAME,
ColibriConferenceIQ.NAMESPACE,
new DefaultPacketExtensionProvider<RTPHdrExtPacketExtension>(
RTPHdrExtPacketExtension.class));
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
SourcePacketExtension.ELEMENT_NAME,
SourcePacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<SourcePacketExtension>(
SourcePacketExtension.class));
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
SourceGroupPacketExtension.ELEMENT_NAME,
SourceGroupPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<SourceGroupPacketExtension>(
SourceGroupPacketExtension.class));
PacketExtensionProvider parameterProvider
- = new DefaultPacketExtensionProvider<ParameterPacketExtension>(
- ParameterPacketExtension.class);
+ = new DefaultPacketExtensionProvider<ParameterPacketExtension>(
+ ParameterPacketExtension.class);
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
ParameterPacketExtension.ELEMENT_NAME,
ColibriConferenceIQ.NAMESPACE,
parameterProvider);
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
ParameterPacketExtension.ELEMENT_NAME,
SourcePacketExtension.NAMESPACE,
parameterProvider);
// Shutdown IQ
- providerManager.addIQProvider(
- GracefulShutdownIQ.ELEMENT_NAME,
- GracefulShutdownIQ.NAMESPACE,
+ smackInteroperabilityLayer.addIQProvider(
+ ShutdownIQ.GRACEFUL_ELEMENT_NAME,
+ ShutdownIQ.NAMESPACE,
+ this);
+ smackInteroperabilityLayer.addIQProvider(
+ ShutdownIQ.FORCE_ELEMENT_NAME,
+ ShutdownIQ.NAMESPACE,
this);
// Shutdown extension
PacketExtensionProvider shutdownProvider
- = new DefaultPacketExtensionProvider
- <ColibriConferenceIQ.GracefulShutdown>(
- ColibriConferenceIQ.GracefulShutdown.class);
+ = new DefaultPacketExtensionProvider
+ <ColibriConferenceIQ.GracefulShutdown>(
+ ColibriConferenceIQ.GracefulShutdown.class);
- providerManager.addExtensionProvider(
- ColibriConferenceIQ.GracefulShutdown.ELEMENT_NAME,
- ColibriConferenceIQ.GracefulShutdown.NAMESPACE,
- shutdownProvider);
+ smackInteroperabilityLayer.addExtensionProvider(
+ ColibriConferenceIQ.GracefulShutdown.ELEMENT_NAME,
+ ColibriConferenceIQ.GracefulShutdown.NAMESPACE,
+ shutdownProvider);
// ColibriStatsIQ
- providerManager.addIQProvider(
- ColibriStatsIQ.ELEMENT_NAME,
- ColibriStatsIQ.NAMESPACE,
- this);
+ smackInteroperabilityLayer.addIQProvider(
+ ColibriStatsIQ.ELEMENT_NAME,
+ ColibriStatsIQ.NAMESPACE,
+ this);
// ColibriStatsExtension
PacketExtensionProvider statsProvider
- = new DefaultPacketExtensionProvider<ColibriStatsExtension>(
- ColibriStatsExtension.class);
+ = new DefaultPacketExtensionProvider<ColibriStatsExtension>(
+ ColibriStatsExtension.class);
- providerManager.addExtensionProvider(
- ColibriStatsExtension.ELEMENT_NAME,
- ColibriStatsExtension.NAMESPACE,
- statsProvider);
+ smackInteroperabilityLayer.addExtensionProvider(
+ ColibriStatsExtension.ELEMENT_NAME,
+ ColibriStatsExtension.NAMESPACE,
+ statsProvider);
// ColibriStatsExtension.Stat
PacketExtensionProvider statProvider
- = new DefaultPacketExtensionProvider<ColibriStatsExtension.Stat>(
- ColibriStatsExtension.Stat.class);
-
- providerManager.addExtensionProvider(
- ColibriStatsExtension.Stat.ELEMENT_NAME,
- ColibriStatsExtension.NAMESPACE,
- statProvider);
+ = new DefaultPacketExtensionProvider
+ <ColibriStatsExtension.Stat>(
+ ColibriStatsExtension.Stat.class);
+
+ smackInteroperabilityLayer.addExtensionProvider(
+ ColibriStatsExtension.Stat.ELEMENT_NAME,
+ ColibriStatsExtension.NAMESPACE,
+ statProvider);
+
+
}
private void addChildExtension(
@@ -199,8 +212,7 @@ public class ColibriIQProvider
throws Exception
{
PacketExtensionProvider extensionProvider
- = (PacketExtensionProvider)
- ProviderManager.getInstance().getExtensionProvider(
+ = smackInteroperabilityLayer.getExtensionProvider(
name,
namespace);
PacketExtension extension;
@@ -416,6 +428,15 @@ public class ColibriIQProvider
if ((expire != null) && (expire.length() != 0))
channel.setExpire(Integer.parseInt(expire));
+ String packetDelay
+ = parser.getAttributeValue(
+ "",
+ ColibriConferenceIQ.Channel
+ .PACKET_DELAY_ATTR_NAME);
+ if (!StringUtils.isNullOrEmpty(packetDelay))
+ channel.setPacketDelay(
+ Integer.parseInt(packetDelay));
+
// host
String host
= parser.getAttributeValue(
@@ -464,6 +485,18 @@ public class ColibriIQProvider
channel.setAdaptiveLastN(
Boolean.parseBoolean(adaptiveLastN));
+ String adaptiveSimulcast
+ = parser.getAttributeValue(
+ "",
+ ColibriConferenceIQ.Channel
+ .ADAPTIVE_SIMULCAST_ATTR_NAME);
+
+ if (!StringUtils.isNullOrEmpty(adaptiveSimulcast))
+ {
+ channel.setAdaptiveSimulcast(
+ Boolean.parseBoolean(adaptiveSimulcast));
+ }
+
// simulcastMode
String simulcastMode
= parser.getAttributeValue(
@@ -802,12 +835,12 @@ public class ColibriIQProvider
iq = conference;
}
- else if (GracefulShutdownIQ.ELEMENT_NAME.equals(parser.getName())
- && GracefulShutdownIQ.NAMESPACE.equals(namespace))
+ else if (ShutdownIQ.NAMESPACE.equals(namespace) &&
+ ShutdownIQ.isValidElementName(parser.getName()))
{
String rootElement = parser.getName();
- iq = new GracefulShutdownIQ();
+ iq = ShutdownIQ.createShutdownIQ(rootElement);
boolean done = false;
@@ -825,12 +858,6 @@ public class ColibriIQProvider
}
break;
}
-
- case XmlPullParser.TEXT:
- {
- // Parse some text here
- break;
- }
}
}
}
@@ -891,12 +918,6 @@ public class ColibriIQProvider
}
break;
}
-
- case XmlPullParser.TEXT:
- {
- // Parse some text here
- break;
- }
}
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriStreamConnector.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriStreamConnector.java
index d5a6ce1..ef80392 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriStreamConnector.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ColibriStreamConnector.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,74 +15,74 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.jabber.extensions.colibri;
-
-import org.jitsi.service.neomedia.*;
-
-/**
- * Implements a <tt>StreamConnector</tt> which allows sharing a specific
- * <tt>StreamConnector</tt> instance among multiple <tt>TransportManager</tt>s
- * for the purposes of the Jitsi Videobridge.
- *
- * @author Lyubomir Marinov
- */
-public class ColibriStreamConnector
- extends StreamConnectorDelegate<StreamConnector>
-{
- /**
- * Initializes a new <tt>ColibriStreamConnector</tt> instance which is to
- * share a specific <tt>StreamConnector</tt> instance among multiple
- * <tt>TransportManager</tt>s for the purposes of the Jitsi Videobridge.
- *
- * @param streamConnector the <tt>StreamConnector</tt> instance to be shared
- * by the new instance among multiple <tt>TransportManager</tt>s for the
- * purposes of the Jitsi Videobridge
- */
- public ColibriStreamConnector(StreamConnector streamConnector)
- {
- super(streamConnector);
- }
-
- /**
- * {@inheritDoc}
- *
- * Overrides {@link StreamConnectorDelegate#close()} in order to prevent the
- * closing of the <tt>StreamConnector</tt> wrapped by this instance because
- * the latter is shared and it is not clear whether no
- * <tt>TransportManager</tt> is using it.
- */
- @Override
- public void close()
- {
- /*
- * Do not close the shared StreamConnector because it is not clear
- * whether no TransportManager is using it.
- */
- }
-
- /**
- * {@inheritDoc}
- *
- * Invokes {@link #close()} on this instance when it is clear that no
- * <tt>TransportManager</tt> is using it in order to release the resources
- * allocated by this instance throughout its life time (that need explicit
- * disposal).
- */
- @Override
- protected void finalize()
- throws Throwable
- {
- try
- {
- /*
- * Close the shared StreamConnector because it is clear that no
- * TrasportManager is using it.
- */
- super.close();
- }
- finally
- {
- super.finalize();
- }
- }
-}
+package net.java.sip.communicator.impl.protocol.jabber.extensions.colibri;
+
+import org.jitsi.service.neomedia.*;
+
+/**
+ * Implements a <tt>StreamConnector</tt> which allows sharing a specific
+ * <tt>StreamConnector</tt> instance among multiple <tt>TransportManager</tt>s
+ * for the purposes of the Jitsi Videobridge.
+ *
+ * @author Lyubomir Marinov
+ */
+public class ColibriStreamConnector
+ extends StreamConnectorDelegate<StreamConnector>
+{
+ /**
+ * Initializes a new <tt>ColibriStreamConnector</tt> instance which is to
+ * share a specific <tt>StreamConnector</tt> instance among multiple
+ * <tt>TransportManager</tt>s for the purposes of the Jitsi Videobridge.
+ *
+ * @param streamConnector the <tt>StreamConnector</tt> instance to be shared
+ * by the new instance among multiple <tt>TransportManager</tt>s for the
+ * purposes of the Jitsi Videobridge
+ */
+ public ColibriStreamConnector(StreamConnector streamConnector)
+ {
+ super(streamConnector);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overrides {@link StreamConnectorDelegate#close()} in order to prevent the
+ * closing of the <tt>StreamConnector</tt> wrapped by this instance because
+ * the latter is shared and it is not clear whether no
+ * <tt>TransportManager</tt> is using it.
+ */
+ @Override
+ public void close()
+ {
+ /*
+ * Do not close the shared StreamConnector because it is not clear
+ * whether no TransportManager is using it.
+ */
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Invokes {@link #close()} on this instance when it is clear that no
+ * <tt>TransportManager</tt> is using it in order to release the resources
+ * allocated by this instance throughout its life time (that need explicit
+ * disposal).
+ */
+ @Override
+ protected void finalize()
+ throws Throwable
+ {
+ try
+ {
+ /*
+ * Close the shared StreamConnector because it is clear that no
+ * TrasportManager is using it.
+ */
+ super.close();
+ }
+ finally
+ {
+ super.finalize();
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ShutdownIQ.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ShutdownIQ.java
new file mode 100644
index 0000000..4df251b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/ShutdownIQ.java
@@ -0,0 +1,134 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.colibri;
+
+import org.jivesoftware.smack.packet.*;
+
+/**
+ * The IQ used to trigger the graceful shutdown mode of the videobridge or force
+ * shutdown the one which receives the stanza(given that source JID is
+ * authorized to do so).
+ *
+ * @author Pawel Domas
+ */
+public class ShutdownIQ
+ extends IQ
+{
+ /**
+ * XML namespace name for shutdown IQs.
+ */
+ final static public String NAMESPACE = ColibriConferenceIQ.NAMESPACE;
+
+ /**
+ * Force shutdown IQ element name.
+ */
+ final static public String FORCE_ELEMENT_NAME = "force-shutdown";
+
+ /**
+ * Graceful shutdown IQ element name.
+ */
+ final static public String GRACEFUL_ELEMENT_NAME = "graceful-shutdown";
+
+ /**
+ * The element name of this IQ. Either {@link #FORCE_ELEMENT_NAME} or
+ * {@link #GRACEFUL_ELEMENT_NAME}.
+ */
+ private final String elementName;
+
+ /**
+ * Checks if given element is a valid one for <tt>ShutdownIQ</tt>.
+ *
+ * @param elementName the name if XML element name inside of the IQ.
+ *
+ * @return <tt>true</tt> if given <tt>elementName</tt> is correct for
+ * <tt>ShutdownIQ</tt>.
+ */
+ public static boolean isValidElementName(String elementName)
+ {
+ return GRACEFUL_ELEMENT_NAME.equals(elementName)
+ || FORCE_ELEMENT_NAME.equals(elementName);
+ }
+
+ /**
+ * Creates shutdown IQ for given element name.
+ *
+ * @param elementName can be {@link #FORCE_ELEMENT_NAME} or
+ * {@link #GRACEFUL_ELEMENT_NAME}
+ *
+ * @return new <tt>ShutdownIQ</tt> instance for given element name.
+ *
+ * @throws IllegalArgumentException if given element name is neither
+ * {@link #FORCE_ELEMENT_NAME} nor {@link #GRACEFUL_ELEMENT_NAME}.
+ */
+ public static ShutdownIQ createShutdownIQ(String elementName)
+ {
+ if (!isValidElementName(elementName))
+ {
+ throw new IllegalArgumentException(
+ "Invalid element name: " + elementName);
+ }
+
+ if (GRACEFUL_ELEMENT_NAME.equals(elementName))
+ {
+ return createGracefulShutdownIQ();
+ }
+ else
+ {
+ return createForceShutdownIQ();
+ }
+ }
+
+ /**
+ * Creates and returns new instance of graceful shutdown IQ.
+ */
+ public static ShutdownIQ createGracefulShutdownIQ()
+ {
+ return new ShutdownIQ(GRACEFUL_ELEMENT_NAME);
+ }
+
+ /**
+ * Creates and returns new instance of force shutdown IQ.
+ */
+ public static ShutdownIQ createForceShutdownIQ()
+ {
+ return new ShutdownIQ(FORCE_ELEMENT_NAME);
+ }
+
+ private ShutdownIQ(String elementName)
+ {
+ this.elementName = elementName;
+ }
+
+ /**
+ * Returns <tt>true</tt> if this IQ instance is a "graceful shutdown" one.
+ * Otherwise it is a force shutdown IQ.
+ */
+ public boolean isGracefulShutdown()
+ {
+ return elementName.equals(GRACEFUL_ELEMENT_NAME);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getChildElementXML()
+ {
+ return "<" + elementName + " xmlns='" + NAMESPACE + "' />";
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/GracefulShutdownIQ.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/health/HealthCheckIQ.java
index 9808b11..661bb1b 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/colibri/GracefulShutdownIQ.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/health/HealthCheckIQ.java
@@ -15,23 +15,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.jabber.extensions.colibri;
+package net.java.sip.communicator.impl.protocol.jabber.extensions.health;
import org.jivesoftware.smack.packet.*;
/**
- * The IQ used to trigger the graceful shutdown mode of the videobridge which
- * receives the stanza(given that source JID is authorized to start it).
+ * The health check IQ used to trigger health checks on the Jitsi Videobridge.
*
* @author Pawel Domas
*/
-public class GracefulShutdownIQ
+public class HealthCheckIQ
extends IQ
{
- public static final String NAMESPACE = ColibriConferenceIQ.NAMESPACE;
+ /**
+ * Health check IQ element name.
+ */
+ final static public String ELEMENT_NAME = "healthcheck";
- public static final String ELEMENT_NAME = "graceful-shutdown";
+ /**
+ * XML namespace name for health check IQs.
+ */
+ final static public String NAMESPACE
+ = "http://jitsi.org/protocol/healthcheck";
+ /**
+ * {@inheritDoc}
+ */
@Override
public String getChildElementXML()
{
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/health/HealthCheckIQProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/health/HealthCheckIQProvider.java
new file mode 100644
index 0000000..9c2903d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/health/HealthCheckIQProvider.java
@@ -0,0 +1,94 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.health;
+
+import net.java.sip.communicator.service.protocol.jabber.*;
+
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.provider.*;
+
+import org.xmlpull.v1.*;
+
+/**
+ * The <tt>IQProvider</tt> for {@link HealthCheckIQ}.
+ *
+ * @author Pawel Domas
+ */
+public class HealthCheckIQProvider
+ implements IQProvider
+{
+ /**
+ * Registers <tt>HealthCheckIQProvider</tt> as an <tt>IQProvider</tt>
+ * in {@link AbstractSmackInteroperabilityLayer}.
+ */
+ public static void registerIQProvider()
+ {
+ AbstractSmackInteroperabilityLayer smackInteropLayer =
+ AbstractSmackInteroperabilityLayer.getInstance();
+
+ // ColibriStatsIQ
+ smackInteropLayer.addIQProvider(
+ HealthCheckIQ.ELEMENT_NAME,
+ HealthCheckIQ.NAMESPACE,
+ new HealthCheckIQProvider());
+ }
+
+ /**
+ * Parses <tt>HealthCheckIQ</tt>.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public IQ parseIQ(XmlPullParser parser)
+ throws Exception
+ {
+ String namespace = parser.getNamespace();
+ IQ iq;
+
+ if (HealthCheckIQ.ELEMENT_NAME.equals(parser.getName())
+ && HealthCheckIQ.NAMESPACE.equals(namespace))
+ {
+ String rootElement = parser.getName();
+
+ iq = new HealthCheckIQ();
+
+ boolean done = false;
+
+ while (!done)
+ {
+ switch (parser.next())
+ {
+ case XmlPullParser.END_TAG:
+ {
+ String name = parser.getName();
+
+ if (rootElement.equals(name))
+ {
+ done = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ else
+ iq = null;
+
+ return iq;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriIq.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriIq.java
new file mode 100644
index 0000000..8b964af
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriIq.java
@@ -0,0 +1,413 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jibri;
+
+import org.jitsi.util.*;
+
+import org.jivesoftware.smack.packet.*;
+
+import java.util.*;
+
+/**
+ * The IQ used to control conference recording with Jibri component.
+ *
+ * Start the recording:
+ *
+ * 1. Send Jibri IQ with {@link Action#START} to Jibri.
+ * 2. Jibri replies with RESULT and status {@link Status#PENDING}.
+ * 3. Jibri sends SET IQ with status {@link Status#ON} once recording actually
+ * starts.
+ *
+ * Stop the recording:
+ *
+ * 1. Send Jibri IQ with {@link Action#STOP} to Jibri.
+ * 2. Jibri replies with {@link Status#OFF} immediately if the recording has
+ * been stopped already or sends separate Jibri SET IQ later on if it takes
+ * more time.
+ *
+ * @author lishunyang
+ * @author Pawel Domas
+ */
+public class JibriIq
+ extends IQ
+{
+ /**
+ * Attribute name of "action".
+ */
+ public static final String ACTION_ATTR_NAME = "action";
+
+ /**
+ * XML element name of the Jibri IQ.
+ */
+ public static final String ELEMENT_NAME = "jibri";
+
+ /**
+ * XML namespace of the Jibri IQ.
+ */
+ public static final String NAMESPACE = "http://jitsi.org/protocol/jibri";
+
+ /**
+ * The name of XML attribute which stores the recording status.
+ */
+ static final String STATUS_ATTR_NAME = "status";
+
+ /**
+ * The name of XML attribute which stores the stream id.
+ */
+ static final String STREAM_ID_ATTR_NAME = "streamid";
+
+ /**
+ * The name of XML attribute which stores the name of the conference room to
+ * be recorded.
+ */
+ static final String ROOM_ATTR_NAME = "room";
+
+ /**
+ * Holds the action.
+ */
+ private Action action = Action.UNDEFINED;
+
+ /**
+ * XMPPError stores error details for {@link Status#FAILED}.
+ */
+ private XMPPError error;
+
+ /**
+ * Holds recording status.
+ */
+ private Status status = Status.UNDEFINED;
+
+ /**
+ * The ID of the stream which will be used to record the conference. The
+ * value depends on recording service provider.
+ */
+ private String streamId = null;
+
+ /**
+ * The name of the conference room to be recorded.
+ */
+ private String room = null;
+
+ /**
+ * Returns the value of {@link #STREAM_ID_ATTR_NAME} attribute.
+ * @return a <tt>String</tt> which contains the value of "stream id"
+ * attribute or <tt>null</tt> if empty.
+ */
+ public String getStreamId()
+ {
+ return streamId;
+ }
+
+ /**
+ * Sets the value for {@link #STREAM_ID_ATTR_NAME} attribute.
+ * @param streamId a <tt>String</tt> for the stream id attribute or
+ * <tt>null</tt> to remove it from XML element.
+ */
+ public void setStreamId(String streamId)
+ {
+ this.streamId = streamId;
+ }
+
+ /**
+ * Returns the value of {@link #ROOM_ATTR_NAME} attribute.
+ * @return a <tt>String</tt> which contains the value of the room attribute
+ * or <tt>null</tt> if empty.
+ * @see #room
+ */
+ public String getRoom()
+ {
+ return room;
+ }
+
+ /**
+ * Sets the value for {@link #ROOM_ATTR_NAME} attribute.
+ * @param room a <tt>String</tt> for the room attribute or <tt>null</tt> to
+ * remove it from XML element.
+ * @see #room
+ */
+ public void setRoom(String room)
+ {
+ this.room = room;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getChildElementXML()
+ {
+ StringBuilder xml = new StringBuilder();
+
+ xml.append('<').append(ELEMENT_NAME);
+ xml.append(" xmlns='").append(NAMESPACE).append("' ");
+
+ if (action != Action.UNDEFINED)
+ {
+ printStringAttribute(xml, ACTION_ATTR_NAME, action.toString());
+ }
+
+ if (status != Status.UNDEFINED)
+ {
+ printStringAttribute(xml, STATUS_ATTR_NAME, status.toString());
+ }
+
+ if (room != null)
+ {
+ printStringAttribute(xml, ROOM_ATTR_NAME, room);
+ }
+
+ if (streamId != null)
+ {
+ printStringAttribute(xml, STREAM_ID_ATTR_NAME, streamId);
+ }
+
+ Collection<PacketExtension> extensions = getExtensions();
+ if (extensions.size() > 0)
+ {
+ xml.append(">");
+ for (PacketExtension extension : extensions)
+ {
+ xml.append(extension.toXML());
+ }
+ xml.append("</").append(ELEMENT_NAME).append(">");
+ }
+ else
+ {
+ xml.append("/>");
+ }
+
+ return xml.toString();
+ }
+
+ private void printStringAttribute(
+ StringBuilder xml, String attrName, String attr)
+ {
+ if (!StringUtils.isNullOrEmpty(attr))
+ {
+ attr = org.jivesoftware.smack.util.StringUtils.escapeForXML(attr);
+ xml.append(attrName).append("='")
+ .append(attr).append("' ");
+ }
+ }
+
+ /**
+ * Sets the value of 'action' attribute.
+ *
+ * @param action the value to be set as 'action' attribute of this IQ.
+ */
+ public void setAction(Action action)
+ {
+ this.action = action;
+ }
+
+ /**
+ * Returns the value of 'action' attribute.
+ */
+ public Action getAction()
+ {
+ return action;
+ }
+
+ /**
+ * Sets the value of 'status' attribute.
+ */
+ public void setStatus(Status status)
+ {
+ this.status = status;
+ }
+
+ /**
+ * Returns the value of 'status' attribute.
+ */
+ public Status getStatus()
+ {
+ return status;
+ }
+
+ /**
+ * Sets the <tt>XMPPError</tt> which will provide details about Jibri
+ * failure. It is expected to be set when this IQ's status value is
+ * {@link Status#FAILED}.
+ *
+ * @param error <tt>XMPPError</tt> to be set on this <tt>JibriIq</tt>
+ * instance.
+ */
+ public void setXMPPError(XMPPError error)
+ {
+ this.error = error;
+ }
+
+ /**
+ * Returns {@link XMPPError} with Jibri error details when the status is
+ * {@link Status#FAILED}.
+ */
+ public XMPPError getError()
+ {
+ return error;
+ }
+
+ /**
+ * Enumerative value of attribute "action" in recording extension.
+ *
+ * @author lishunyang
+ * @author Pawel Domas
+ *
+ */
+ public enum Action
+ {
+ /**
+ * Start the recording.
+ */
+ START("start"),
+ /**
+ * Stop the recording.
+ */
+ STOP("stop"),
+ /**
+ * Unknown/uninitialized
+ */
+ UNDEFINED("undefined");
+
+ private String name;
+
+ Action(String name)
+ {
+ this.name = name;
+ }
+
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Parses <tt>Action</tt> from given string.
+ *
+ * @param action the string representation of <tt>Action</tt>.
+ *
+ * @return <tt>Action</tt> value for given string or
+ * {@link #UNDEFINED} if given string does not
+ * reflect any of valid values.
+ */
+ public static Action parse(String action)
+ {
+ if (StringUtils.isNullOrEmpty(action))
+ return UNDEFINED;
+
+ try
+ {
+ return Action.valueOf(action.toUpperCase());
+ }
+ catch(IllegalArgumentException e)
+ {
+ return UNDEFINED;
+ }
+ }
+ }
+
+ /**
+ * The enumeration of recording status values.
+ */
+ public enum Status
+ {
+ /**
+ * Recording is in progress.
+ */
+ ON("on"),
+
+ /**
+ * Recording stopped.
+ */
+ OFF("off"),
+
+ /**
+ * Starting the recording process.
+ */
+ PENDING("pending"),
+
+ /**
+ * The recorder has failed and the service is retrying on another
+ * instance.
+ */
+ RETRYING("retrying"),
+
+ /**
+ * An error occurred any point during startup, recording or shutdown.
+ */
+ FAILED("failed"),
+
+ /**
+ * There are Jibri instances connected to the system, but all of them
+ * are currently busy.
+ */
+ BUSY("busy"),
+
+ /**
+ * Unknown/uninitialized.
+ */
+ UNDEFINED("undefined");
+
+ /**
+ * Status name holder.
+ */
+ private String name;
+
+ /**
+ * Creates new {@link Status} instance.
+ * @param name a string corresponding to one of {@link Status} values.
+ */
+ Status(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Parses <tt>Status</tt> from given string.
+ *
+ * @param status the string representation of <tt>Status</tt>.
+ *
+ * @return <tt>Status</tt> value for given string or
+ * {@link #UNDEFINED} if given string does not
+ * reflect any of valid values.
+ */
+ public static Status parse(String status)
+ {
+ if (StringUtils.isNullOrEmpty(status))
+ return UNDEFINED;
+
+ try
+ {
+ return Status.valueOf(status.toUpperCase());
+ }
+ catch(IllegalArgumentException e)
+ {
+ return UNDEFINED;
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriIqProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriIqProvider.java
new file mode 100644
index 0000000..155853c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriIqProvider.java
@@ -0,0 +1,112 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jibri;
+
+import org.jitsi.util.*;
+
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.provider.*;
+import org.jivesoftware.smack.util.PacketParserUtils;
+
+import org.xmlpull.v1.*;
+
+/**
+ * Parses {@link JibriIq}.
+ */
+public class JibriIqProvider
+ implements IQProvider
+{
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IQ parseIQ(XmlPullParser parser)
+ throws Exception
+ {
+ String namespace = parser.getNamespace();
+
+ // Check the namespace
+ if (!JibriIq.NAMESPACE.equals(namespace))
+ {
+ return null;
+ }
+
+ String rootElement = parser.getName();
+
+ JibriIq iq;
+
+ if (JibriIq.ELEMENT_NAME.equals(rootElement))
+ {
+ iq = new JibriIq();
+
+ String action
+ = parser.getAttributeValue("", JibriIq.ACTION_ATTR_NAME);
+ iq.setAction(JibriIq.Action.parse(action));
+
+ String status
+ = parser.getAttributeValue("", JibriIq.STATUS_ATTR_NAME);
+ iq.setStatus(JibriIq.Status.parse(status));
+
+ String room
+ = parser.getAttributeValue("", JibriIq.ROOM_ATTR_NAME);
+ if (!StringUtils.isNullOrEmpty(room))
+ iq.setRoom(room);
+
+ String streamId
+ = parser.getAttributeValue("", JibriIq.STREAM_ID_ATTR_NAME);
+ if (!StringUtils.isNullOrEmpty(streamId))
+ iq.setStreamId(streamId);
+ }
+ else
+ {
+ return null;
+ }
+
+ boolean done = false;
+
+ while (!done)
+ {
+ switch (parser.next())
+ {
+ case XmlPullParser.START_TAG:
+ {
+ String name = parser.getName();
+
+ if ("error".equals(name))
+ {
+ XMPPError error = PacketParserUtils.parseError(parser);
+ iq.setXMPPError(error);
+ }
+ break;
+ }
+ case XmlPullParser.END_TAG:
+ {
+ String name = parser.getName();
+
+ if (rootElement.equals(name))
+ {
+ done = true;
+ }
+ break;
+ }
+ }
+ }
+
+ return iq;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriStatusPacketExt.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriStatusPacketExt.java
new file mode 100644
index 0000000..e046b68
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/JibriStatusPacketExt.java
@@ -0,0 +1,121 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jibri;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
+
+import org.jitsi.util.*;
+
+import org.jivesoftware.smack.provider.*;
+
+/**
+ * Status extension included in MUC presence by Jibri to indicate it's status.
+ * One of:
+ * <li>idle</li> - the instance is idle and can be used for recording
+ * <li>busy</li> - the instance is currently recording or doing something very
+ * important and should not be disturbed
+ *
+ *
+ */
+public class JibriStatusPacketExt
+ extends AbstractPacketExtension
+{
+ /**
+ * The namespace of this packet extension.
+ */
+ public static final String NAMESPACE = JibriIq.NAMESPACE;
+
+ /**
+ * XML element name of this packet extension.
+ */
+ public static final String ELEMENT_NAME = "jibri-status";
+
+ private static final String STATUS_ATTRIBUTE = "status";
+
+ /**
+ * Creates new instance of <tt>VideoMutedExtension</tt>.
+ */
+ public JibriStatusPacketExt()
+ {
+ super(NAMESPACE, ELEMENT_NAME);
+ }
+
+ static public void registerExtensionProvider()
+ {
+ ProviderManager.getInstance().addExtensionProvider(
+ ELEMENT_NAME,
+ NAMESPACE,
+ new DefaultPacketExtensionProvider<JibriStatusPacketExt>(
+ JibriStatusPacketExt.class)
+ );
+ }
+
+ public Status getStatus()
+ {
+ return Status.parse(getAttributeAsString(STATUS_ATTRIBUTE));
+ }
+
+ public void setStatus(Status status)
+ {
+ setAttribute(STATUS_ATTRIBUTE, String.valueOf(status));
+ }
+
+ public enum Status
+ {
+ IDLE("idle"),
+ BUSY("busy"),
+ UNDEFINED("undefined");
+
+ private String name;
+
+ Status(String name)
+ {
+ this.name = name;
+ }
+
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Parses <tt>Status</tt> from given string.
+ *
+ * @param status the string representation of <tt>Status</tt>.
+ *
+ * @return <tt>Status</tt> value for given string or
+ * {@link #UNDEFINED} if given string does not
+ * reflect any of valid values.
+ */
+ public static Status parse(String status)
+ {
+ if (StringUtils.isNullOrEmpty(status))
+ return UNDEFINED;
+
+ try
+ {
+ return Status.valueOf(status.toUpperCase());
+ }
+ catch(IllegalArgumentException e)
+ {
+ return UNDEFINED;
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/RecordingStatus.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/RecordingStatus.java
new file mode 100644
index 0000000..13177cf
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/RecordingStatus.java
@@ -0,0 +1,126 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jibri;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
+
+import org.jivesoftware.smack.packet.*;
+
+import java.util.*;
+
+/**
+ * The packet extension added to Jicofo MUC presence to broadcast current
+ * recording status to all conference participants.
+ *
+ * Status meaning:
+ * <tt>{@link JibriIq.Status#UNDEFINED}</tt> - recording not available
+ * <tt>{@link JibriIq.Status#OFF}</tt> - recording stopped(available to start)
+ * <tt>{@link JibriIq.Status#PENDING}</tt> - starting recording
+ * <tt>{@link JibriIq.Status#ON}</tt> - recording in progress
+ */
+public class RecordingStatus
+ extends AbstractPacketExtension
+{
+ /**
+ * The namespace of this packet extension.
+ */
+ public static final String NAMESPACE = JibriIq.NAMESPACE;
+
+ /**
+ * XML element name of this packet extension.
+ */
+ public static final String ELEMENT_NAME = "jibri-recording-status";
+
+ /**
+ * The name of XML attribute which holds the recording status.
+ */
+ private static final String STATUS_ATTRIBUTE = "status";
+
+ public RecordingStatus()
+ {
+ super(NAMESPACE, ELEMENT_NAME);
+ }
+
+ /**
+ * Returns the value of current recording status stored in it's attribute.
+ * @return one of {@link JibriIq.Status}
+ */
+ public JibriIq.Status getStatus()
+ {
+ String statusAttr = getAttributeAsString(STATUS_ATTRIBUTE);
+
+ return JibriIq.Status.parse(statusAttr);
+ }
+
+ /**
+ * Sets new value for the recording status.
+ * @param status one of {@link JibriIq.Status}
+ */
+ public void setStatus(JibriIq.Status status)
+ {
+ setAttribute(STATUS_ATTRIBUTE, String.valueOf(status));
+ }
+
+ /**
+ * Returns <tt>XMPPError</tt> associated with current
+ * {@link RecordingStatus}.
+ */
+ public XMPPError getError()
+ {
+ XMPPErrorPE errorPe = getErrorPE();
+ return errorPe != null ? errorPe.getError() : null;
+ }
+
+ /**
+ * Gets <tt>{@link XMPPErrorPE}</tt> from the list of child packet
+ * extensions.
+ * @return {@link XMPPErrorPE} or <tt>null</tt> if not found.
+ */
+ private XMPPErrorPE getErrorPE()
+ {
+ List<? extends PacketExtension> errorPe
+ = getChildExtensionsOfType(XMPPErrorPE.class);
+
+ return (XMPPErrorPE) (!errorPe.isEmpty() ? errorPe.get(0) : null);
+ }
+
+ /**
+ * Sets <tt>XMPPError</tt> on this <tt>RecordingStatus</tt>.
+ * @param error <tt>XMPPError</tt> to add error details to this
+ * <tt>RecordingStatus</tt> instance or <tt>null</tt> to have it removed.
+ */
+ public void setError(XMPPError error)
+ {
+ if (error != null)
+ {
+ // Wrap and add XMPPError as packet extension
+ XMPPErrorPE errorPe = getErrorPE();
+ if (errorPe == null)
+ {
+ errorPe = new XMPPErrorPE(error);
+ addChildExtension(errorPe);
+ }
+ errorPe.setError(error);
+ }
+ else
+ {
+ // Remove error PE
+ getChildExtensions().remove(getErrorPE());
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/XMPPErrorPE.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/XMPPErrorPE.java
new file mode 100644
index 0000000..a72f310
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jibri/XMPPErrorPE.java
@@ -0,0 +1,93 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jibri;
+
+import org.jivesoftware.smack.packet.*;
+
+import java.util.*;
+
+/**
+ * Wraps Smack's <tt>XMPPError</tt> into <tt>PacketExtension</tt>, so that it
+ * can be easily inserted into {@link RecordingStatus}.
+ */
+public class XMPPErrorPE
+ implements PacketExtension
+{
+ /**
+ * <tt>XMPPError</tt> wrapped into this <tt>XMPPErrorPE</tt>.
+ */
+ private XMPPError error;
+
+ /**
+ * Creates new instance of <tt>XMPPErrorPE</tt>.
+ * @param xmppError the instance of <tt>XMPPError</tt> that will be wrapped
+ * by the newly created <tt>XMPPErrorPE</tt>.
+ */
+ public XMPPErrorPE(XMPPError xmppError)
+ {
+ setError(xmppError);
+ }
+
+ /**
+ * Returns the underlying instance of <tt>XMPPError</tt>.
+ */
+ public XMPPError getError()
+ {
+ return error;
+ }
+
+ /**
+ * Sets new instance of <tt>XMPPError</tt> to be wrapped by this
+ * <tt>XMPPErrorPE</tt>.
+ * @param error <tt>XMPPError</tt> that will be wrapped by this
+ * <TT>XMPPErrorPE</TT>.
+ */
+ public void setError(XMPPError error)
+ {
+ Objects.requireNonNull(error, "error");
+
+ this.error = error;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getElementName()
+ {
+ return "error";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getNamespace()
+ {
+ return "";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toXML()
+ {
+ return error.toXML();
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CandidatePacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CandidatePacketExtension.java
index 0c5b190..46b1e77 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CandidatePacketExtension.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CandidatePacketExtension.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,441 +15,441 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle;
-
-import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
-import org.ice4j.ice.*;
-
-/**
- * @author Emil Ivov
- */
-public class CandidatePacketExtension extends AbstractPacketExtension
- implements Comparable<CandidatePacketExtension>
-{
- /**
- * The name of the "candidate" element.
- */
- public static final String ELEMENT_NAME = "candidate";
-
- /**
- * The name of the "component" element.
- */
- public static final String COMPONENT_ATTR_NAME = "component";
-
- /**
- * The "component" ID for RTP components.
- */
- public static final int RTP_COMPONENT_ID = 1;
-
- /**
- * The "component" ID for RTCP components.
- */
- public static final int RTCP_COMPONENT_ID = 2;
-
- /**
- * The name of the "foundation" element.
- */
- public static final String FOUNDATION_ATTR_NAME = "foundation";
-
- /**
- * The name of the "generation" element.
- */
- public static final String GENERATION_ATTR_NAME = "generation";
-
- /**
- * The name of the "id" element.
- */
- public static final String ID_ATTR_NAME = "id";
-
- /**
- * The name of the "ip" element.
- */
- public static final String IP_ATTR_NAME = "ip";
-
- /**
- * The name of the "network" element.
- */
- public static final String NETWORK_ATTR_NAME = "network";
-
- /**
- * The name of the "port" element.
- */
- public static final String PORT_ATTR_NAME = "port";
-
- /**
- * The name of the "priority" element.
- */
- public static final String PRIORITY_ATTR_NAME = "priority";
-
- /**
- * The name of the "protocol" element.
- */
- public static final String PROTOCOL_ATTR_NAME = "protocol";
-
- /**
- * The name of the "rel-addr" element.
- */
- public static final String REL_ADDR_ATTR_NAME = "rel-addr";
-
- /**
- * The name of the "rel-port" element.
- */
- public static final String REL_PORT_ATTR_NAME = "rel-port";
-
- /**
- * The name of the "type" element.
- */
- public static final String TYPE_ATTR_NAME = "type";
-
- /**
- * The name of the "tcptype" element.
- */
- public static final String TCPTYPE_ATTR_NAME = "tcptype";
-
- /**
- * Creates a new {@link CandidatePacketExtension}
- */
- public CandidatePacketExtension()
- {
- super(null, ELEMENT_NAME);
- }
-
- /**
- * Creates a new {@link CandidatePacketExtension} with the specified
- * <tt>elementName</tt> so that this class would be usable as a
- * <tt>RemoteCandidatePacketExtension</tt> parent.
- *
- * @param elementName the element name that this instance should be using.
- */
- protected CandidatePacketExtension(String elementName)
- {
- super(null, elementName);
- }
-
- /**
- * Sets a component ID as defined in ICE-CORE.
- *
- * @param component a component ID as defined in ICE-CORE.
- */
- public void setComponent(int component)
- {
- super.setAttribute(COMPONENT_ATTR_NAME, component);
- }
-
- /**
- * Returns a component ID as defined in ICE-CORE.
- *
- * @return a component ID as defined in ICE-CORE.
- */
- public int getComponent()
- {
- return super.getAttributeAsInt(COMPONENT_ATTR_NAME);
- }
-
- /**
- * Sets the candidate foundation as defined in ICE-CORE.
- *
- * @param foundation the candidate foundation as defined in ICE-CORE.
- */
- public void setFoundation(String foundation)
- {
- super.setAttribute(FOUNDATION_ATTR_NAME, foundation);
- }
-
- /**
- * Returns the candidate foundation as defined in ICE-CORE.
- *
- * @return the candidate foundation as defined in ICE-CORE.
- */
- public String getFoundation()
- {
- return super.getAttributeAsString(FOUNDATION_ATTR_NAME);
- }
-
- /**
- * Sets this candidate's generation index. A generation is an index,
- * starting at 0, that enables the parties to keep track of updates to the
- * candidate throughout the life of the session. For details, see the ICE
- * Restarts section of XEP-0176.
- *
- * @param generation this candidate's generation index.
- */
- public void setGeneration(int generation)
- {
- super.setAttribute(GENERATION_ATTR_NAME, generation);
- }
-
- /**
- * Returns this candidate's generation. A generation is an index, starting at
- * 0, that enables the parties to keep track of updates to the candidate
- * throughout the life of the session. For details, see the ICE Restarts
- * section of XEP-0176.
- *
- * @return this candidate's generation index.
- */
- public int getGeneration()
- {
- return super.getAttributeAsInt(GENERATION_ATTR_NAME);
- }
-
- /**
- * Sets this candidates's unique identifier <tt>String</tt>.
- *
- * @param id this candidates's unique identifier <tt>String</tt>
- */
- public void setID(String id)
- {
- super.setAttribute(ID_ATTR_NAME, id);
- }
-
- /**
- * Returns this candidates's unique identifier <tt>String</tt>.
- *
- * @return this candidates's unique identifier <tt>String</tt>
- */
- public String getID()
- {
- return super.getAttributeAsString(ID_ATTR_NAME);
- }
-
- /**
- * Sets this candidate's Internet Protocol (IP) address; this can be either
- * an IPv4 address or an IPv6 address.
- *
- * @param ip this candidate's IPv4 or IPv6 address.
- */
- public void setIP(String ip)
- {
- super.setAttribute(IP_ATTR_NAME, ip);
- }
-
- /**
- * Returns this candidate's Internet Protocol (IP) address; this can be
- * either an IPv4 address or an IPv6 address.
- *
- * @return this candidate's IPv4 or IPv6 address.
- */
- public String getIP()
- {
- return super.getAttributeAsString(IP_ATTR_NAME);
- }
-
- /**
- * The network index indicating the interface that the candidate belongs to.
- * The network ID is used for diagnostic purposes only in cases where the
- * calling hardware has more than one Network Interface Card.
- *
- * @param network the network index indicating the interface that the
- * candidate belongs to.
- */
- public void setNetwork(int network)
- {
- super.setAttribute(NETWORK_ATTR_NAME, network);
- }
-
- /**
- * Returns the network index indicating the interface that the candidate
- * belongs to. The network ID is used for diagnostic purposes only in cases
- * where the calling hardware has more than one Network Interface Card.
- *
- * @return the network index indicating the interface that the candidate
- * belongs to.
- */
- public int getNetwork()
- {
- return super.getAttributeAsInt(NETWORK_ATTR_NAME);
- }
-
- /**
- * Sets this candidate's port number.
- *
- * @param port this candidate's port number.
- */
- public void setPort(int port)
- {
- super.setAttribute(PORT_ATTR_NAME, port);
- }
-
- /**
- * Returns this candidate's port number.
- *
- * @return this candidate's port number.
- */
- public int getPort()
- {
- return super.getAttributeAsInt(PORT_ATTR_NAME);
- }
-
- /**
- * This candidate's priority as defined in ICE's RFC 5245
- *
- * @param priority this candidate's priority
- */
- public void setPriority(long priority)
- {
- super.setAttribute(PRIORITY_ATTR_NAME, priority);
- }
-
- /**
- * This candidate's priority as defined in ICE's RFC 5245
- *
- * @return this candidate's priority
- */
- public int getPriority()
- {
- return super.getAttributeAsInt(PRIORITY_ATTR_NAME);
- }
-
- /**
- * Sets this candidate's transport protocol.
- *
- * @param protocol this candidate's transport protocol.
- */
- public void setProtocol(String protocol)
- {
- super.setAttribute(PROTOCOL_ATTR_NAME, protocol);
- }
-
- /**
- * Sets this candidate's transport protocol.
- *
- * @return this candidate's transport protocol.
- */
- public String getProtocol()
- {
- return super.getAttributeAsString(PROTOCOL_ATTR_NAME);
- }
-
- /**
- * Sets this candidate's related address as described by ICE's RFC 5245.
- *
- * @param relAddr this candidate's related address as described by ICE's
- * RFC 5245.
- */
- public void setRelAddr(String relAddr)
- {
- super.setAttribute(REL_ADDR_ATTR_NAME, relAddr);
- }
-
- /**
- * Returns this candidate's related address as described by ICE's RFC 5245.
- *
- * @return this candidate's related address as described by ICE's RFC 5245.
- */
- public String getRelAddr()
- {
- return super.getAttributeAsString(REL_ADDR_ATTR_NAME);
- }
-
- /**
- * Sets this candidate's related port as described by ICE's RFC 5245.
- *
- * @param relPort this candidate's related port as described by ICE's
- * RFC 5245.
- */
- public void setRelPort(int relPort)
- {
- super.setAttribute(REL_PORT_ATTR_NAME, relPort);
- }
-
- /**
- * Returns this candidate's related port as described by ICE's RFC 5245.
- *
- * @return this candidate's related port as described by ICE's RFC 5245.
- */
- public int getRelPort()
- {
- return super.getAttributeAsInt(REL_PORT_ATTR_NAME);
- }
-
- /**
- * Sets a Candidate Type as defined in ICE-CORE. The allowable values are
- * "host" for host candidates, "prflx" for peer reflexive candidates,
- * "relay" for relayed candidates, and "srflx" for server reflexive
- * candidates. All allowable values are enumerated in the {@link
- * CandidateType} enum.
- *
- * @param type this candidates' type as per ICE's RFC 5245.
- */
- public void setType(CandidateType type)
- {
- super.setAttribute(TYPE_ATTR_NAME, type);
- }
-
- /**
- * Returns a Candidate Type as defined in ICE-CORE. The allowable values are
- * "host" for host candidates, "prflx" for peer reflexive candidates,
- * "relay" for relayed candidates, and "srflx" for server reflexive
- * candidates. All allowable values are enumerated in the {@link
- * CandidateType} enum.
- *
- * @return this candidates' type as per ICE's RFC 5245.
- */
- public CandidateType getType()
- {
- return CandidateType.valueOf(getAttributeAsString(TYPE_ATTR_NAME));
- }
-
- /**
- * Compares this instance with another CandidatePacketExtension by
- * preference of type: host < local < prflx < srflx < stun < relay.
- *
- * @return 0 if the type are equal. -1 if this instance type is preferred.
- * Otherwise 1.
- */
- public int compareTo(CandidatePacketExtension candidatePacketExtension)
- {
- // If the types are different.
- if(this.getType() != candidatePacketExtension.getType())
- {
- CandidateType[] types = {
- CandidateType.host,
- CandidateType.local,
- CandidateType.prflx,
- CandidateType.srflx,
- CandidateType.stun,
- CandidateType.relay
- };
- for(int i = 0; i < types.length; ++i)
- {
- // this object is preferred.
- if(types[i] == this.getType())
- {
- return -1;
- }
- // the candidatePacketExtension is preferred.
- else if(types[i] == candidatePacketExtension.getType())
- {
- return 1;
- }
- }
- }
- // If the types are equal.
- return 0;
- }
-
- /**
- * Gets the TCP type for this <tt>CandidatePacketExtension</tt>.
- */
- public CandidateTcpType getTcpType()
- {
- String tcpTypeString = getAttributeAsString(TCPTYPE_ATTR_NAME);
- try
- {
- return CandidateTcpType.parse(tcpTypeString);
- }
- catch (IllegalArgumentException iae)
- {
- return null;
- }
- }
-
- /**
- * Sets the TCP type for this <tt>CandidatePacketExtension</tt>.
- * @param tcpType
- */
- public void setTcpType(CandidateTcpType tcpType)
- {
- setAttribute(TCPTYPE_ATTR_NAME, tcpType.toString());
- }
-}
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
+import org.ice4j.ice.*;
+
+/**
+ * @author Emil Ivov
+ */
+public class CandidatePacketExtension extends AbstractPacketExtension
+ implements Comparable<CandidatePacketExtension>
+{
+ /**
+ * The name of the "candidate" element.
+ */
+ public static final String ELEMENT_NAME = "candidate";
+
+ /**
+ * The name of the "component" element.
+ */
+ public static final String COMPONENT_ATTR_NAME = "component";
+
+ /**
+ * The "component" ID for RTP components.
+ */
+ public static final int RTP_COMPONENT_ID = 1;
+
+ /**
+ * The "component" ID for RTCP components.
+ */
+ public static final int RTCP_COMPONENT_ID = 2;
+
+ /**
+ * The name of the "foundation" element.
+ */
+ public static final String FOUNDATION_ATTR_NAME = "foundation";
+
+ /**
+ * The name of the "generation" element.
+ */
+ public static final String GENERATION_ATTR_NAME = "generation";
+
+ /**
+ * The name of the "id" element.
+ */
+ public static final String ID_ATTR_NAME = "id";
+
+ /**
+ * The name of the "ip" element.
+ */
+ public static final String IP_ATTR_NAME = "ip";
+
+ /**
+ * The name of the "network" element.
+ */
+ public static final String NETWORK_ATTR_NAME = "network";
+
+ /**
+ * The name of the "port" element.
+ */
+ public static final String PORT_ATTR_NAME = "port";
+
+ /**
+ * The name of the "priority" element.
+ */
+ public static final String PRIORITY_ATTR_NAME = "priority";
+
+ /**
+ * The name of the "protocol" element.
+ */
+ public static final String PROTOCOL_ATTR_NAME = "protocol";
+
+ /**
+ * The name of the "rel-addr" element.
+ */
+ public static final String REL_ADDR_ATTR_NAME = "rel-addr";
+
+ /**
+ * The name of the "rel-port" element.
+ */
+ public static final String REL_PORT_ATTR_NAME = "rel-port";
+
+ /**
+ * The name of the "type" element.
+ */
+ public static final String TYPE_ATTR_NAME = "type";
+
+ /**
+ * The name of the "tcptype" element.
+ */
+ public static final String TCPTYPE_ATTR_NAME = "tcptype";
+
+ /**
+ * Creates a new {@link CandidatePacketExtension}
+ */
+ public CandidatePacketExtension()
+ {
+ super(null, ELEMENT_NAME);
+ }
+
+ /**
+ * Creates a new {@link CandidatePacketExtension} with the specified
+ * <tt>elementName</tt> so that this class would be usable as a
+ * <tt>RemoteCandidatePacketExtension</tt> parent.
+ *
+ * @param elementName the element name that this instance should be using.
+ */
+ protected CandidatePacketExtension(String elementName)
+ {
+ super(null, elementName);
+ }
+
+ /**
+ * Sets a component ID as defined in ICE-CORE.
+ *
+ * @param component a component ID as defined in ICE-CORE.
+ */
+ public void setComponent(int component)
+ {
+ super.setAttribute(COMPONENT_ATTR_NAME, component);
+ }
+
+ /**
+ * Returns a component ID as defined in ICE-CORE.
+ *
+ * @return a component ID as defined in ICE-CORE.
+ */
+ public int getComponent()
+ {
+ return super.getAttributeAsInt(COMPONENT_ATTR_NAME);
+ }
+
+ /**
+ * Sets the candidate foundation as defined in ICE-CORE.
+ *
+ * @param foundation the candidate foundation as defined in ICE-CORE.
+ */
+ public void setFoundation(String foundation)
+ {
+ super.setAttribute(FOUNDATION_ATTR_NAME, foundation);
+ }
+
+ /**
+ * Returns the candidate foundation as defined in ICE-CORE.
+ *
+ * @return the candidate foundation as defined in ICE-CORE.
+ */
+ public String getFoundation()
+ {
+ return super.getAttributeAsString(FOUNDATION_ATTR_NAME);
+ }
+
+ /**
+ * Sets this candidate's generation index. A generation is an index,
+ * starting at 0, that enables the parties to keep track of updates to the
+ * candidate throughout the life of the session. For details, see the ICE
+ * Restarts section of XEP-0176.
+ *
+ * @param generation this candidate's generation index.
+ */
+ public void setGeneration(int generation)
+ {
+ super.setAttribute(GENERATION_ATTR_NAME, generation);
+ }
+
+ /**
+ * Returns this candidate's generation. A generation is an index, starting at
+ * 0, that enables the parties to keep track of updates to the candidate
+ * throughout the life of the session. For details, see the ICE Restarts
+ * section of XEP-0176.
+ *
+ * @return this candidate's generation index.
+ */
+ public int getGeneration()
+ {
+ return super.getAttributeAsInt(GENERATION_ATTR_NAME);
+ }
+
+ /**
+ * Sets this candidates's unique identifier <tt>String</tt>.
+ *
+ * @param id this candidates's unique identifier <tt>String</tt>
+ */
+ public void setID(String id)
+ {
+ super.setAttribute(ID_ATTR_NAME, id);
+ }
+
+ /**
+ * Returns this candidates's unique identifier <tt>String</tt>.
+ *
+ * @return this candidates's unique identifier <tt>String</tt>
+ */
+ public String getID()
+ {
+ return super.getAttributeAsString(ID_ATTR_NAME);
+ }
+
+ /**
+ * Sets this candidate's Internet Protocol (IP) address; this can be either
+ * an IPv4 address or an IPv6 address.
+ *
+ * @param ip this candidate's IPv4 or IPv6 address.
+ */
+ public void setIP(String ip)
+ {
+ super.setAttribute(IP_ATTR_NAME, ip);
+ }
+
+ /**
+ * Returns this candidate's Internet Protocol (IP) address; this can be
+ * either an IPv4 address or an IPv6 address.
+ *
+ * @return this candidate's IPv4 or IPv6 address.
+ */
+ public String getIP()
+ {
+ return super.getAttributeAsString(IP_ATTR_NAME);
+ }
+
+ /**
+ * The network index indicating the interface that the candidate belongs to.
+ * The network ID is used for diagnostic purposes only in cases where the
+ * calling hardware has more than one Network Interface Card.
+ *
+ * @param network the network index indicating the interface that the
+ * candidate belongs to.
+ */
+ public void setNetwork(int network)
+ {
+ super.setAttribute(NETWORK_ATTR_NAME, network);
+ }
+
+ /**
+ * Returns the network index indicating the interface that the candidate
+ * belongs to. The network ID is used for diagnostic purposes only in cases
+ * where the calling hardware has more than one Network Interface Card.
+ *
+ * @return the network index indicating the interface that the candidate
+ * belongs to.
+ */
+ public int getNetwork()
+ {
+ return super.getAttributeAsInt(NETWORK_ATTR_NAME);
+ }
+
+ /**
+ * Sets this candidate's port number.
+ *
+ * @param port this candidate's port number.
+ */
+ public void setPort(int port)
+ {
+ super.setAttribute(PORT_ATTR_NAME, port);
+ }
+
+ /**
+ * Returns this candidate's port number.
+ *
+ * @return this candidate's port number.
+ */
+ public int getPort()
+ {
+ return super.getAttributeAsInt(PORT_ATTR_NAME);
+ }
+
+ /**
+ * This candidate's priority as defined in ICE's RFC 5245
+ *
+ * @param priority this candidate's priority
+ */
+ public void setPriority(long priority)
+ {
+ super.setAttribute(PRIORITY_ATTR_NAME, priority);
+ }
+
+ /**
+ * This candidate's priority as defined in ICE's RFC 5245
+ *
+ * @return this candidate's priority
+ */
+ public int getPriority()
+ {
+ return super.getAttributeAsInt(PRIORITY_ATTR_NAME);
+ }
+
+ /**
+ * Sets this candidate's transport protocol.
+ *
+ * @param protocol this candidate's transport protocol.
+ */
+ public void setProtocol(String protocol)
+ {
+ super.setAttribute(PROTOCOL_ATTR_NAME, protocol);
+ }
+
+ /**
+ * Sets this candidate's transport protocol.
+ *
+ * @return this candidate's transport protocol.
+ */
+ public String getProtocol()
+ {
+ return super.getAttributeAsString(PROTOCOL_ATTR_NAME);
+ }
+
+ /**
+ * Sets this candidate's related address as described by ICE's RFC 5245.
+ *
+ * @param relAddr this candidate's related address as described by ICE's
+ * RFC 5245.
+ */
+ public void setRelAddr(String relAddr)
+ {
+ super.setAttribute(REL_ADDR_ATTR_NAME, relAddr);
+ }
+
+ /**
+ * Returns this candidate's related address as described by ICE's RFC 5245.
+ *
+ * @return this candidate's related address as described by ICE's RFC 5245.
+ */
+ public String getRelAddr()
+ {
+ return super.getAttributeAsString(REL_ADDR_ATTR_NAME);
+ }
+
+ /**
+ * Sets this candidate's related port as described by ICE's RFC 5245.
+ *
+ * @param relPort this candidate's related port as described by ICE's
+ * RFC 5245.
+ */
+ public void setRelPort(int relPort)
+ {
+ super.setAttribute(REL_PORT_ATTR_NAME, relPort);
+ }
+
+ /**
+ * Returns this candidate's related port as described by ICE's RFC 5245.
+ *
+ * @return this candidate's related port as described by ICE's RFC 5245.
+ */
+ public int getRelPort()
+ {
+ return super.getAttributeAsInt(REL_PORT_ATTR_NAME);
+ }
+
+ /**
+ * Sets a Candidate Type as defined in ICE-CORE. The allowable values are
+ * "host" for host candidates, "prflx" for peer reflexive candidates,
+ * "relay" for relayed candidates, and "srflx" for server reflexive
+ * candidates. All allowable values are enumerated in the {@link
+ * CandidateType} enum.
+ *
+ * @param type this candidates' type as per ICE's RFC 5245.
+ */
+ public void setType(CandidateType type)
+ {
+ super.setAttribute(TYPE_ATTR_NAME, type);
+ }
+
+ /**
+ * Returns a Candidate Type as defined in ICE-CORE. The allowable values are
+ * "host" for host candidates, "prflx" for peer reflexive candidates,
+ * "relay" for relayed candidates, and "srflx" for server reflexive
+ * candidates. All allowable values are enumerated in the {@link
+ * CandidateType} enum.
+ *
+ * @return this candidates' type as per ICE's RFC 5245.
+ */
+ public CandidateType getType()
+ {
+ return CandidateType.valueOf(getAttributeAsString(TYPE_ATTR_NAME));
+ }
+
+ /**
+ * Compares this instance with another CandidatePacketExtension by
+ * preference of type: host < local < prflx < srflx < stun < relay.
+ *
+ * @return 0 if the type are equal. -1 if this instance type is preferred.
+ * Otherwise 1.
+ */
+ public int compareTo(CandidatePacketExtension candidatePacketExtension)
+ {
+ // If the types are different.
+ if(this.getType() != candidatePacketExtension.getType())
+ {
+ CandidateType[] types = {
+ CandidateType.host,
+ CandidateType.local,
+ CandidateType.prflx,
+ CandidateType.srflx,
+ CandidateType.stun,
+ CandidateType.relay
+ };
+ for(int i = 0; i < types.length; ++i)
+ {
+ // this object is preferred.
+ if(types[i] == this.getType())
+ {
+ return -1;
+ }
+ // the candidatePacketExtension is preferred.
+ else if(types[i] == candidatePacketExtension.getType())
+ {
+ return 1;
+ }
+ }
+ }
+ // If the types are equal.
+ return 0;
+ }
+
+ /**
+ * Gets the TCP type for this <tt>CandidatePacketExtension</tt>.
+ */
+ public CandidateTcpType getTcpType()
+ {
+ String tcpTypeString = getAttributeAsString(TCPTYPE_ATTR_NAME);
+ try
+ {
+ return CandidateTcpType.parse(tcpTypeString);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the TCP type for this <tt>CandidatePacketExtension</tt>.
+ * @param tcpType
+ */
+ public void setTcpType(CandidateTcpType tcpType)
+ {
+ setAttribute(TCPTYPE_ATTR_NAME, tcpType.toString());
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java
index 69b2e47..3ccbd72 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java
@@ -17,6 +17,8 @@
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle;
+import java.util.Objects;
+
import ch.imvs.sdes4j.srtp.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
@@ -332,4 +334,14 @@ public class CryptoPacketExtension
}
return false;
}
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(
+ getCryptoSuite(),
+ getKeyParams(),
+ getSessionParams(),
+ getTag());
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java
index 1112c8c..173701f 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java
@@ -191,6 +191,27 @@ public class IceUdpTransportPacketExtension
}
/**
+ * Removes given <tt>PacketExtension</tt> from the list of child packet
+ * extensions. <tt>CandidatePacketExtension</tt> are not taken into account
+ * in this method and {@link #removeCandidate(CandidatePacketExtension)}
+ * should be used instead.
+ *
+ * @param childExtension <tt>PacketExtension</tt> instance to be removed
+ * from child packet extensions list.
+ *
+ * @return <tt>true</tt> if given <tt>childExtension</tt> has been in the
+ * list and was removed or <tt>false</tt> otherwise.
+ */
+ public boolean removeChildExtension(PacketExtension childExtension)
+ {
+ List<? extends PacketExtension> childExtensions
+ = super.getChildExtensions();
+
+ return childExtensions != null
+ && childExtensions.remove(childExtension);
+ }
+
+ /**
* Returns the list of {@link CandidatePacketExtension}s currently
* registered with this transport.
*
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQ.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQ.java
index 9183fa0..65b0849 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQ.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQ.java
@@ -21,6 +21,7 @@ import java.math.*;
import java.security.*;
import java.util.*;
+import net.java.sip.communicator.service.protocol.jabber.*;
import org.jivesoftware.smack.packet.*;
/**
@@ -62,7 +63,8 @@ public class JingleIQ extends IQ
* The name of the argument that contains the session id.
*/
public static final String SID_ATTR_NAME = "sid";
-
+
+
/**
* The <tt>JingleAction</tt> that describes the purpose of this
* <tt>jingle</tt> element.
@@ -104,8 +106,8 @@ public class JingleIQ extends IQ
* The list of "content" elements included in this IQ.
*/
private final List<ContentPacketExtension> contentList
- = new ArrayList<ContentPacketExtension>();
-
+ = new ArrayList<ContentPacketExtension>();
+
/**
* Returns the XML string of this Jingle IQ's "section" sub-element.
*
@@ -124,17 +126,18 @@ public class JingleIQ extends IQ
if( initiator != null)
bldr.append(" " + INITIATOR_ATTR_NAME
- + "='" + getInitiator() + "'");
+ + "='" + getInitiator() + "'");
if( responder != null)
bldr.append(" " + RESPONDER_ATTR_NAME
- + "='" + getResponder() + "'");
+ + "='" + getResponder() + "'");
bldr.append(" " + SID_ATTR_NAME
- + "='" + getSID() + "'");
-
- String extensionsXML = getExtensionsXML();
+ + "='" + getSID() + "'");
+ CharSequence extensionsXMLSeq = getExtensionsXML();
+ String extensionsXML = extensionsXMLSeq.toString();
+
if ((contentList.size() == 0)
&& (reason == null)
&& (sessionInfo == null)
@@ -348,7 +351,7 @@ public class JingleIQ extends IQ
* otherwise.
*/
public boolean containsContentChildOfType(
- Class<? extends PacketExtension> contentType)
+ Class<? extends PacketExtension> contentType)
{
if(getContentForType(contentType) != null)
return true;
@@ -369,14 +372,14 @@ public class JingleIQ extends IQ
* found.
*/
public ContentPacketExtension getContentForType(
- Class<? extends PacketExtension> contentType)
+ Class<? extends PacketExtension> contentType)
{
synchronized(contentList)
{
for(ContentPacketExtension content : contentList)
{
PacketExtension child
- = content.getFirstChildOfType(contentType);
+ = content.getFirstChildOfType(contentType);
if(child != null)
return content;
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
index 11f909a..49934e5 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
@@ -20,6 +20,7 @@ package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jitsimeet.*;
+import net.java.sip.communicator.service.protocol.jabber.*;
import org.jivesoftware.smack.provider.*;
import org.xmlpull.v1.*;
@@ -37,174 +38,187 @@ public class JingleIQProvider implements IQProvider
*/
public JingleIQProvider()
{
- ProviderManager providerManager = ProviderManager.getInstance();
+
+ AbstractSmackInteroperabilityLayer smackInteroperabilityLayer =
+ AbstractSmackInteroperabilityLayer.getInstance();
//<description/> provider
- providerManager.addExtensionProvider(
- RtpDescriptionPacketExtension.ELEMENT_NAME,
- RtpDescriptionPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <RtpDescriptionPacketExtension>(
- RtpDescriptionPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ RtpDescriptionPacketExtension.ELEMENT_NAME,
+ RtpDescriptionPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <RtpDescriptionPacketExtension>(
+ RtpDescriptionPacketExtension.class));
//<payload-type/> provider
- providerManager.addExtensionProvider(
- PayloadTypePacketExtension.ELEMENT_NAME,
- RtpDescriptionPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <PayloadTypePacketExtension>(
- PayloadTypePacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ PayloadTypePacketExtension.ELEMENT_NAME,
+ RtpDescriptionPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <PayloadTypePacketExtension>(
+ PayloadTypePacketExtension.class));
//<parameter/> provider
- providerManager.addExtensionProvider(
- ParameterPacketExtension.ELEMENT_NAME,
- RtpDescriptionPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <ParameterPacketExtension>(ParameterPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ ParameterPacketExtension.ELEMENT_NAME,
+ RtpDescriptionPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <ParameterPacketExtension>
+ (ParameterPacketExtension.class));
//<rtp-hdrext/> provider
- providerManager.addExtensionProvider(
- RTPHdrExtPacketExtension.ELEMENT_NAME,
- RTPHdrExtPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <RTPHdrExtPacketExtension>(RTPHdrExtPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ RTPHdrExtPacketExtension.ELEMENT_NAME,
+ RTPHdrExtPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <RTPHdrExtPacketExtension>
+ (RTPHdrExtPacketExtension.class));
// <sctpmap/> provider
- providerManager.addExtensionProvider(
- SctpMapExtension.ELEMENT_NAME,
- SctpMapExtension.NAMESPACE,
- new SctpMapExtensionProvider());
+ smackInteroperabilityLayer.addExtensionProvider(
+ SctpMapExtension.ELEMENT_NAME,
+ SctpMapExtension.NAMESPACE,
+ new SctpMapExtensionProvider());
//<encryption/> provider
- providerManager.addExtensionProvider(
- EncryptionPacketExtension.ELEMENT_NAME,
- RtpDescriptionPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <EncryptionPacketExtension>(EncryptionPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ EncryptionPacketExtension.ELEMENT_NAME,
+ RtpDescriptionPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <EncryptionPacketExtension>
+ (EncryptionPacketExtension.class));
//<zrtp-hash/> provider
- providerManager.addExtensionProvider(
- ZrtpHashPacketExtension.ELEMENT_NAME,
- ZrtpHashPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <ZrtpHashPacketExtension>(ZrtpHashPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ ZrtpHashPacketExtension.ELEMENT_NAME,
+ ZrtpHashPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <ZrtpHashPacketExtension>
+ (ZrtpHashPacketExtension.class));
//<crypto/> provider
- providerManager.addExtensionProvider(
- CryptoPacketExtension.ELEMENT_NAME,
- RtpDescriptionPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <CryptoPacketExtension>(CryptoPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ CryptoPacketExtension.ELEMENT_NAME,
+ RtpDescriptionPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <CryptoPacketExtension>
+ (CryptoPacketExtension.class));
// <bundle/> provider
- providerManager.addExtensionProvider(
- BundlePacketExtension.ELEMENT_NAME,
- BundlePacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <BundlePacketExtension>(BundlePacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ BundlePacketExtension.ELEMENT_NAME,
+ BundlePacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <BundlePacketExtension>
+ (BundlePacketExtension.class));
// <group/> provider
- providerManager.addExtensionProvider(
- GroupPacketExtension.ELEMENT_NAME,
- GroupPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider
- <GroupPacketExtension>(GroupPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ GroupPacketExtension.ELEMENT_NAME,
+ GroupPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <GroupPacketExtension>(GroupPacketExtension.class));
//ice-udp transport
- providerManager.addExtensionProvider(
- IceUdpTransportPacketExtension.ELEMENT_NAME,
- IceUdpTransportPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider<IceUdpTransportPacketExtension>(
- IceUdpTransportPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ IceUdpTransportPacketExtension.ELEMENT_NAME,
+ IceUdpTransportPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <IceUdpTransportPacketExtension>(
+ IceUdpTransportPacketExtension.class));
//<raw-udp/> provider
- providerManager.addExtensionProvider(
- RawUdpTransportPacketExtension.ELEMENT_NAME,
- RawUdpTransportPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider<RawUdpTransportPacketExtension>(
- RawUdpTransportPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ RawUdpTransportPacketExtension.ELEMENT_NAME,
+ RawUdpTransportPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <RawUdpTransportPacketExtension>(
+ RawUdpTransportPacketExtension.class));
//ice-udp <candidate/> provider
- providerManager.addExtensionProvider(
- CandidatePacketExtension.ELEMENT_NAME,
- IceUdpTransportPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider<CandidatePacketExtension>(
- CandidatePacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ CandidatePacketExtension.ELEMENT_NAME,
+ IceUdpTransportPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <CandidatePacketExtension>(
+ CandidatePacketExtension.class));
//raw-udp <candidate/> provider
- providerManager.addExtensionProvider(
- CandidatePacketExtension.ELEMENT_NAME,
- RawUdpTransportPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider<CandidatePacketExtension>(
- CandidatePacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ CandidatePacketExtension.ELEMENT_NAME,
+ RawUdpTransportPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <CandidatePacketExtension>(
+ CandidatePacketExtension.class));
//ice-udp <remote-candidate/> provider
- providerManager.addExtensionProvider(
- RemoteCandidatePacketExtension.ELEMENT_NAME,
- IceUdpTransportPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider<RemoteCandidatePacketExtension>(
- RemoteCandidatePacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ RemoteCandidatePacketExtension.ELEMENT_NAME,
+ IceUdpTransportPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <RemoteCandidatePacketExtension>(
+ RemoteCandidatePacketExtension.class));
//inputevt <inputevt/> provider
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
InputEvtPacketExtension.ELEMENT_NAME,
InputEvtPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<InputEvtPacketExtension>(
InputEvtPacketExtension.class));
//coin <conference-info/> provider
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
CoinPacketExtension.ELEMENT_NAME,
CoinPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<CoinPacketExtension>(
CoinPacketExtension.class));
// DTLS-SRTP
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
DtlsFingerprintPacketExtension.ELEMENT_NAME,
DtlsFingerprintPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider
- <DtlsFingerprintPacketExtension>(
+ <DtlsFingerprintPacketExtension>(
DtlsFingerprintPacketExtension.class));
/*
* XEP-0251: Jingle Session Transfer <transfer/> and <transferred>
* providers
*/
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
TransferPacketExtension.ELEMENT_NAME,
TransferPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<TransferPacketExtension>(
TransferPacketExtension.class));
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
TransferredPacketExtension.ELEMENT_NAME,
TransferredPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<TransferredPacketExtension>(
TransferredPacketExtension.class));
//conference description <callid/> provider
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
ConferenceDescriptionPacketExtension.CALLID_ELEM_NAME,
ConferenceDescriptionPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<CallIdPacketExtension>(
CallIdPacketExtension.class));
//rtcp-fb
- providerManager.addExtensionProvider(
- RtcpFbPacketExtension.ELEMENT_NAME,
- RtcpFbPacketExtension.NAMESPACE,
- new DefaultPacketExtensionProvider<RtcpFbPacketExtension>(
- RtcpFbPacketExtension.class));
+ smackInteroperabilityLayer.addExtensionProvider(
+ RtcpFbPacketExtension.ELEMENT_NAME,
+ RtcpFbPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider<RtcpFbPacketExtension>(
+ RtcpFbPacketExtension.class));
//rtcp-mux
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
RtcpmuxPacketExtension.ELEMENT_NAME,
IceUdpTransportPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<RtcpmuxPacketExtension>(
RtcpmuxPacketExtension.class));
//ssrcInfo
- providerManager.addExtensionProvider(
+ smackInteroperabilityLayer.addExtensionProvider(
SSRCInfoPacketExtension.ELEMENT_NAME,
SSRCInfoPacketExtension.NAMESPACE,
new DefaultPacketExtensionProvider<SSRCInfoPacketExtension>(
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/ComponentVersionsExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/ComponentVersionsExtension.java
new file mode 100644
index 0000000..bcc3397
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/ComponentVersionsExtension.java
@@ -0,0 +1,135 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jitsimeet;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
+
+/**
+ * The packet extension is used by Jicofo to broadcast versions of all video
+ * conferencing system components. This packets extension is added to jicofo's
+ * MUC presence. It will contain {@link Component} children which carry each
+ * component's name and version.
+ *
+ * @author Pawel Domas
+ */
+public class ComponentVersionsExtension
+ extends AbstractPacketExtension
+{
+ /**
+ * The XML element name of {@link ComponentVersionsExtension}.
+ */
+ public static final String ELEMENT_NAME = "versions";
+
+ /**
+ * The name of XML sub-elements which carry the info about particular
+ * component's version.
+ */
+ public static final String COMPONENT_ELEMENT_NAME = "component";
+
+ /**
+ * Constant for {@link Component} name used to signal the version of
+ * conference focus.
+ */
+ public static final String COMPONENT_FOCUS = "focus";
+
+ /**
+ * Constant for {@link Component} name used to signal the version of
+ * XMPP server.
+ */
+ public static final String COMPONENT_XMPP_SERVER = "xmpp";
+
+ /**
+ * Constant for {@link Component} name used to signal the version of
+ * the videobridge.
+ */
+ public static final String COMPONENT_VIDEOBRIDGE = "videobridge";
+
+ /**
+ * The XML element namespace of {@link ComponentVersionsExtension}.
+ */
+ public static final String NAMESPACE = "http://jitsi.org/jitmeet";
+
+ /**
+ * Creates an {@link AbstractPacketExtension} instance for the specified
+ * <tt>namespace</tt> and <tt>elementName</tt>.
+ */
+ public ComponentVersionsExtension()
+ {
+ super(NAMESPACE, ELEMENT_NAME);
+ }
+
+ /**
+ * Adds component's version to this extension.
+ *
+ * @param componentName the name of the component for which
+ * child {@link Component} extension will be added.
+ * @param versionStr human readable string that describes component's
+ * version.
+ */
+ public void addComponentVersion(String componentName, String versionStr)
+ {
+ Component v = new Component();
+
+ v.setName(componentName);
+ v.setText(versionStr);
+
+ addChildExtension(v);
+ }
+
+ /**
+ * Component child element of {@link ComponentVersionsExtension}. The name
+ * of the component is carried in name attribute and the version string is
+ * the text value.
+ */
+ public class Component
+ extends AbstractPacketExtension
+ {
+ /**
+ * The name of that attribute that carries component's name.
+ */
+ private final String NAME_ATTR_NAME = "name";
+
+ /**
+ * Creates new instance of {@link Component} packet extension.
+ */
+ public Component()
+ {
+ super(NAMESPACE, COMPONENT_ELEMENT_NAME);
+ }
+
+ /**
+ * Returns the value of the name attribute.
+ * @return <tt>String</tt> which describes the name of video
+ * conferencing system component.
+ */
+ public String getName()
+ {
+ return getAttributeAsString(NAME_ATTR_NAME);
+ }
+
+ /**
+ * Sets new value for the component's name attribute.
+ * @param name a <tt>String</tt> which describes the name of video
+ * conferencing system component.
+ */
+ public void setName(String name)
+ {
+ setAttribute(NAME_ATTR_NAME, name);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/SSRCInfoPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/SSRCInfoPacketExtension.java
index 239c708..7384c9e 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/SSRCInfoPacketExtension.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/SSRCInfoPacketExtension.java
@@ -1,8 +1,19 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.jitsimeet;
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/VideoMutedExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/VideoMutedExtension.java
new file mode 100644
index 0000000..cf76d89
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jitsimeet/VideoMutedExtension.java
@@ -0,0 +1,70 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jitsimeet;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
+
+/**
+ * Video muted extension that is included in users presence in Jitsi-meet
+ * conferences. It does carry the info about user's video muted status.
+ *
+ * @author Pawel Domas
+ */
+public class VideoMutedExtension
+ extends AbstractPacketExtension
+{
+ /**
+ * The namespace of this packet extension.
+ */
+ public static final String NAMESPACE = "http://jitsi.org/jitmeet/video";
+
+ /**
+ * XML element name of this packet extension.
+ */
+ public static final String ELEMENT_NAME = "videomuted";
+
+ /**
+ * Creates new instance of <tt>VideoMutedExtension</tt>.
+ */
+ public VideoMutedExtension()
+ {
+ super(NAMESPACE, ELEMENT_NAME);
+ }
+
+ /**
+ * Check whether or not user's video is in muted status.
+ * @return <tt>true</tt> if muted, <tt>false</tt> if unmuted or
+ * <tt>null</tt> if no valid info found in the extension body.
+ */
+ public Boolean isVideoMuted()
+ {
+ return Boolean.valueOf(getText());
+ }
+
+ /**
+ * Sets user's video muted status.
+ *
+ * @param videoMuted <tt>true</tt> or <tt>false</tt> which indicates video
+ * muted status of the user.
+ */
+ public void setVideoMuted(Boolean videoMuted)
+ {
+ setText(
+ String.valueOf(videoMuted));
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java b/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java
index 93cdead..8094f68 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/jinglesdp/JingleUtils.java
@@ -179,12 +179,17 @@ public class JingleUtils
else
paramsMap.put(paramName, param.getValue());
}
-
- // video-related attributes in payload-type element
+
for(String attr : payloadType.getAttributeNames())
{
+ //video-related attributes in payload-type element
if(attr.equals("width") || attr.equals("height"))
paramsMap.put(attr, payloadType.getAttributeAsString(attr));
+
+ //update ptime with the actual value from the payload
+ if (attr.equals(PayloadTypePacketExtension.PTIME_ATTR_NAME))
+ advancedMap.put(PayloadTypePacketExtension.PTIME_ATTR_NAME,
+ Integer.toString(payloadType.getPtime()));
}
//now create the format.
diff --git a/src/net/java/sip/communicator/impl/protocol/mock/MockContactGroup.java b/src/net/java/sip/communicator/impl/protocol/mock/MockContactGroup.java
index fa4fff1..e6cdd36 100644
--- a/src/net/java/sip/communicator/impl/protocol/mock/MockContactGroup.java
+++ b/src/net/java/sip/communicator/impl/protocol/mock/MockContactGroup.java
@@ -506,6 +506,31 @@ public class MockContactGroup
return true;
}
+ @Override
+ public int hashCode()
+ {
+ List<Object> objects = new ArrayList<Object>();
+ objects.add(getGroupName());
+ objects.add(getUID());
+ objects.add(countContacts());
+ objects.add(countSubgroups());
+
+ //traverse child contacts
+ for (Contact c : contacts)
+ {
+ objects.add(c.getAddress());
+ }
+
+
+ //traverse subgroups
+ for (ContactGroup g : subGroups)
+ {
+ objects.add(g.getGroupName());
+ }
+
+ return Objects.hash(objects.toArray());
+ }
+
public void setPersistent(boolean isPersistent)
{
this.isPersistent = isPersistent;
diff --git a/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java b/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java
index bcff799..a7b6e5e 100644
--- a/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java
+++ b/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java
@@ -294,6 +294,15 @@ public class MockProvider
}
/**
+ * Always true.
+ */
+ @Override
+ public boolean validateContactAddress(String contactId, List<String> result)
+ {
+ return true;
+ }
+
+ /**
* Mock implementation of the corresponding ProtocolProviderService method.
* We have no icon corresponding to this protocol provider.
*/
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/AddressResolverImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/AddressResolverImpl.java
index eba0da6..4fd1b6f 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/AddressResolverImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/AddressResolverImpl.java
@@ -70,18 +70,8 @@ public class AddressResolverImpl
// if it is a textual IP address, do no try to resolve it
if(NetworkUtils.isValidIPAddress(hostAddress))
{
- byte[] addr = null;
-
- addr = NetworkUtils.strToIPv4(hostAddress);
-
- // not an IPv4, try IPv6
- if (addr == null)
- {
- addr = NetworkUtils.strToIPv6(hostAddress);
- }
-
InetSocketAddress hostSocketAddress = new InetSocketAddress(
- InetAddress.getByAddress(hostAddress, addr),
+ NetworkUtils.getInetAddress(hostAddress),
inputAddress.getPort());
return new HopImpl(hostSocketAddress.getHostName(),
inputAddress.getPort(),
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
index c4193a5..b626dbb 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
@@ -87,7 +87,7 @@ public class CallPeerMediaHandlerSipImpl
* Whether other party is able to change video quality settings.
* Normally its whether we have detected existence of imageattr in sdp.
*/
- boolean supportQualityControls;
+ private boolean supportQualityControls;
/**
* The current quality controls for this peer media handler if any.
@@ -98,7 +98,7 @@ public class CallPeerMediaHandlerSipImpl
* The lock we use to make sure that we won't be processing a second
* offer/answer exchange while a .
*/
- private Object offerAnswerLock = new Object();
+ private final Object offerAnswerLock = new Object();
/**
* Creates a new handler that will be managing media streams for
@@ -164,7 +164,7 @@ public class CallPeerMediaHandlerSipImpl
throws OperationFailedException
{
//Audio Media Description
- Vector<MediaDescription> mediaDescs = createMediaDescriptions();
+ List<MediaDescription> mediaDescs = createMediaDescriptions();
//wrap everything up in a session description
String userName
@@ -197,7 +197,7 @@ public class CallPeerMediaHandlerSipImpl
* for reasons like - problems with device interaction, allocating ports,
* etc.
*/
- private Vector<MediaDescription> createMediaDescriptions()
+ private List<MediaDescription> createMediaDescriptions()
throws OperationFailedException
{
//Audio Media Description
@@ -215,12 +215,16 @@ public class CallPeerMediaHandlerSipImpl
receiveQualityPreset = qualityControls.getRemoteSendMaxPreset();
}
- for (MediaType mediaType : MediaType.values())
+ for (MediaType mediaType : new MediaType[] { MediaType.AUDIO , MediaType.VIDEO})
{
MediaDevice dev = getDefaultDevice(mediaType);
if (!isDeviceActive(dev, sendQualityPreset, receiveQualityPreset))
+ {
+ logger.warn("No active device for " + mediaType.toString()
+ + " was found!");
continue;
+ }
MediaDirection direction
= dev.getDirection().and(getDirectionUserPreference(mediaType));
@@ -339,7 +343,7 @@ public class CallPeerMediaHandlerSipImpl
* it is known that the other endpoint supports this
* profile" and "[o]ther profiles MAY also be used."
*/
- updateMediaDescriptionForZrtp(mediaType, md, null);
+ updateMediaDescriptionForZrtp(mediaType, md);
if (SrtpControl.RTP_SAVP.equals(proto)
|| SrtpControl.RTP_SAVPF.equals(proto))
{
@@ -400,7 +404,7 @@ public class CallPeerMediaHandlerSipImpl
{
//create the media descriptions reflecting our current state.
- Vector<MediaDescription> newMediaDescs = createMediaDescriptions();
+ List<MediaDescription> newMediaDescs = createMediaDescriptions();
SessionDescription newOffer = SdpUtils.createSessionUpdateDescription(
sdescToUpdate, getTransportManager().getLastUsedLocalHost(),
@@ -510,7 +514,7 @@ public class CallPeerMediaHandlerSipImpl
throws OperationFailedException,
IllegalArgumentException
{
- Vector<MediaDescription> answerDescriptions
+ List<MediaDescription> answerDescriptions
= createMediaDescriptionsForAnswer(newOffer);
// wrap everything up in a session description
SessionDescription newAnswer
@@ -555,10 +559,11 @@ public class CallPeerMediaHandlerSipImpl
boolean rejectedAvpOfferDueToSavpMandatory = false;
AccountID accountID = getPeer().getProtocolProvider().getAccountID();
- int savpOption
- = accountID.getAccountPropertyBoolean(
- ProtocolProviderFactory.DEFAULT_ENCRYPTION,
- true)
+ boolean useDefaultEncryption =
+ accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_ENCRYPTION , true);
+
+ int savpOption = useDefaultEncryption
? accountID.getAccountPropertyInt(
ProtocolProviderFactory.SAVP_OPTION,
ProtocolProviderFactory.SAVP_OFF)
@@ -638,7 +643,7 @@ public class CallPeerMediaHandlerSipImpl
{
mutuallySupportedFormats = null;
}
- else if(mediaType.equals(MediaType.VIDEO)
+ else if(MediaType.VIDEO.equals(mediaType)
&& (qualityControls != null))
{
/*
@@ -705,18 +710,18 @@ public class CallPeerMediaHandlerSipImpl
= getTransportManager().getStreamConnector(mediaType);
// check for options from remote party and set them locally
- if(mediaType.equals(MediaType.VIDEO))
+ if(MediaType.VIDEO.equals(mediaType))
{
// update stream
MediaStream stream = getStream(MediaType.VIDEO);
- if(stream != null && dev != null)
+ if(stream != null)
{
List<MediaFormat> fmts = intersectFormats(
getLocallySupportedFormats(dev),
remoteFormats);
- if(fmts.size() > 0)
+ if(!fmts.isEmpty())
{
MediaFormat fmt = fmts.get(0);
@@ -809,7 +814,7 @@ public class CallPeerMediaHandlerSipImpl
{
if(remoteDescriptions.size() > 1)
{
- if(mediaType.equals(MediaType.AUDIO))
+ if(MediaType.AUDIO.equals(mediaType))
{
masterStream = true;
masterStreamSet = true;
@@ -1192,8 +1197,7 @@ public class CallPeerMediaHandlerSipImpl
*/
private boolean updateMediaDescriptionForZrtp(
MediaType mediaType,
- MediaDescription localMd,
- MediaDescription remoteMd)
+ MediaDescription localMd)
{
MediaAwareCallPeer<?, ?, ?> peer = getPeer();
AccountID accountID = peer.getProtocolProvider().getAccountID();
@@ -1499,7 +1503,7 @@ public class CallPeerMediaHandlerSipImpl
// check for options from remote party and set
// is quality controls supported
- if(mediaType.equals(MediaType.VIDEO))
+ if(MediaType.VIDEO.equals(mediaType))
{
supportQualityControls
= SdpUtils.containsAttribute(mediaDescription, "imageattr");
@@ -1544,7 +1548,7 @@ public class CallPeerMediaHandlerSipImpl
{
if(remoteDescriptions.size() > 1)
{
- if(mediaType.equals(MediaType.AUDIO))
+ if(MediaType.AUDIO.equals(mediaType))
{
masterStream = true;
masterStreamSet = true;
@@ -1882,7 +1886,7 @@ public class CallPeerMediaHandlerSipImpl
// ZRTP
else if(srtpControlType == SrtpControlType.ZRTP)
{
- if(updateMediaDescriptionForZrtp(mediaType, localMd, remoteMd))
+ if(updateMediaDescriptionForZrtp(mediaType, localMd))
{
// Stop once an encryption advertisement has been chosen.
return;
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java
index fa0e08e..62711c7 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/CallSipImpl.java
@@ -61,15 +61,27 @@ public class CallSipImpl
* Name of extra INVITE header which specifies name of MUC room that is
* hosting the Jitsi Meet conference.
*/
- public static final String JITSI_MEET_ROOM_HEADER
- = "Jitsi-Conference-Room";
+ public String JITSI_MEET_ROOM_HEADER = "Jitsi-Conference-Room";
+
+ /**
+ * Property name of extra INVITE header which specifies name of MUC room
+ * that is hosting the Jitsi Meet conference.
+ */
+ private static final String JITSI_MEET_ROOM_HEADER_PROPERTY
+ = "JITSI_MEET_ROOM_HEADER_NAME";
+
+ /**
+ * Property name of extra INVITE header which specifies password required
+ * to enter MUC room that is hosting the Jitsi Meet conference.
+ */
+ public String JITSI_MEET_ROOM_PASS_HEADER = "Jitsi-Conference-Room-Pass";
/**
* Name of extra INVITE header which specifies password required to enter
* MUC room that is hosting the Jitsi Meet conference.
*/
- public static final String JITSI_MEET_ROOM_PASS_HEADER
- = "Jitsi-Conference-Room-Pass";
+ private static final String JITSI_MEET_ROOM_PASS_HEADER_PROPERTY
+ = "JITSI_MEET_ROOM_PASS_HEADER_NAME";
/**
* Custom header included in initial desktop sharing call creation.
@@ -78,16 +90,27 @@ public class CallSipImpl
public static final String DS_SHARING_HEADER = "X-Desktop-Share";
/**
- * When starting call we may have quality preferences we must use
- * for the call.
+ * Custom header name prefix that can be added to the call instance.
+ * Several headers can be specified in the form of:
+ * EXTRA_HEADER_NAME.1=...
+ * EXTRA_HEADER_NAME.2=...
+ * Index starting from 1.
*/
- private QualityPreset initialQualityPreferences;
+ public static final String EXTRA_HEADER_NAME = "EXTRA_HEADER_NAME";
/**
- * A reference to the <tt>SipMessageFactory</tt> instance that we should
- * use when creating requests.
+ * Custom header value prefix that can be added to the call instance.
+ * Several headers can be specified in the form of:
+ * EXTRA_HEADER_VALUE.1=...
+ * EXTRA_HEADER_VALUE.2=...
+ * Index starting from 1.
*/
- private final SipMessageFactory messageFactory;
+ public static final String EXTRA_HEADER_VALUE = "EXTRA_HEADER_VALUE";
+
+ /**
+ * Maximum number of retransmissions that will be sent.
+ */
+ private static final int MAX_RETRANSMISSIONS = 3;
/**
* The name of the property under which the user may specify the number of
@@ -95,19 +118,27 @@ public class CallSipImpl
* 180.
*/
private static final String RETRANSMITS_RINGING_INTERVAL
- = "net.java.sip.communicator.impl.protocol.sip"
- + ".RETRANSMITS_RINGING_INTERVAL";
+ = "net.java.sip.communicator.impl.protocol.sip"
+ + ".RETRANSMITS_RINGING_INTERVAL";
/**
- * The default amount of time (in milliseconds) for the initial interval for
- * retransmissions of response 180.
- */
+ * The default amount of time (in milliseconds) for the initial interval for
+ * retransmissions of response 180.
+ */
private static final int DEFAULT_RETRANSMITS_RINGING_INTERVAL = 500;
/**
- * Maximum number of retransmissions that will be sent.
+ * When starting call we may have quality preferences we must use
+ * for the call.
*/
- private static final int MAX_RETRANSMISSIONS = 3;
+ private QualityPreset initialQualityPreferences;
+
+ /**
+ * A reference to the <tt>SipMessageFactory</tt> instance that we should
+ * use when creating requests.
+ */
+ private final SipMessageFactory messageFactory;
+
/**
* The amount of time (in milliseconds) for the initial interval for
@@ -140,6 +171,13 @@ public class CallSipImpl
}
this.retransmitsRingingInterval = retransmitsRingingInterval;
+ AccountID account = parentOpSet.getProtocolProvider().getAccountID();
+ // Specify custom header names
+ JITSI_MEET_ROOM_HEADER = account.getAccountPropertyString(
+ JITSI_MEET_ROOM_HEADER_PROPERTY, JITSI_MEET_ROOM_HEADER);
+ JITSI_MEET_ROOM_PASS_HEADER = account.getAccountPropertyString(
+ JITSI_MEET_ROOM_PASS_HEADER_PROPERTY, JITSI_MEET_ROOM_PASS_HEADER);
+
//let's add ourselves to the calls repo. we are doing it ourselves just
//to make sure that no one ever forgets.
parentOpSet.getActiveCallsRepository().addCall(this);
@@ -387,24 +425,21 @@ public class CallSipImpl
logger.trace("Looking for peer with dialog: " + dialog
+ "among " + getCallPeerCount() + " calls");
}
- while (callPeers.hasNext())
+ for (CallPeerSipImpl callPeer : getCallPeerList())
{
- CallPeerSipImpl cp = callPeers.next();
-
- if (cp.getDialog() == dialog)
+ if (callPeer.getDialog() == dialog)
{
if (logger.isTraceEnabled())
- logger.trace("Returning cp=" + cp);
- return cp;
+ logger.trace("Returning cp=" + callPeer);
+ return callPeer;
}
else
{
if (logger.isTraceEnabled())
- logger.trace("Ignoring cp=" + cp + " because cp.dialog="
- + cp.getDialog() + " while dialog=" + dialog);
+ logger.trace("Ignoring cp=" + callPeer + " because cp.dialog="
+ + callPeer.getDialog() + " while dialog=" + dialog);
}
}
-
return null;
}
@@ -449,7 +484,7 @@ public class CallSipImpl
// Transport preference
String forceTransport = null;
javax.sip.address.URI calleeURI = calleeAddress.getURI();
- if(calleeURI.getScheme().toLowerCase().equals("sips"))
+ if("sips".equals(calleeURI.getScheme().toLowerCase()))
{
// MUST use TLS
forceTransport = "TLS";
@@ -553,7 +588,7 @@ public class CallSipImpl
String alternativeIMPPAddress = null;
if (infoHeader != null
&& infoHeader.getParameter("purpose") != null
- && infoHeader.getParameter("purpose").equals("impp"))
+ && "impp".equals(infoHeader.getParameter("purpose")))
{
alternativeIMPPAddress = infoHeader.getInfo().toString();
}
@@ -585,7 +620,7 @@ public class CallSipImpl
{
if (logger.isTraceEnabled())
logger.trace("will send ringing response: ");
- if(peer.getState().equals(CallPeerState.INCOMING_CALL))
+ if( CallPeerState.INCOMING_CALL.equals(peer.getState()) )
{
response = messageFactory.createResponse(Response.RINGING, invite);
@@ -680,10 +715,10 @@ public class CallSipImpl
*/
public void reInvite() throws OperationFailedException
{
- Iterator<CallPeerSipImpl> peers = getCallPeers();
-
- while (peers.hasNext())
- peers.next().sendReInvite();
+ for(CallPeerSipImpl peer : getCallPeerList())
+ {
+ peer.sendReInvite();
+ }
}
/**
@@ -706,6 +741,22 @@ public class CallSipImpl
protected void processExtraHeaders(javax.sip.message.Message message)
throws ParseException
{
+ // If there are custom headers added to the call instance, add those
+ // headers
+ int extraHeaderIx = 1;
+
+ Object name = getData(EXTRA_HEADER_NAME + "." + extraHeaderIx);
+ while(name != null)
+ {
+ Object value = getData(EXTRA_HEADER_VALUE + "." + extraHeaderIx);
+
+ Header header = getProtocolProvider().getHeaderFactory()
+ .createHeader((String) name, (String) value);
+ message.setHeader(header);
+
+ extraHeaderIx++;
+ name = getData(EXTRA_HEADER_NAME + "." + extraHeaderIx);
+ }
}
/**
@@ -758,8 +809,8 @@ public class CallSipImpl
{
try
{
- if(!peer.getState().equals(
- CallPeerState.INCOMING_CALL))
+ if( !CallPeerState.INCOMING_CALL.equals(
+ peer.getState()) )
{
timer.cancel();
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java
index f5782f1..3c2aeb5 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java
@@ -641,5 +641,31 @@ public class ContactGroupSipImpl
return true;
}
+
+ @Override
+ public int hashCode()
+ {
+ List<Object> objects = new ArrayList<Object>();
+ objects.add(getGroupName());
+ objects.add(getUID());
+ objects.add(countContacts());
+ objects.add(countSubgroups());
+ objects.add(getProtocolProvider());
+
+ //traverse child contacts
+ for (Contact c : contacts)
+ {
+ objects.add(c.getAddress());
+ }
+
+
+ //traverse subgroups
+ for (ContactGroup g : subGroups)
+ {
+ objects.add(g.getGroupName());
+ }
+
+ return Objects.hash(objects.toArray());
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java
index 0d0b5e8..d4662dd 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java
@@ -172,7 +172,7 @@ public class ContactSipImpl
public String getAddress()
{
SipURI sipURI = (SipURI) sipAddress.getURI();
- return sipURI.getUser() + "@" + sipURI.getHost();
+ return sipURI.toString().substring(sipURI.getScheme().length() + 1);
}
/**
@@ -535,9 +535,7 @@ public class ContactSipImpl
if(obj instanceof String)
{
String sobj = (String)obj;
-
- if(sobj.startsWith("sip:"))
- sobj = sobj.substring(4);
+ sobj = stripScheme(stripAddress(sobj));
if(getAddress().equalsIgnoreCase(sobj))
return true;
@@ -556,6 +554,43 @@ public class ContactSipImpl
}
/**
+ * Get rid of any parameters, ports etc. within a sip contact
+ * @param address the address to strip
+ * @return [sip[s]:]user@host without any params or port numbers.
+ */
+ static String stripAddress(String address)
+ {
+ if (address != null && address.length() > 0)
+ {
+ int idx = address.indexOf(':', 5);
+ if (idx > -1)
+ address = address.substring(0, idx);
+ idx = address.indexOf(';');
+ if (idx > -1)
+ address = address.substring(0, idx);
+ }
+ return address;
+ }
+
+ /**
+ * @param from address to strip
+ * @return the address, stripped from either "sip:" or "sips:"
+ */
+ public static String stripScheme(String from)
+ {
+ if (from.startsWith("sip:"))
+ {
+ return from.substring(4);
+ }
+ else if (from.startsWith("sips:"))
+ {
+ return from.substring(5);
+ }
+
+ return from;
+ }
+
+ /**
* Returns the presence operation set that this contact belongs
* to.
*
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
index 5ee32c9..fc99643 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
@@ -434,7 +434,10 @@ public class OperationSetBasicTelephonySipImpl
CSeqHeader cseq = ((CSeqHeader) response.getHeader(CSeqHeader.NAME));
if (cseq == null)
+ {
logger.error("An incoming response did not contain a CSeq header");
+ return false;
+ }
String method = cseq.getMethod();
@@ -1163,11 +1166,7 @@ public class OperationSetBasicTelephonySipImpl
protocolProvider.getAccountID().getService()
, 399, reasonText);
}
- catch(InvalidArgumentException e)
- {
- logger.error("Cannot create warning header", e);
- }
- catch(ParseException e)
+ catch(InvalidArgumentException | ParseException e)
{
logger.error("Cannot create warning header", e);
}
@@ -1458,11 +1457,7 @@ public class OperationSetBasicTelephonySipImpl
{
serverTransaction.sendResponse(accepted);
}
- catch (InvalidArgumentException ex)
- {
- failure = ex;
- }
- catch (SipException ex)
+ catch (InvalidArgumentException | SipException ex)
{
failure = ex;
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetJitsiMeetToolsSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetJitsiMeetToolsSipImpl.java
index 77a7fae..4997fc1 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetJitsiMeetToolsSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetJitsiMeetToolsSipImpl.java
@@ -142,6 +142,16 @@ public class OperationSetJitsiMeetToolsSipImpl
* {@inheritDoc}
*/
@Override
+ public void removePresenceExtension(ChatRoom chatRoom,
+ PacketExtension extension)
+ {
+ throw new RuntimeException("Not implemented for SIP");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public void setPresenceStatus(ChatRoom chatRoom, String statusMessage)
{
throw new RuntimeException("Not implemented for SIP");
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetMessageWaitingSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetMessageWaitingSipImpl.java
index 28fce28..7972ee8 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetMessageWaitingSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetMessageWaitingSipImpl.java
@@ -209,6 +209,10 @@ public class OperationSetMessageWaitingSipImpl
try
{
subscribeAddress = getSubscribeAddress();
+ if (subscribeAddress == null)
+ {
+ return;
+ }
}
catch (ParseException e)
{
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java
index 2fce57e..ef0ec4c 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java
@@ -2240,6 +2240,40 @@ public class OperationSetPresenceSipImpl
updateContactIcon((ContactSipImpl) contact, personStatusIcon);
}
+ // search for a <note> that can define a more precise
+ // status this is not recommended by RFC3863 but some im
+ // clients use this.
+ NodeList presNoteList = getPidfChilds(presence, NOTE_ELEMENT);
+ if (presNoteList.getLength() >= 1)
+ {
+ Node noteNode = presNoteList.item(presNoteList.getLength() - 1);
+ if (noteNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String state = getTextContent((Element)noteNode);
+ if (state != null)
+ {
+ switch (state.toLowerCase())
+ {
+ case "ready":
+ case "available":
+ personStatus = sipStatusEnum
+ .getStatus(SipStatusEnum.ONLINE);
+ break;
+ case "ringing":
+ case "on the phone":
+ case "on hold":
+ personStatus = sipStatusEnum
+ .getStatus(SipStatusEnum.ON_THE_PHONE);
+ break;
+ case "unavailable":
+ personStatus = sipStatusEnum
+ .getStatus(SipStatusEnum.OFFLINE);
+ break;
+ }
+ }
+ }
+ }
+
// Vector containing the list of status to set for each contact in
// the presence document ordered by priority (highest first).
// <SipContact, Float (priority), SipStatusEnum>
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyBLFSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyBLFSipImpl.java
index 644c85a..a9aefbe 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyBLFSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetTelephonyBLFSipImpl.java
@@ -72,6 +72,10 @@ public class OperationSetTelephonyBLFSipImpl
* Account property suffix to set/provision monitored line group.
*/
public static final String BLF_LINE_GROUP_ACC_PROP_PREFIX = "Group";
+ /**
+ * Account property suffix to set/provision monitored line pickup template.
+ */
+ public static final String BLF_LINE_PICKUP_ACC_PROP_PREFIX = "Pickup";
/**
* The name of the event package supported by
@@ -195,7 +199,7 @@ public class OperationSetTelephonyBLFSipImpl
String[] lineValues = lines.get(ix);
if(lineValues == null)
{
- lineValues = new String[3];
+ lineValues = new String[4];
lines.put(ix, lineValues);
}
@@ -211,13 +215,17 @@ public class OperationSetTelephonyBLFSipImpl
{
lineValues[2] = entryValue;
}
+ else if(pName.contains(BLF_LINE_PICKUP_ACC_PROP_PREFIX))
+ {
+ lineValues[3] = entryValue;
+ }
}
for(Map.Entry<String, String[]> en : lines.entrySet())
{
String[] vals = en.getValue();
- this.lines.add(new Line(vals[0], vals[1], vals[2], this.provider));
+ this.lines.add(new Line(vals[0], vals[1], vals[2], vals[3], this.provider));
}
}
@@ -263,16 +271,25 @@ public class OperationSetTelephonyBLFSipImpl
if(details == null)
return;
- if(StringUtils.isNullOrEmpty(details.callID)
- || StringUtils.isNullOrEmpty(details.localTag)
- || StringUtils.isNullOrEmpty(details.remoteTag))
- return;
-
// replaces
Address targetAddress = null;
try
{
- targetAddress = provider.parseAddressString(line.getAddress());
+ String address = line.getAddress();
+ if(asteriskMode(details))
+ {
+ // broken mode for Asterisk, doesn't provide us with
+ // the proper call-id, etc. attributes.
+ // send an unspecified pickup-call if a template is set
+ if (StringUtils.isNullOrEmpty(line.getPickupTemplate(), true))
+ {
+ return;
+ }
+
+ address = line.getPickupTemplate().replace("\\1", address);
+ }
+
+ targetAddress = provider.parseAddressString(address);
}
catch (ParseException ex)
{
@@ -281,6 +298,16 @@ public class OperationSetTelephonyBLFSipImpl
OperationFailedException.ILLEGAL_ARGUMENT, ex, logger);
}
+ OperationSetBasicTelephonySipImpl telOpSet
+ = (OperationSetBasicTelephonySipImpl)provider
+ .getOperationSet(OperationSetBasicTelephony.class);
+
+ if (asteriskMode(details))
+ {
+ telOpSet.createOutgoingCall(targetAddress, null, null);
+ return;
+ }
+
Replaces replacesHeader = null;
SipURI sipURI = (SipURI) targetAddress.getURI();
@@ -315,12 +342,14 @@ public class OperationSetTelephonyBLFSipImpl
OperationFailedException.INTERNAL_ERROR, ex, logger);
}
- OperationSetBasicTelephonySipImpl telOpSet
- = (OperationSetBasicTelephonySipImpl)provider
- .getOperationSet(OperationSetBasicTelephony.class);
-
- CallSipImpl call
- = telOpSet.createOutgoingCall(targetAddress, null, null);
+ telOpSet.createOutgoingCall(targetAddress, null, null);
+ }
+
+ private boolean asteriskMode(LineDetails details)
+ {
+ return StringUtils.isNullOrEmpty(details.callID)
+ || StringUtils.isNullOrEmpty(details.localTag)
+ || StringUtils.isNullOrEmpty(details.remoteTag);
}
/**
@@ -549,6 +578,8 @@ public class OperationSetTelephonyBLFSipImpl
Node dialogNode = dialogList.item(i);
Element dialogElem = (Element)dialogNode;
+ details.id = dialogElem.getAttribute("id");
+ details.direction = dialogElem.getAttribute("direction");
details.callID = dialogElem.getAttribute("call-id");
details.localTag = dialogElem.getAttribute("local-tag");
details.remoteTag = dialogElem.getAttribute("remote-tag");
@@ -698,12 +729,25 @@ public class OperationSetTelephonyBLFSipImpl
*/
private class LineDetails
{
+
/**
* The current status of the line, the last event fired for it.
*/
int lastStatusEvent = BLFStatusEvent.STATUS_OFFLINE;
/**
+ * id of the dialog. Mandatory.
+ */
+ String id = null;
+
+ /**
+ * either initiator or recipient, and indicates whether the observed
+ * user was the initiator of the dialog, or the recipient of the INVITE
+ * that created it.
+ */
+ String direction;
+
+ /**
* call-id of the dialog if any, used for remote pickup.
*/
String callID = null;
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
index 0fbcf23..927c0a3 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
@@ -246,6 +246,76 @@ public class ProtocolProviderServiceSipImpl
}
/**
+ * Validates the contact identifier and returns an error message if
+ * applicable and a suggested correction
+ *
+ * @param contactId the contact identifier to validate
+ * @param result Must be supplied as an empty a list. Implementors add
+ * items:
+ * <ol>
+ * <li>is the error message if applicable
+ * <li>a suggested correction. Index 1 is optional and can only
+ * be present if there was a validation failure.
+ * </ol>
+ * @return true if the contact id is valid, false otherwise
+ */
+ @Override
+ public boolean validateContactAddress(String contactId, List<String> result)
+ {
+ if (result == null)
+ {
+ throw new IllegalArgumentException("result must be an empty list");
+ }
+
+ result.clear();
+ try
+ {
+ Address address = parseAddressString(contactId);
+ if (address.toString().equals(contactId))
+ {
+ return true;
+ }
+ else if (((SipUri) address.getURI()).getUser().equals(contactId))
+ {
+ return true;
+ }
+ else if (address.toString().equals(address.getURI().getScheme() + ":" + contactId))
+ {
+ return true;
+ }
+ else
+ {
+ result.add(SipActivator.getResources().getI18NString(
+ "impl.protocol.sip.INVALID_ADDRESS", new String[]
+ { contactId }));
+ result.add(((SipUri) address.getURI()).getUser());
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.error("Validating SIP address failed for " + contactId, ex);
+ result.add(SipActivator.getResources()
+ .getI18NString("impl.protocol.sip.INVALID_ADDRESS", new String[]
+ { contactId }));
+
+ String user = contactId;
+ String remainder = "";
+ int at = contactId.indexOf('@');
+ if (at > -1)
+ {
+ user = contactId.substring(0, at);
+ remainder = contactId.substring(at);
+ }
+
+ // replace invalid characters in user part with hex encoding
+ String banned = "([^a-z0-9-_.!~*'()&=+$,;?/])+";
+ result.add(user.replaceAll(banned, "") + remainder);
+ }
+
+ return false;
+ }
+
+ /**
* Indicates whether or not this provider must registered
* when placing outgoing calls.
*
@@ -610,50 +680,50 @@ public class ProtocolProviderServiceSipImpl
addSupportedOperationSet(
OperationSetPresence.class,
opSetPersPresence);
+ }
- // Only init messaging and typing if enabled.
- boolean isMessagingDisabled
- = SipActivator.getConfigurationService()
- .getBoolean(IS_MESSAGING_DISABLED, false);
+ // Only init messaging and typing if enabled.
+ boolean isMessagingDisabled
+ = SipActivator.getConfigurationService()
+ .getBoolean(IS_MESSAGING_DISABLED, false);
- if (!isMessagingDisabled)
- {
- // init instant messaging
- this.opSetBasicIM =
- new OperationSetBasicInstantMessagingSipImpl(this);
+ if (!isMessagingDisabled)
+ {
+ // init instant messaging
+ this.opSetBasicIM =
+ new OperationSetBasicInstantMessagingSipImpl(this);
- addSupportedOperationSet(
- OperationSetBasicInstantMessaging.class,
- opSetBasicIM);
+ addSupportedOperationSet(
+ OperationSetBasicInstantMessaging.class,
+ opSetBasicIM);
- // init typing notifications
- this.opSetTypingNotif
- = new OperationSetTypingNotificationsSipImpl(
- this, opSetBasicIM);
- addSupportedOperationSet(
- OperationSetTypingNotifications.class,
- opSetTypingNotif);
+ // init typing notifications
+ this.opSetTypingNotif
+ = new OperationSetTypingNotificationsSipImpl(
+ this, opSetBasicIM);
+ addSupportedOperationSet(
+ OperationSetTypingNotifications.class,
+ opSetTypingNotif);
- addSupportedOperationSet(
- OperationSetInstantMessageTransform.class,
- new OperationSetInstantMessageTransformImpl());
- }
+ addSupportedOperationSet(
+ OperationSetInstantMessageTransform.class,
+ new OperationSetInstantMessageTransformImpl());
+ }
- this.opSetSSAccountInfo =
- new OperationSetServerStoredAccountInfoSipImpl(this);
+ this.opSetSSAccountInfo =
+ new OperationSetServerStoredAccountInfoSipImpl(this);
- // Set the display name.
- opSetSSAccountInfo.setOurDisplayName(ourDisplayName);
+ // Set the display name.
+ opSetSSAccountInfo.setOurDisplayName(ourDisplayName);
- // init avatar
- addSupportedOperationSet(
- OperationSetServerStoredAccountInfo.class,
- opSetSSAccountInfo);
+ // init avatar
+ addSupportedOperationSet(
+ OperationSetServerStoredAccountInfo.class,
+ opSetSSAccountInfo);
- addSupportedOperationSet(
- OperationSetAvatar.class,
- new OperationSetAvatarSipImpl(this, opSetSSAccountInfo));
- }
+ addSupportedOperationSet(
+ OperationSetAvatar.class,
+ new OperationSetAvatarSipImpl(this, opSetSSAccountInfo));
// MWI is enabled by default
if(accountID.getAccountPropertyBoolean(
@@ -1519,16 +1589,16 @@ public class ProtocolProviderServiceSipImpl
Set<ProtocolProviderServiceSipImpl> instances
= new HashSet<ProtocolProviderServiceSipImpl>();
BundleContext context = SipActivator.getBundleContext();
- ServiceReference[] references = context.getServiceReferences(
- ProtocolProviderService.class.getName(),
- null
- );
- for(ServiceReference reference : references)
+ Collection<ServiceReference<ProtocolProviderService>> references =
+ context.getServiceReferences(ProtocolProviderService.class,
+ null);
+ for(ServiceReference<ProtocolProviderService> ref : references)
{
- Object service = context.getService(reference);
+ ProtocolProviderService service = context.getService(ref);
if(service instanceof ProtocolProviderServiceSipImpl)
instances.add((ProtocolProviderServiceSipImpl) service);
}
+
return instances;
}
catch(InvalidSyntaxException ex)
@@ -2390,21 +2460,38 @@ public class ProtocolProviderServiceSipImpl
//we don't know how to handle the "tel:" and "callto:" schemes ... or
// rather we handle them same as sip so replace:
if(uriStr.toLowerCase().startsWith("tel:"))
- uriStr = "sip:" + uriStr.substring("tel:".length());
+ uriStr = uriStr.substring("tel:".length());
else if(uriStr.toLowerCase().startsWith("callto:"))
- uriStr = "sip:" + uriStr.substring("callto:".length());
+ uriStr = uriStr.substring("callto:".length());
+ else if(uriStr.toLowerCase().startsWith("sips:"))
+ uriStr = uriStr.substring("sips:".length());
+ else if(uriStr.toLowerCase().startsWith("sip:"))
+ uriStr = uriStr.substring("sip:".length());
+
+ String user = uriStr;
+ String remainder = "";
+ int at = uriStr.indexOf('@');
+ if (at > -1)
+ {
+ user = uriStr.substring(0, at);
+ remainder = uriStr.substring(at);
+ }
+
+ //replace invalid characters in user part with hex encoding
+ String banned = "([^a-z0-9-_.!~*'()&=+$,;?/])+";
+ user = user.replaceAll(banned, "") + remainder;
//Handle default domain name (i.e. transform 1234 -> 1234@sip.com)
//assuming that if no domain name is specified then it should be the
//same as ours.
- if (uriStr.indexOf('@') == -1)
+ if (at == -1)
{
//if we have a registrar, then we could append its domain name as
//default
SipRegistrarConnection src = sipRegistrarConnection;
if(src != null && !src.isRegistrarless() )
{
- uriStr = uriStr + "@"
+ uriStr = user + "@"
+ ((SipURI)src.getAddressOfRecord().getURI()).getHost();
}
@@ -2684,6 +2771,11 @@ public class ProtocolProviderServiceSipImpl
*/
protected void notifyConnectionFailed()
{
+ if (sipRegistrarConnection.isRegistrarless())
+ {
+ return;
+ }
+
if(getRegistrationState().equals(RegistrationState.REGISTERED)
&& sipRegistrarConnection != null)
sipRegistrarConnection.setRegistrationState(
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProxyRouter.java b/src/net/java/sip/communicator/impl/protocol/sip/ProxyRouter.java
index 5d60612..b6bf997 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ProxyRouter.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ProxyRouter.java
@@ -19,6 +19,7 @@ package net.java.sip.communicator.impl.protocol.sip;
import gov.nist.javax.sip.stack.*;
+import java.net.*;
import java.util.*;
import javax.sip.*;
@@ -26,6 +27,7 @@ import javax.sip.address.*;
import javax.sip.header.*;
import javax.sip.message.*;
+import net.java.sip.communicator.impl.protocol.sip.net.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
@@ -137,7 +139,9 @@ public class ProxyRouter
ProtocolProviderServiceSipImpl sipProvider
= ((ProtocolProviderServiceSipImpl) service);
- String proxy = sipProvider.getConnection().getOutboundProxyString();
+ final ProxyConnection connection = sipProvider.getConnection();
+ final String proxy = connection.getOutboundProxyString();
+ logger.trace("Router for proxy: " + proxy);
boolean forceLooseRouting
= sipProvider.getAccountID()
@@ -146,13 +150,30 @@ public class ProxyRouter
// P2P case
if (proxy == null || forceLooseRouting )
+ {
+ logger.info("Returning default SIP router, P2P/loose routing");
return this.getDefaultRouter();
+ }
// outbound proxy case
Router router = routerCache.get(proxy);
if (router == null)
{
- router = new DefaultRouter(stack, proxy);
+ router = new DefaultRouter(stack, proxy)
+ {
+ @Override
+ public Hop getNextHop(Request request) throws SipException
+ {
+ logger.info("Outbound proxy mode, using proxy " +
+ proxy + " as hop instead of an address resolved" +
+ " by the SIP router");
+ InetSocketAddress sa = connection.getAddress();
+ return new HopImpl(
+ sa.getAddress().getHostAddress(),
+ sa.getPort(),
+ connection.getTransport());
+ }
+ };
routerCache.put(proxy, router);
}
return router;
@@ -164,6 +185,7 @@ public class ProxyRouter
logger.error("unable to identify the service which created this "
+ "out-of-dialog request");
+ logger.info("Returning default router");
return this.getDefaultRouter();
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java b/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java
index 99cb0f8..2a3ed00 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java
@@ -1288,8 +1288,11 @@ public class SipRegistrarConnection
if(registrarPort != ListeningPoint.PORT_5060)
registrarURI.setPort(registrarPort);
- if(!registrationTransport.equals(ListeningPoint.UDP))
+ if(!registrationTransport.equals(ListeningPoint.UDP)
+ && !registrationTransport.equals(ListeningPoint.TLS))
+ {
registrarURI.setTransportParam(registrationTransport);
+ }
}
return registrarURI;
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java b/src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java
index 2e714b5..c92782e 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/SipStackSharing.java
@@ -1172,6 +1172,9 @@ public class SipStackSharing
String transport)
throws IOException
{
+ logger.info("Gettting source address for " +
+ localAddress + " -> " + dst + ":" + dstPort +
+ "(" + transport + ")");
if(ListeningPoint.TLS.equalsIgnoreCase(transport))
return (java.net.InetSocketAddress)(((SipStackImpl)this.stack)
.getLocalAddressForTlsDst(dst, dstPort, localAddress));
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/UriHandlerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/UriHandlerSipImpl.java
index 885455a..ecec5c5 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/UriHandlerSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/UriHandlerSipImpl.java
@@ -351,7 +351,11 @@ public class UriHandlerSipImpl
// Even if not registered after the timeout, try the call
// anyway and the error popup will appear to ask the
// user if they want to register
- handleUri(uri, provider);
+ if(provider.getRegistrationState()
+ != RegistrationState.REGISTERED)
+ {
+ handleUri(uri, provider);
+ }
}
}, initialRegistrationTimeout);
}
@@ -401,9 +405,34 @@ public class UriHandlerSipImpl
OperationSetBasicTelephony<?> telephonyOpSet
= provider.getOperationSet(OperationSetBasicTelephony.class);
+ OperationSetVideoTelephony videoTelephonyOpSet
+ = provider.getOperationSet(OperationSetVideoTelephony.class);
+
+ boolean videoCall = false;
+ if(videoTelephonyOpSet != null
+ && uri.contains("?"))
+ {
+ String params = uri.substring(uri.indexOf('?') + 1);
+ uri = uri.substring(0, uri.indexOf('?'));
+
+ StringTokenizer paramTokens = new StringTokenizer(params, "&");
+ while(paramTokens.hasMoreTokens())
+ {
+ String tok = paramTokens.nextToken();
+ String[] keyValue = tok.split("\\=");
+ if (keyValue.length == 2
+ && keyValue[0].equalsIgnoreCase("video")
+ && keyValue[1].equalsIgnoreCase("true"))
+ videoCall = true;
+ }
+ }
+
try
{
- telephonyOpSet.createCall(uri);
+ if(videoCall)
+ videoTelephonyOpSet.createVideoCall(uri);
+ else
+ telephonyOpSet.createCall(uri);
}
catch (OperationFailedException exc)
{
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/net/ManualProxyConnection.java b/src/net/java/sip/communicator/impl/protocol/sip/net/ManualProxyConnection.java
index 5439d99..ca7faa9 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/net/ManualProxyConnection.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/net/ManualProxyConnection.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,115 +15,115 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.sip.net;
-
-import static javax.sip.ListeningPoint.PORT_5060;
-import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.PREFERRED_TRANSPORT;
-import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.PROXY_ADDRESS;
-import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.PROXY_PORT;
-
-import java.net.*;
-import java.text.*;
-
-import net.java.sip.communicator.impl.protocol.sip.*;
-import net.java.sip.communicator.service.dns.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Implementation of the manually configured SIP proxy connection. IP Address
- * lookups are performed using the account's proxy address.
- *
- * @author Ingo Bauersachs
- */
-public class ManualProxyConnection
- extends ProxyConnection
-{
- private final static Logger logger
- = Logger.getLogger(ManualProxyConnection.class);
-
- private String address;
- private int port;
-
- private InetSocketAddress[] lookups;
- private int lookupIndex;
-
- /**
- * Creates a new instance of this class. Uses the server from the account.
- *
- * @param account the account of this SIP protocol instance
- */
- public ManualProxyConnection(SipAccountIDImpl account)
- {
- super(account);
- reset();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see net.java.sip.communicator.impl.protocol.sip.net.ProxyConnection#
- * getNextAddress()
- */
- @Override
- public boolean getNextAddressFromDns()
- throws DnssecException
- {
- if(lookups == null)
- {
- try
- {
- lookupIndex = 0;
- lookups = NetworkUtils.getAandAAAARecords(address, port);
-
- //no result found, reset state and indicate "out of addresses"
- if(lookups.length == 0)
- {
- lookups = null;
- return false;
- }
- }
- catch (ParseException e)
- {
- logger.error("Invalid address <" + address + ">", e);
- return false;
- }
- }
-
- //check if the available addresses are exhausted
- if(lookupIndex >= lookups.length)
- {
- if(logger.isDebugEnabled())
- logger.debug("No more addresses for " + account);
- lookups = null;
- return false;
- }
-
- //assign the next address and return lookup success
- if(logger.isDebugEnabled())
- logger.debug("Returning <" + socketAddress
- + "> as next address for " + account);
- socketAddress = lookups[lookupIndex];
- lookupIndex++;
- return true;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * net.java.sip.communicator.impl.protocol.sip.net.ProxyConnection#reset()
- */
- @Override
- public void reset()
- {
- super.reset();
- address = account.getAccountPropertyString(PROXY_ADDRESS);
- port = account.getAccountPropertyInt(PROXY_PORT, PORT_5060);
- transport = account.getAccountPropertyString(PREFERRED_TRANSPORT);
-
- //check property sanity
- if(!ProtocolProviderServiceSipImpl.isValidTransport(transport))
- throw new IllegalArgumentException(
- transport + " is not a valid SIP transport");
- }
-}
+package net.java.sip.communicator.impl.protocol.sip.net;
+
+import static javax.sip.ListeningPoint.PORT_5060;
+import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.PREFERRED_TRANSPORT;
+import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.PROXY_ADDRESS;
+import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.PROXY_PORT;
+
+import java.net.*;
+import java.text.*;
+
+import net.java.sip.communicator.impl.protocol.sip.*;
+import net.java.sip.communicator.service.dns.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Implementation of the manually configured SIP proxy connection. IP Address
+ * lookups are performed using the account's proxy address.
+ *
+ * @author Ingo Bauersachs
+ */
+public class ManualProxyConnection
+ extends ProxyConnection
+{
+ private final static Logger logger
+ = Logger.getLogger(ManualProxyConnection.class);
+
+ private String address;
+ private int port;
+
+ private InetSocketAddress[] lookups;
+ private int lookupIndex;
+
+ /**
+ * Creates a new instance of this class. Uses the server from the account.
+ *
+ * @param account the account of this SIP protocol instance
+ */
+ public ManualProxyConnection(SipAccountIDImpl account)
+ {
+ super(account);
+ reset();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.java.sip.communicator.impl.protocol.sip.net.ProxyConnection#
+ * getNextAddress()
+ */
+ @Override
+ public boolean getNextAddressFromDns()
+ throws DnssecException
+ {
+ if(lookups == null)
+ {
+ try
+ {
+ lookupIndex = 0;
+ lookups = NetworkUtils.getAandAAAARecords(address, port);
+
+ //no result found, reset state and indicate "out of addresses"
+ if(lookups.length == 0)
+ {
+ lookups = null;
+ return false;
+ }
+ }
+ catch (ParseException e)
+ {
+ logger.error("Invalid address <" + address + ">", e);
+ return false;
+ }
+ }
+
+ //check if the available addresses are exhausted
+ if(lookupIndex >= lookups.length)
+ {
+ if(logger.isDebugEnabled())
+ logger.debug("No more addresses for " + account);
+ lookups = null;
+ return false;
+ }
+
+ //assign the next address and return lookup success
+ if(logger.isDebugEnabled())
+ logger.debug("Returning <" + socketAddress
+ + "> as next address for " + account);
+ socketAddress = lookups[lookupIndex];
+ lookupIndex++;
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.java.sip.communicator.impl.protocol.sip.net.ProxyConnection#reset()
+ */
+ @Override
+ public void reset()
+ {
+ super.reset();
+ address = account.getAccountPropertyString(PROXY_ADDRESS);
+ port = account.getAccountPropertyInt(PROXY_PORT, PORT_5060);
+ transport = account.getAccountPropertyString(PREFERRED_TRANSPORT);
+
+ //check property sanity
+ if(!ProtocolProviderServiceSipImpl.isValidTransport(transport))
+ throw new IllegalArgumentException(
+ transport + " is not a valid SIP transport");
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/net/ProxyConnection.java b/src/net/java/sip/communicator/impl/protocol/sip/net/ProxyConnection.java
index 99fcfb2..f7079f4 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/net/ProxyConnection.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/net/ProxyConnection.java
@@ -1,180 +1,180 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.sip.net;
-
-import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.PROXY_AUTO_CONFIG;
-
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.impl.protocol.sip.*;
-import net.java.sip.communicator.service.dns.*;
-
-/**
- * Abstract class for the determining the address for the SIP proxy.
- *
- * @author Ingo Bauersachs
- */
-public abstract class ProxyConnection
-{
- private List<String> returnedAddresses = new LinkedList<String>();
-
- protected String transport;
- protected InetSocketAddress socketAddress;
- protected final SipAccountIDImpl account;
-
- /**
- * Creates a new instance of this class.
- * @param account the account of this SIP protocol instance
- */
- protected ProxyConnection(SipAccountIDImpl account)
- {
- this.account = account;
- }
-
- /**
- * Gets the address to use for the next connection attempt.
- * @return the address of the last lookup.
- */
- public final InetSocketAddress getAddress()
- {
- return socketAddress;
- }
-
- /**
- * Gets the transport to use for the next connection attempt.
- * @return the transport of the last lookup.
- */
- public final String getTransport()
- {
- return transport;
- }
-
- /**
- * In case we are using an outbound proxy this method returns
- * a suitable string for use with Router.
- * The method returns <tt>null</tt> otherwise.
- *
- * @return the string of our outbound proxy if we are using one and
- * <tt>null</tt> otherwise.
- */
- public final String getOutboundProxyString()
- {
- if(socketAddress == null)
- return null;
-
- InetAddress proxyAddress = socketAddress.getAddress();
- StringBuilder proxyStringBuffer
- = new StringBuilder(proxyAddress.getHostAddress());
-
- if(proxyAddress instanceof Inet6Address)
- {
- proxyStringBuffer.insert(0, '[');
- proxyStringBuffer.append(']');
- }
-
- proxyStringBuffer.append(':');
- proxyStringBuffer.append(socketAddress.getPort());
- proxyStringBuffer.append('/');
- proxyStringBuffer.append(transport);
-
- return proxyStringBuffer.toString();
- }
-
- /**
- * Compares an InetAddress against the active outbound proxy. The comparison
- * is by reference, not equals.
- *
- * @param addressToTest The addres to test.
- * @return True when the InetAddress is the same as the outbound proxy.
- */
- public final boolean isSameInetAddress(InetAddress addressToTest)
- {
- // if the proxy is not yet initialized then this is not the provider
- // that caused this comparison
- if(socketAddress == null)
- return false;
- return addressToTest == socketAddress.getAddress();
- }
-
- /**
- * Retrieves the next address to use from DNS. Duplicate results are
- * suppressed.
- *
- * @return True if a new address is available through {@link #getAddress()},
- * false if the last address was reached. A new lookup from scratch
- * can be started by calling {@link #reset()}.
- * @throws DnssecException if there is a problem related to DNSSEC
- */
- public final boolean getNextAddress() throws DnssecException
- {
- boolean result;
- String key = null;
- do
- {
- result = getNextAddressFromDns();
- if(result && socketAddress != null)
- {
- key = getOutboundProxyString();
- if(!returnedAddresses.contains(key))
- {
- returnedAddresses.add(key);
- break;
- }
- }
- }
- while(result && returnedAddresses.contains(key));
- return result;
- }
-
- /**
- * Implementations must use this method to get the next address, but do not
- * have to care about duplicate addresses.
- *
- * @return True when a further address was available.
- * @throws DnssecException when a DNSSEC validation failure occured.
- */
- protected abstract boolean getNextAddressFromDns()
- throws DnssecException;
-
- /**
- * Resets the lookup to it's initial state. Overriders methods have to call
- * this method through a super-call.
- */
- public void reset()
- {
- returnedAddresses.clear();
- }
-
- /**
- * Factory method to create a proxy connection based on the account settings
- * of the protocol provider.
- *
- * @param pps the protocol provider that needs a SIP server connection.
- * @return An instance of a derived class.
- */
- public static ProxyConnection create(ProtocolProviderServiceSipImpl pps)
- {
- if (pps.getAccountID().getAccountPropertyBoolean(PROXY_AUTO_CONFIG,
- true))
- return new AutoProxyConnection((SipAccountIDImpl) pps.getAccountID(),
- pps.getDefaultTransport());
- else
- return new ManualProxyConnection((SipAccountIDImpl) pps.getAccountID());
- }
-}
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Copyright @ 2015 Atlassian Pty Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.java.sip.communicator.impl.protocol.sip.net;
+
+import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.PROXY_AUTO_CONFIG;
+
+import java.net.*;
+import java.util.*;
+
+import net.java.sip.communicator.impl.protocol.sip.*;
+import net.java.sip.communicator.service.dns.*;
+
+/**
+ * Abstract class for the determining the address for the SIP proxy.
+ *
+ * @author Ingo Bauersachs
+ */
+public abstract class ProxyConnection
+{
+ private List<String> returnedAddresses = new LinkedList<String>();
+
+ protected String transport;
+ protected InetSocketAddress socketAddress;
+ protected final SipAccountIDImpl account;
+
+ /**
+ * Creates a new instance of this class.
+ * @param account the account of this SIP protocol instance
+ */
+ protected ProxyConnection(SipAccountIDImpl account)
+ {
+ this.account = account;
+ }
+
+ /**
+ * Gets the address to use for the next connection attempt.
+ * @return the address of the last lookup.
+ */
+ public final InetSocketAddress getAddress()
+ {
+ return socketAddress;
+ }
+
+ /**
+ * Gets the transport to use for the next connection attempt.
+ * @return the transport of the last lookup.
+ */
+ public final String getTransport()
+ {
+ return transport;
+ }
+
+ /**
+ * In case we are using an outbound proxy this method returns
+ * a suitable string for use with Router.
+ * The method returns <tt>null</tt> otherwise.
+ *
+ * @return the string of our outbound proxy if we are using one and
+ * <tt>null</tt> otherwise.
+ */
+ public final String getOutboundProxyString()
+ {
+ if(socketAddress == null)
+ return null;
+
+ InetAddress proxyAddress = socketAddress.getAddress();
+ StringBuilder proxyStringBuffer
+ = new StringBuilder(proxyAddress.getHostAddress());
+
+ if(proxyAddress instanceof Inet6Address)
+ {
+ proxyStringBuffer.insert(0, '[');
+ proxyStringBuffer.append(']');
+ }
+
+ proxyStringBuffer.append(':');
+ proxyStringBuffer.append(socketAddress.getPort());
+ proxyStringBuffer.append('/');
+ proxyStringBuffer.append(transport);
+
+ return proxyStringBuffer.toString();
+ }
+
+ /**
+ * Compares an InetAddress against the active outbound proxy. The comparison
+ * is by reference, not equals.
+ *
+ * @param addressToTest The addres to test.
+ * @return True when the InetAddress is the same as the outbound proxy.
+ */
+ public final boolean isSameInetAddress(InetAddress addressToTest)
+ {
+ // if the proxy is not yet initialized then this is not the provider
+ // that caused this comparison
+ if(socketAddress == null)
+ return false;
+ return addressToTest == socketAddress.getAddress();
+ }
+
+ /**
+ * Retrieves the next address to use from DNS. Duplicate results are
+ * suppressed.
+ *
+ * @return True if a new address is available through {@link #getAddress()},
+ * false if the last address was reached. A new lookup from scratch
+ * can be started by calling {@link #reset()}.
+ * @throws DnssecException if there is a problem related to DNSSEC
+ */
+ public final boolean getNextAddress() throws DnssecException
+ {
+ boolean result;
+ String key = null;
+ do
+ {
+ result = getNextAddressFromDns();
+ if(result && socketAddress != null)
+ {
+ key = getOutboundProxyString();
+ if(!returnedAddresses.contains(key))
+ {
+ returnedAddresses.add(key);
+ break;
+ }
+ }
+ }
+ while(result && returnedAddresses.contains(key));
+ return result;
+ }
+
+ /**
+ * Implementations must use this method to get the next address, but do not
+ * have to care about duplicate addresses.
+ *
+ * @return True when a further address was available.
+ * @throws DnssecException when a DNSSEC validation failure occured.
+ */
+ protected abstract boolean getNextAddressFromDns()
+ throws DnssecException;
+
+ /**
+ * Resets the lookup to it's initial state. Overriders methods have to call
+ * this method through a super-call.
+ */
+ public void reset()
+ {
+ returnedAddresses.clear();
+ }
+
+ /**
+ * Factory method to create a proxy connection based on the account settings
+ * of the protocol provider.
+ *
+ * @param pps the protocol provider that needs a SIP server connection.
+ * @return An instance of a derived class.
+ */
+ public static ProxyConnection create(ProtocolProviderServiceSipImpl pps)
+ {
+ if (pps.getAccountID().getAccountPropertyBoolean(PROXY_AUTO_CONFIG,
+ true))
+ return new AutoProxyConnection((SipAccountIDImpl) pps.getAccountID(),
+ pps.getDefaultTransport());
+ else
+ return new ManualProxyConnection((SipAccountIDImpl) pps.getAccountID());
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/net/RFC5922Matcher.java b/src/net/java/sip/communicator/impl/protocol/sip/net/RFC5922Matcher.java
index 0027ec5..262b717 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/net/RFC5922Matcher.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/net/RFC5922Matcher.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,211 +15,211 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.protocol.sip.net;
-
-import java.security.cert.*;
-import java.text.*;
-import java.util.*;
-import java.util.regex.*;
-
-import javax.sip.address.*;
-
-import net.java.sip.communicator.impl.protocol.sip.*;
-import net.java.sip.communicator.service.certificate.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Matcher that extracts certificate identities according to <a
- * href="http://tools.ietf.org/html/rfc5922#section-7.1">RFC5922, Section
- * 7.1</a> and compares them with the rules from Section 7.2 and 7.3.
- * @see #PNAME_STRICT_RFC5922 for wildcard handling; the default is false
- *
- * @author Ingo Bauersachs
- */
-public class RFC5922Matcher
- implements CertificateMatcher
-{
- /**
- * When set to true, enables strict validation of the hostname according to
- * <a href="http://tools.ietf.org/html/rfc5922#section-7.2">RFC5922 Section
- * 7.2</a>
- */
- public final static String PNAME_STRICT_RFC5922 =
- "net.java.sip.communicator.sip.tls.STRICT_RFC5922";
-
- private ProtocolProviderServiceSipImpl provider;
-
- /**
- * Creates a new instance of this class.
- * @param provider The SIP Provider to which this matcher belongs.
- */
- public RFC5922Matcher(ProtocolProviderServiceSipImpl provider)
- {
- this.provider = provider;
- }
-
- /** Our class logger. */
- private static final Logger logger = Logger
- .getLogger(CertificateMatcher.class);
-
- /*
- * (non-Javadoc)
- *
- * @see
- * net.java.sip.communicator.service.certificate.CertificateMatcher#verify
- * (java.lang.Iterable, java.security.cert.X509Certificate)
- */
- public void verify(Iterable<String> identitiesToTest, X509Certificate cert)
- throws CertificateException
- {
- boolean strict = SipActivator.getConfigurationService()
- .getBoolean(PNAME_STRICT_RFC5922, false);
-
- // if any of the identities is contained in the certificate we're good
- boolean oneMatched = false;
- Iterable<String> certIdentities = extractCertIdentities(cert);
- for (String identity : identitiesToTest)
- {
- // check if the intended hostname is contained in one of the
- // hostnames of the certificate according to
- // http://tools.ietf.org/html/rfc5922#section-7.2
- for(String dnsName : certIdentities)
- {
- try
- {
- if(NetworkUtils.compareDnsNames(dnsName, identity) == 0)
- {
- // one of the hostnames matched, we're good to go
- return;
- }
-
- if(!strict
- // is a wildcard name
- && dnsName.startsWith("*.")
- // contains at least two dots (*.example.com)
- && identity.indexOf(".") < identity.lastIndexOf(".")
- // compare *.example.com stripped to example.com with
- // - foo.example.com stripped to example.com
- // - foo.bar.example.com to bar.example.com
- && NetworkUtils.compareDnsNames(
- dnsName.substring(2),
- identity.substring(identity.indexOf(".")+1)) == 0)
- {
- // the wildcard matched, we're good to go
- return;
- }
- }
- catch (ParseException e)
- {} // we don't care - this hostname did not match
- }
- }
- if (!oneMatched)
- throw new CertificateException("None of <" + identitiesToTest
- + "> matched by the rules of RFC5922 to the cert with CN="
- + cert.getSubjectDN());
- }
-
- private Iterable<String> extractCertIdentities(X509Certificate cert)
- {
- List<String> certIdentities = new ArrayList<String>();
- Collection<List<?>> subjAltNames = null;
- try
- {
- subjAltNames = cert.getSubjectAlternativeNames();
- }
- catch (CertificateParsingException ex)
- {
- logger.error("Error parsing TLS certificate", ex);
- }
- // subjAltName types are defined in rfc2459
- final Integer dnsNameType = 2;
- final Integer uriNameType = 6;
- if (subjAltNames != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("found subjAltNames: " + subjAltNames);
-
- // First look for a URI in the subjectAltName field
- for (List<?> altName : subjAltNames)
- {
- // 0th position is the alt name type
- // 1st position is the alt name data
- if (altName.get(0).equals(uriNameType))
- {
- SipURI altNameUri;
- try
- {
- altNameUri =
- provider.getAddressFactory().createSipURI(
- (String) altName.get(1));
- // only sip URIs are allowed
- if (!"sip".equals(altNameUri.getScheme()))
- continue;
- // user certificates are not allowed
- if (altNameUri.getUser() != null)
- continue;
- String altHostName = altNameUri.getHost();
- if (logger.isDebugEnabled())
- {
- logger.debug("found uri " + altName.get(1)
- + ", hostName " + altHostName);
- }
- certIdentities.add(altHostName);
- }
- catch (ParseException e)
- {
- logger.error("certificate contains invalid uri: "
- + altName.get(1));
- }
- }
-
- }
- // DNS An implementation MUST accept a domain name system
- // identifier as a SIP domain identity if and only if no other
- // identity is found that matches the "sip" URI type described
- // above.
- if (certIdentities.isEmpty())
- {
- for (List<?> altName : subjAltNames)
- {
- if (altName.get(0).equals(dnsNameType))
- {
- if (logger.isDebugEnabled())
- logger.debug("found dns " + altName.get(1));
- certIdentities.add(altName.get(1).toString());
- }
- }
- }
- }
- else
- {
- // If and only if the subjectAltName does not appear in the
- // certificate, the implementation MAY examine the CN field of the
- // certificate. If a valid DNS name is found there, the
- // implementation MAY accept this value as a SIP domain identity.
- String dname = cert.getSubjectDN().getName();
- String cname = "";
- try
- {
- Pattern EXTRACT_CN =
- Pattern.compile(".*CN\\s*=\\s*([\\w*\\.]+).*");
- Matcher matcher = EXTRACT_CN.matcher(dname);
- if (matcher.matches())
- {
- cname = matcher.group(1);
- if (logger.isDebugEnabled())
- {
- logger.debug("found CN: " + cname + " from DN: "
- + dname);
- }
- certIdentities.add(cname);
- }
- }
- catch (Exception ex)
- {
- logger.error("exception while extracting CN", ex);
- }
- }
- return certIdentities;
- }
-}
+package net.java.sip.communicator.impl.protocol.sip.net;
+
+import java.security.cert.*;
+import java.text.*;
+import java.util.*;
+import java.util.regex.*;
+
+import javax.sip.address.*;
+
+import net.java.sip.communicator.impl.protocol.sip.*;
+import net.java.sip.communicator.service.certificate.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Matcher that extracts certificate identities according to <a
+ * href="http://tools.ietf.org/html/rfc5922#section-7.1">RFC5922, Section
+ * 7.1</a> and compares them with the rules from Section 7.2 and 7.3.
+ * @see #PNAME_STRICT_RFC5922 for wildcard handling; the default is false
+ *
+ * @author Ingo Bauersachs
+ */
+public class RFC5922Matcher
+ implements CertificateMatcher
+{
+ /**
+ * When set to true, enables strict validation of the hostname according to
+ * <a href="http://tools.ietf.org/html/rfc5922#section-7.2">RFC5922 Section
+ * 7.2</a>
+ */
+ public final static String PNAME_STRICT_RFC5922 =
+ "net.java.sip.communicator.sip.tls.STRICT_RFC5922";
+
+ private ProtocolProviderServiceSipImpl provider;
+
+ /**
+ * Creates a new instance of this class.
+ * @param provider The SIP Provider to which this matcher belongs.
+ */
+ public RFC5922Matcher(ProtocolProviderServiceSipImpl provider)
+ {
+ this.provider = provider;
+ }
+
+ /** Our class logger. */
+ private static final Logger logger = Logger
+ .getLogger(CertificateMatcher.class);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.java.sip.communicator.service.certificate.CertificateMatcher#verify
+ * (java.lang.Iterable, java.security.cert.X509Certificate)
+ */
+ public void verify(Iterable<String> identitiesToTest, X509Certificate cert)
+ throws CertificateException
+ {
+ boolean strict = SipActivator.getConfigurationService()
+ .getBoolean(PNAME_STRICT_RFC5922, false);
+
+ // if any of the identities is contained in the certificate we're good
+ boolean oneMatched = false;
+ Iterable<String> certIdentities = extractCertIdentities(cert);
+ for (String identity : identitiesToTest)
+ {
+ // check if the intended hostname is contained in one of the
+ // hostnames of the certificate according to
+ // http://tools.ietf.org/html/rfc5922#section-7.2
+ for(String dnsName : certIdentities)
+ {
+ try
+ {
+ if(NetworkUtils.compareDnsNames(dnsName, identity) == 0)
+ {
+ // one of the hostnames matched, we're good to go
+ return;
+ }
+
+ if(!strict
+ // is a wildcard name
+ && dnsName.startsWith("*.")
+ // contains at least two dots (*.example.com)
+ && identity.indexOf(".") < identity.lastIndexOf(".")
+ // compare *.example.com stripped to example.com with
+ // - foo.example.com stripped to example.com
+ // - foo.bar.example.com to bar.example.com
+ && NetworkUtils.compareDnsNames(
+ dnsName.substring(2),
+ identity.substring(identity.indexOf(".")+1)) == 0)
+ {
+ // the wildcard matched, we're good to go
+ return;
+ }
+ }
+ catch (ParseException e)
+ {} // we don't care - this hostname did not match
+ }
+ }
+ if (!oneMatched)
+ throw new CertificateException("None of <" + identitiesToTest
+ + "> matched by the rules of RFC5922 to the cert with CN="
+ + cert.getSubjectDN());
+ }
+
+ private Iterable<String> extractCertIdentities(X509Certificate cert)
+ {
+ List<String> certIdentities = new ArrayList<String>();
+ Collection<List<?>> subjAltNames = null;
+ try
+ {
+ subjAltNames = cert.getSubjectAlternativeNames();
+ }
+ catch (CertificateParsingException ex)
+ {
+ logger.error("Error parsing TLS certificate", ex);
+ }
+ // subjAltName types are defined in rfc2459
+ final Integer dnsNameType = 2;
+ final Integer uriNameType = 6;
+ if (subjAltNames != null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("found subjAltNames: " + subjAltNames);
+
+ // First look for a URI in the subjectAltName field
+ for (List<?> altName : subjAltNames)
+ {
+ // 0th position is the alt name type
+ // 1st position is the alt name data
+ if (altName.get(0).equals(uriNameType))
+ {
+ SipURI altNameUri;
+ try
+ {
+ altNameUri =
+ provider.getAddressFactory().createSipURI(
+ (String) altName.get(1));
+ // only sip URIs are allowed
+ if (!"sip".equals(altNameUri.getScheme()))
+ continue;
+ // user certificates are not allowed
+ if (altNameUri.getUser() != null)
+ continue;
+ String altHostName = altNameUri.getHost();
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("found uri " + altName.get(1)
+ + ", hostName " + altHostName);
+ }
+ certIdentities.add(altHostName);
+ }
+ catch (ParseException e)
+ {
+ logger.error("certificate contains invalid uri: "
+ + altName.get(1));
+ }
+ }
+
+ }
+ // DNS An implementation MUST accept a domain name system
+ // identifier as a SIP domain identity if and only if no other
+ // identity is found that matches the "sip" URI type described
+ // above.
+ if (certIdentities.isEmpty())
+ {
+ for (List<?> altName : subjAltNames)
+ {
+ if (altName.get(0).equals(dnsNameType))
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("found dns " + altName.get(1));
+ certIdentities.add(altName.get(1).toString());
+ }
+ }
+ }
+ }
+ else
+ {
+ // If and only if the subjectAltName does not appear in the
+ // certificate, the implementation MAY examine the CN field of the
+ // certificate. If a valid DNS name is found there, the
+ // implementation MAY accept this value as a SIP domain identity.
+ String dname = cert.getSubjectDN().getName();
+ String cname = "";
+ try
+ {
+ Pattern EXTRACT_CN =
+ Pattern.compile(".*CN\\s*=\\s*([\\w*\\.]+).*");
+ Matcher matcher = EXTRACT_CN.matcher(dname);
+ if (matcher.matches())
+ {
+ cname = matcher.group(1);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("found CN: " + cname + " from DN: "
+ + dname);
+ }
+ certIdentities.add(cname);
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.error("exception while extracting CN", ex);
+ }
+ }
+ return certIdentities;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/net/SslNetworkLayer.java b/src/net/java/sip/communicator/impl/protocol/sip/net/SslNetworkLayer.java
index f1c5856..9d088a2 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/net/SslNetworkLayer.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/net/SslNetworkLayer.java
@@ -18,6 +18,7 @@
package net.java.sip.communicator.impl.protocol.sip.net;
import gov.nist.core.net.*;
+import gov.nist.javax.sip.*;
import java.io.*;
import java.net.*;
@@ -421,4 +422,9 @@ public class SslNetworkLayer
return 0;
}
+
+ @Override
+ public void setSipStack(SipStackImpl sipStack)
+ {
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java b/src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java
index c51a96c..e30b12d 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/sdp/SdpUtils.java
@@ -36,6 +36,7 @@ import org.jitsi.service.neomedia.*;
import org.jitsi.service.neomedia.MediaType;
import org.jitsi.service.neomedia.format.*;
import org.jitsi.util.*;
+import org.opentelecoms.javax.sdp.*;
/**
* The class contains a number of utility methods that are meant to facilitate
@@ -64,7 +65,7 @@ public class SdpUtils
/**
* A reference to the currently valid SDP factory instance.
*/
- private static final SdpFactory sdpFactory = SdpFactory.getInstance();
+ private static final SdpFactory sdpFactory = new NistSdpFactory();
/**
* The name of the SDP attribute that defines zrtp hello hash.
@@ -455,8 +456,21 @@ public class SdpUtils
while (iter.hasNext())
{
Map.Entry<String, String> ntry = iter.next();
- Attribute adv = sdpFactory.createAttribute(ntry.getKey(),
- payloadType + " " + ntry.getValue());
+ Attribute adv;
+ switch (ntry.getKey())
+ {
+ // RFC7587, Sect. 7 says there's no payload number for ptime
+ case "ptime":
+ case "maxptime":
+ adv = sdpFactory.createAttribute(ntry.getKey(),
+ ntry.getValue());
+ break;
+ default:
+ adv = sdpFactory.createAttribute(ntry.getKey(),
+ payloadType + " " + ntry.getValue());
+ break;
+ }
+
mediaAttributes.add(adv);
}
@@ -567,7 +581,7 @@ public class SdpUtils
public static SessionDescription createSessionDescription(
InetAddress localAddress,
String userName,
- Vector<MediaDescription> mediaDescriptions)
+ List<MediaDescription> mediaDescriptions)
throws OperationFailedException
{
SessionDescription sessDescr = null;
@@ -613,8 +627,9 @@ public class SdpUtils
sessDescr.setConnection(c);
if ( mediaDescriptions != null)
- sessDescr.setMediaDescriptions(mediaDescriptions);
-
+ {
+ sessDescr.setMediaDescriptions( new Vector<>(mediaDescriptions));
+ }
return sessDescr;
}
catch (SdpException exc)
@@ -655,7 +670,7 @@ public class SdpUtils
public static SessionDescription createSessionUpdateDescription(
SessionDescription descToUpdate,
InetAddress newConnectionAddress,
- Vector<MediaDescription> newMediaDescriptions)
+ List<MediaDescription> newMediaDescriptions)
throws OperationFailedException
{
SessionDescription update = createSessionDescription(
@@ -1711,7 +1726,7 @@ public class SdpUtils
* <tt>descs</tt> <tt>Vector</tt>.
*/
private static MediaDescription removeMediaDesc(
- Vector<MediaDescription> descs,
+ List<MediaDescription> descs,
MediaType type)
{
for (Iterator<MediaDescription> i = descs.iterator(); i.hasNext();)
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
index c15c025..2015a17 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
@@ -5,9 +5,22 @@ Bundle-Vendor: jitsi.org
Bundle-Version: 0.0.1
Bundle-SymbolicName: net.java.sip.communicator.protocol.sip
Import-Package: ch.imvs.sdes4j.srtp,
+ gov.nist.core,
+ gov.nist.core.net,
+ gov.nist.javax.sip,
+ gov.nist.javax.sip.address,
+ gov.nist.javax.sip.header,
+ gov.nist.javax.sip.header.extensions,
+ gov.nist.javax.sip.message,
+ gov.nist.javax.sip.stack,
javax.net,
javax.net.ssl,
javax.security.auth.x500,
+ javax.sdp,
+ javax.sip,
+ javax.sip.address,
+ javax.sip.header,
+ javax.sip.message,
javax.xml.datatype,
javax.xml.namespace,
javax.xml.parsers,
@@ -76,6 +89,7 @@ Import-Package: ch.imvs.sdes4j.srtp,
org.jitsi.util.xml,
org.json.simple,
org.osgi.framework,
+ org.opentelecoms.javax.sdp,
org.w3c.dom,
org.xml.sax
Export-Package: net.java.sip.communicator.impl.protocol.sip,
@@ -88,6 +102,4 @@ Export-Package: net.java.sip.communicator.impl.protocol.sip,
net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists,
net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps,
net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror,
- net.java.sip.communicator.impl.protocol.sip.xcap.utils,
- javax.sdp,
- gov.nist.javax.sdp.fields
+ net.java.sip.communicator.impl.protocol.sip.xcap.utils
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ContactGroupSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/ContactGroupSSHImpl.java
deleted file mode 100644
index 7de2e16..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ContactGroupSSHImpl.java
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * A simple, straightforward implementation of a ssh ContactGroup. Since
- * the SSH protocol is not a real one, we simply store all group details
- * in class fields. You should know that when implementing a real protocol,
- * the contact group implementation would rather encapsulate group objects from
- * the protocol stack and group property values should be returned by
- * consulting the encapsulated object.
- *
- * @author Shobhit Jindal
- */
-public class ContactGroupSSHImpl
- implements ContactGroup
-{
-
- /**
- * The name of this SSH contact group.
- */
- private String groupName = null;
-
- /**
- * The list of this group's members.
- */
- private Vector<Contact> contacts = new Vector<Contact>();
-
- /**
- * The list of sub groups belonging to this group.
- */
- private Vector<ContactGroup> subGroups = new Vector<ContactGroup>();
-
- /**
- * The group that this group belongs to (or null if this is the root group).
- */
- private ContactGroupSSHImpl parentGroup = null;
-
- /**
- * Determines whether this group is really in the contact list or whether
- * it is here only temporarily and will be gone next time we restart.
- */
- private boolean isPersistent = true;
-
- /**
- * The protocol provider that created us.
- */
- private ProtocolProviderServiceSSHImpl parentProvider = null;
-
- /**
- * Determines whether this group has been resolved on the server.
- * Unresolved groups are groups that were available on previous runs and
- * that the meta contact list has stored. During all next runs, when
- * bootstrapping, the meta contact list would create these groups as
- * unresolved. Once a protocol provider implementation confirms that the
- * groups are still on the server, it would issue an event indicating that
- * the groups are now resolved.
- */
- private boolean isResolved = true;
-
- /**
- * An id uniquely identifying the group. For many protocols this could be
- * the group name itself.
- */
- private String uid = null;
- private static final String UID_SUFFIX = ".uid";
-
- /**
- * Creates a ContactGroupSSHImpl with the specified name.
- *
- * @param groupName the name of the group.
- * @param parentProvider the protocol provider that created this group.
- */
- public ContactGroupSSHImpl(
- String groupName,
- ProtocolProviderServiceSSHImpl parentProvider)
- {
- this.groupName = groupName;
- this.uid = groupName + UID_SUFFIX;
- this.parentProvider = parentProvider;
- }
-
- /**
- * Determines whether the group may contain subgroups or not.
- *
- * @return always true in this implementation.
- */
- public boolean canContainSubgroups()
- {
- return true;
- }
-
- /**
- * Returns the protocol provider that this group belongs to.
- * @return a regerence to the ProtocolProviderService instance that this
- * ContactGroup belongs to.
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return parentProvider;
- }
-
- /**
- * Returns an Iterator over all contacts, member of this
- * <tt>ContactGroup</tt>.
- *
- * @return a java.util.Iterator over all contacts inside this
- * <tt>ContactGroup</tt>
- */
- public Iterator<Contact> contacts()
- {
- return contacts.iterator();
- }
-
- /**
- * Adds the specified contact to this group.
- * @param contactToAdd the ContactSSHImpl to add to this group.
- */
- public void addContact(ContactSSH contactToAdd)
- {
- this.contacts.add(contactToAdd);
- contactToAdd.setParentGroup(this);
- }
-
- /**
- * Returns the number of <tt>Contact</tt> members of this
- * <tt>ContactGroup</tt>
- *
- * @return an int indicating the number of <tt>Contact</tt>s, members of
- * this <tt>ContactGroup</tt>.
- */
- public int countContacts()
- {
- return contacts.size();
- }
-
- /**
- * Returns the number of subgroups contained by this
- * <tt>ContactGroup</tt>.
- *
- * @return the number of subGroups currently added to this group.
- */
- public int countSubgroups()
- {
- return subGroups.size();
- }
-
- /**
- * Adds the specified contact group to the contained by this group.
- * @param subgroup the ContactGroupSSHImpl to add as a subgroup to this
- * group.
- */
- public void addSubgroup(ContactGroupSSHImpl subgroup)
- {
- this.subGroups.add(subgroup);
- subgroup.setParentGroup(this);
- }
-
- /**
- * Sets the group that is the new parent of this group
- * @param parent ContactGroupSSHImpl
- */
- void setParentGroup(ContactGroupSSHImpl parent)
- {
- this.parentGroup = parent;
- }
-
- /**
- * Returns the contact group that currently contains this group or null if
- * this is the root contact group.
- * @return the contact group that currently contains this group or null if
- * this is the root contact group.
- */
- public ContactGroup getParentContactGroup()
- {
- return this.parentGroup;
- }
-
- /**
- * Removes the specified contact group from the this group's subgroups.
- * @param subgroup the ContactGroupSSHImpl subgroup to remove.
- */
- public void removeSubGroup(ContactGroupSSHImpl subgroup)
- {
- this.subGroups.remove(subgroup);
- subgroup.setParentGroup(null);
- }
-
- /**
- * Returns the group that is parent of the specified sshGroup or null
- * if no parent was found.
- * @param sshGroup the group whose parent we're looking for.
- * @return the ContactGroupSSHImpl instance that sshGroup
- * belongs to or null if no parent was found.
- */
- public ContactGroupSSHImpl findGroupParent(
- ContactGroupSSHImpl sshGroup)
- {
- if ( subGroups.contains(sshGroup) )
- return this;
-
- Iterator<ContactGroup> subGroupsIter = subgroups();
- while (subGroupsIter.hasNext())
- {
- ContactGroupSSHImpl subgroup
- = (ContactGroupSSHImpl) subGroupsIter.next();
-
- ContactGroupSSHImpl parent
- = subgroup.findGroupParent(sshGroup);
-
- if(parent != null)
- return parent;
- }
- return null;
- }
-
- /**
- * Returns the group that is parent of the specified sshContact or
- * null if no parent was found.
- *
- * @param sshContact the contact whose parent we're looking for.
- * @return the ContactGroupSSHImpl instance that sshContact
- * belongs to or <tt>null</tt> if no parent was found.
- */
- public ContactGroupSSHImpl findContactParent(
- ContactSSHImpl sshContact)
- {
- if ( contacts.contains(sshContact) )
- return this;
-
- Iterator<ContactGroup> subGroupsIter = subgroups();
- while (subGroupsIter.hasNext())
- {
- ContactGroupSSHImpl subgroup
- = (ContactGroupSSHImpl) subGroupsIter.next();
-
- ContactGroupSSHImpl parent
- = subgroup.findContactParent(sshContact);
-
- if(parent != null)
- return parent;
- }
- return null;
- }
-
-
-
- /**
- * Returns the <tt>Contact</tt> with the specified address or identifier.
- *
- * @param id the addres or identifier of the <tt>Contact</tt> we are
- * looking for.
- * @return the <tt>Contact</tt> with the specified id or address.
- */
- public Contact getContact(String id)
- {
- Iterator<Contact> contactsIter = contacts();
- while (contactsIter.hasNext())
- {
- ContactSSHImpl contact = (ContactSSHImpl) contactsIter.next();
- if (contact.getAddress().equals(id))
- return contact;
-
- }
- return null;
- }
-
- /**
- * Returns the subgroup with the specified index.
- *
- * @param index the index of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(int index)
- {
- return subGroups.get(index);
- }
-
- /**
- * Returns the subgroup with the specified name.
- *
- * @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(String groupName)
- {
- Iterator<ContactGroup> groupsIter = subgroups();
- while (groupsIter.hasNext())
- {
- ContactGroupSSHImpl contactGroup
- = (ContactGroupSSHImpl) groupsIter.next();
- if (contactGroup.getGroupName().equals(groupName))
- return contactGroup;
-
- }
- return null;
-
- }
-
- /**
- * Returns the name of this group.
- *
- * @return a String containing the name of this group.
- */
- public String getGroupName()
- {
- return this.groupName;
- }
-
- /**
- * Sets this group a new name.
- * @param newGrpName a String containing the new name of this group.
- */
- public void setGroupName(String newGrpName)
- {
- this.groupName = newGrpName;
- }
-
- /**
- * Returns an iterator over the sub groups that this
- * <tt>ContactGroup</tt> contains.
- *
- * @return a java.util.Iterator over the <tt>ContactGroup</tt> children
- * of this group (i.e. subgroups).
- */
- public Iterator<ContactGroup> subgroups()
- {
- return subGroups.iterator();
- }
-
- /**
- * Removes the specified contact from this group.
- * @param contact the ContactSSHImpl to remove from this group
- */
- public void removeContact(ContactSSHImpl contact)
- {
- this.contacts.remove(contact);
- }
-
- /**
- * Returns the contact with the specified id or null if no such contact
- * exists.
- * @param id the id of the contact we're looking for.
- * @return ContactSSHImpl
- */
- public ContactSSHImpl findContactByID(String id)
- {
- //first go through the contacts that are direct children.
- Iterator<Contact> contactsIter = contacts();
-
- while(contactsIter.hasNext())
- {
- ContactSSHImpl mContact = (ContactSSHImpl)contactsIter.next();
-
- if( mContact.getAddress().equals(id) )
- return mContact;
- }
-
- //if we didn't find it here, let's try in the subougroups
- Iterator<ContactGroup> groupsIter = subgroups();
-
- while( groupsIter.hasNext() )
- {
- ContactGroupSSHImpl mGroup = (ContactGroupSSHImpl)groupsIter.next();
-
- ContactSSHImpl mContact = mGroup.findContactByID(id);
-
- if (mContact != null)
- return mContact;
- }
-
- return null;
- }
-
- /**
- * Returns a String representation of this group and the contacts it
- * contains (may turn out to be a relatively long string).
- * @return a String representing this group and its child contacts.
- */
- @Override
- public String toString()
- {
- StringBuffer buff = new StringBuffer(getGroupName());
- buff.append(".subGroups=" + countSubgroups() + ":\n");
-
- Iterator<ContactGroup> subGroups = subgroups();
- while (subGroups.hasNext())
- {
- ContactGroup group = subGroups.next();
- buff.append(group.toString());
- if (subGroups.hasNext())
- buff.append("\n");
- }
-
- buff.append("\nChildContacts="+countContacts()+":[");
-
- Iterator<Contact> contacts = contacts();
- while (contacts.hasNext())
- {
- Contact contact = contacts.next();
- buff.append(contact.toString());
- if(contacts.hasNext())
- buff.append(", ");
- }
- return buff.append("]").toString();
- }
-
- /**
- * Specifies whether or not this contact group is being stored by the
- * server.
- * Non persistent contact groups are common in the case of simple,
- * non-persistent presence operation sets. They could however also be seen
- * in persistent presence operation sets when for example we have received
- * an event from someone not on our contact list and the contact that we
- * associated with that user is placed in a non persistent group. Non
- * persistent contact groups are volatile even when coming from a
- * persistent presence op. set. They would only exist until the
- * application is closed and will not be there next time it is loaded.
- *
- * @param isPersistent true if the contact group is to be persistent and
- * false otherwise.
- */
- public void setPersistent(boolean isPersistent)
- {
- this.isPersistent = isPersistent;
- }
-
- /**
- * Determines whether or not this contact group is being stored by the
- * server. Non persistent contact groups exist for the sole purpose of
- * containing non persistent contacts.
- * @return true if the contact group is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Returns null as no persistent data is required and the contact address is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Makes the group resolved or unresolved.
- *
- * @param resolved true to make the group resolved; false to
- * make it unresolved
- */
- public void setResolved(boolean resolved)
- {
- this.isResolved = resolved;
- }
-
- /**
- * Returns a <tt>String</tt> that uniquely represnets the group inside
- * the current protocol. The string MUST be persistent (it must not change
- * across connections or runs of the application). In many cases (Jabber,
- * ICQ) the string may match the name of the group as these protocols
- * only allow a single level of contact groups and there is no danger of
- * having the same name twice in the same contact list. Other protocols
- * (no examples come to mind but that doesn't bother me ;) ) may be
- * supporting mutilple levels of grooups so it might be possible for group
- * A and group B to both contain groups named C. In such cases the
- * implementation must find a way to return a unique identifier in this
- * method and this UID should never change for a given group.
- *
- * @return a String representing this group in a unique and persistent
- * way.
- */
- public String getUID()
- {
- return uid;
- }
-
- /**
- * Ugly but tricky conversion method.
- * @param uid the uid we'd like to get a name from
- * @return the name of the group with the specified <tt>uid</tt>.
- */
- static String createNameFromUID(String uid)
- {
- return uid.substring(0, uid.length() - (UID_SUFFIX.length()));
- }
-
- /**
- * Indicates whether some other object is "equal to" this one which in terms
- * of contact groups translates to having the equal names and matching
- * subgroups and child contacts. The resolved status of contactgroups and
- * contacts is deliberately ignored so that groups and/or contacts would
- * be assumed equal even if it differs.
- * <p>
- * @param obj the reference object with which to compare.
- * @return <code>true</code> if this contact group has the equal child
- * contacts and subgroups to those of the <code>obj</code> argument.
- */
- @Override
- public boolean equals(Object obj)
- {
- if(obj == null
- || !(obj instanceof ContactGroupSSHImpl))
- return false;
-
- ContactGroupSSHImpl sshGroup
- = (ContactGroupSSHImpl)obj;
-
- if( ! sshGroup.getGroupName().equals(getGroupName())
- || ! sshGroup.getUID().equals(getUID())
- || sshGroup.countContacts() != countContacts()
- || sshGroup.countSubgroups() != countSubgroups())
- return false;
-
- //traverse child contacts
- Iterator<Contact> theirContacts = sshGroup.contacts();
-
- while(theirContacts.hasNext())
- {
- Contact theirContact = theirContacts.next();
- Contact ourContact = getContact(theirContact.getAddress());
-
- if(ourContact == null
- || !ourContact.equals(theirContact))
- return false;
- }
-
- //traverse subgroups
- Iterator<ContactGroup> theirSubgroups = sshGroup.subgroups();
-
- while(theirSubgroups.hasNext())
- {
- ContactGroup theirSubgroup = theirSubgroups.next();
- ContactGroup ourSubgroup = getGroup(theirSubgroup.getGroupName());
-
- if(ourSubgroup == null
- || !ourSubgroup.equals(theirSubgroup))
- return false;
- }
-
- return true;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ContactSSH.java b/src/net/java/sip/communicator/impl/protocol/ssh/ContactSSH.java
deleted file mode 100644
index a13414b..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ContactSSH.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-import com.jcraft.jsch.*;
-
-/**
- * This interface represents a Contact of SSH Type
- * As a SSH Session is specific to a contact, additional information needed
- * to maintain its state with the remote server is present here
- *
- * @author Shobhit Jindal
- */
-interface ContactSSH
- extends Contact
-{
- /**
- * An event type indicating that the message being received is a standard
- * conversation message sent by another contact.
- */
- public static final int CONVERSATION_MESSAGE_RECEIVED = 1;
-
- /**
- * An event type indicting that the message being received is a system
- * message being sent by the server or a system administrator.
- */
- public static final int SYSTEM_MESSAGE_RECEIVED = 2;
-
- //Following eight function declations to be moved to Contact
-
- /**
- * This method is only called when the contact is added to a new
- * <tt>ContactGroupSSHImpl</tt> by the
- * <tt>ContactGroupSSHImpl</tt> itself.
- *
- * @param newParentGroup the <tt>ContactGroupSSHImpl</tt> that is now
- * parent of this <tt>ContactSSHImpl</tt>
- */
- void setParentGroup (ContactGroupSSHImpl newParentGroup);
-
- /**
- * Sets <tt>sshPresenceStatus</tt> as the PresenceStatus that this
- * contact is currently in.
- * @param sshPresenceStatus the <tt>SSHPresenceStatus</tt>
- * currently valid for this contact.
- */
- public void setPresenceStatus (PresenceStatus sshPresenceStatus);
-
- /**
- * Returns the persistent presence operation set that this contact belongs
- * to.
- *
- * @return the <tt>OperationSetPersistentPresenceSSHImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetPersistentPresence
- getParentPresenceOperationSet ();
-
- /**
- * Returns the BasicInstant Messaging operation set that this contact
- * belongs to.
- *
- * @return the <tt>OperationSetBasicInstantMessagingSSHImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetBasicInstantMessaging
- getParentBasicInstantMessagingOperationSet ();
-
- /**
- * Returns the File Transfer operation set that this contact belongs
- * to.
- *
- * @return the <tt>OperationSetFileTransferSSHImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetFileTransfer
- getFileTransferOperationSet ();
-
- /**
- * Return the type of message received from remote server
- *
- * @return messageType
- */
- public int getMessageType ();
-
- /**
- * Sets the type of message received from remote server
- *
- * @param messageType
- */
- public void setMessageType (int messageType);
-
- /**
- * Stores persistent data of the contact.
- *
- * @param persistentData of the contact
- */
- public void setPersistentData (String persistentData);
-
- /**
- * Makes the contact resolved or unresolved.
- *
- * @param resolved true to make the contact resolved; false to
- * make it unresolved
- */
- public void setResolved (boolean resolved);
-
- /**
- * Specifies whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @param isPersistent true if the contact is persistent and false
- * otherwise.
- */
- public void setPersistent (boolean isPersistent);
-
- /**
- * Returns true if a command has been sent whos reply was not received yet
- * false otherwise
- *
- * @return commandSent
- */
- public boolean isCommandSent ();
-
- /**
- * Set the state of commandSent variable which determines whether a reply
- * to a command sent is awaited
- *
- * @param commandSent
- */
- public void setCommandSent (boolean commandSent);
-
- /**
- * Initializes the reader and writers associated with shell of this contact
- *
- * @param shellInputStream The InputStream of stack
- * @param shellOutputStream The OutputStream of stack
- */
- void initializeShellIO (InputStream shellInputStream,
- OutputStream shellOutputStream);
-
- /**
- * Closes the readers and writer associated with shell of this contact
- */
- void closeShellIO ();
-
- /**
- * Determines whether a connection to a remote server is already underway
- *
- * @return connectionInProgress
- */
- public boolean isConnectionInProgress ();
-
- /**
- * Sets the status of connection attempt to remote server
- *
- * @param connectionInProgress
- */
- public void setConnectionInProgress (boolean connectionInProgress);
-
-// /**
-// * Sets the PS1 prompt of the current shell of Contact
-// * This method is synchronized
-// *
-// * @param sshPrompt to be associated
-// */
-// public void setShellPrompt(String sshPrompt);
-//
-// /**
-// * Returns the PS1 prompt of the current shell of Contact
-// *
-// * @return sshPrompt
-// */
-// public String getShellPrompt();
-
-
- /**
- * Saves the details of contact in persistentData
- */
- public void savePersistentDetails ();
-
- /*
- * Returns the SSHContactInfo associated with this contact
- *
- * @return sshConfigurationForm
- */
- public SSHContactInfo getSSHConfigurationForm ();
-
- /**
- * Returns the JSch Stack identified associated with this contact
- *
- * @return jsch
- */
- JSch getJSch ();
-
- /**
- * Starts the timer and its task to periodically update the status of
- * remote machine
- */
- void startTimerTask ();
-
- /**
- * Stops the timer and its task to stop updating the status of
- * remote machine
- */
- void stopTimerTask ();
-
- /**
- * Sets the JSch Stack identified associated with this contact
- *
- * @param jsch to be associated
- */
- void setJSch (JSch jsch);
-
- /**
- * Returns the Username associated with this contact
- *
- * @return userName
- */
- String getUserName ();
-
- /**
- * Returns the Hostname associated with this contact
- *
- * @return hostName
- */
- String getHostName ();
-
- /**
- * Returns the Password associated with this contact
- *
- * @return password
- */
- String getPassword ();
-
- /**
- * Sets the Password associated with this contact
- *
- * @param password
- */
- void setPassword (String password);
-
- /**
- * Returns the SSH Session associated with this contact
- *
- * @return sshSession
- */
- Session getSSHSession ();
-
- /**
- * Sets the SSH Session associated with this contact
- *
- * @param sshSession the newly created SSH Session to be associated
- */
- void setSSHSession (Session sshSession);
-
- /**
- * Returns the SSH Shell Channel associated with this contact
- *
- * @return shellChannel
- */
- Channel getShellChannel ();
-
- /**
- * Sets the SSH Shell channel associated with this contact
- *
- * @param shellChannel to be associated with SSH Session of this contact
- */
- void setShellChannel (Channel shellChannel);
-
- /**
- * Sends a message a line to remote machine via the Shell Writer
- *
- * @param message to be sent
- * @throws IOException if message failed to be sent
- */
- public void sendLine (String message)
- throws IOException;
-
-// /**
-// * Reads a line from the remote machine via the Shell Reader
-// *
-// * @return message read
-// */
-// public String getLine()
-// throws IOException;
-
- /**
- * Returns the Input Stream associated with SSH Channel of this contact
- *
- * @return shellInputStream associated with SSH Channel of this contact
- */
- public InputStream getShellInputStream ();
-
-// /**
-// * Sets the Input Stream associated with SSH Channel of this contact
-// *
-// * @param shellInputStream to be associated with SSH Channel of this
-// * contact
-// */
-// public void setShellInputStream(InputStream shellInputStream);
-
- /**
- * Returns the Output Stream associated with SSH Channel of this contact
- *
- * @return shellOutputStream associated with SSH Channel of this contact
- */
- public OutputStream getShellOutputStream ();
-
-// /**
-// * Sets the Output Stream associated with SSH Channel of this contact
-// *
-// * @param shellOutputStream to be associated with SSH Channel of this
-// * contact
-// */
-// public void setShellOutputStream(OutputStream shellOutputStream);
-//
- /**
- * Returns the BufferedReader associated with SSH Channel of this contact
- *
- * @return shellReader associated with SSH Channel of this contact
- */
- public InputStreamReader getShellReader ();
-//
-// /**
-// * Sets the BufferedReader associated with SSH Channel of this contact
-// *
-// * @param shellReader to be associated with SSH Channel of this contact
-// */
-// public void setShellReader(BufferedReader shellReader);
-
- /**
- * Returns the PrintWriter associated with SSH Channel of this contact
- *
- * @return shellWriter associated with SSH Channel of this contact
- */
- public PrintWriter getShellWriter ();
-
-// /**
-// * Sets the PrintWriter associated with SSH Channel of this contact
-// *
-// * @param shellWriter to be associated with SSH Channel of this contact
-// */
-// public void setShellWriter(PrintWriter shellWriter);
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ContactSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/ContactSSHImpl.java
deleted file mode 100644
index 15da209..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ContactSSHImpl.java
+++ /dev/null
@@ -1,918 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.Base64; // disambiguation
-import net.java.sip.communicator.util.Logger;
-
-import com.jcraft.jsch.*;
-// disambiguation
-
-/**
- * A Contact of SSH Type
- *
- * @author Shobhit Jindal
- */
-public class ContactSSHImpl
- extends AbstractContact
- implements ContactSSH
-{
- private static final Logger logger
- = Logger.getLogger(ContactSSHImpl.class);
-
- /**
- * This acts as a separator between details stored in persistent data
- */
- private final String separator =
- Resources.getString("impl.protocol.ssh.DETAILS_SEPARATOR");
-
- /**
- * The identifier for SSH Stack
- * Java Secure Channel JSch
- */
- private JSch jsch;
-
- /**
- * Interface for user to provide details about machine
- */
- private SSHContactInfo sshConfigurationForm;
-
- /**
- * A Timer Daemon to update the status of this contact
- */
- private Timer timer = new Timer(true);
-
- /**
- * A Daemon to retrieve and fire messages received from remote machine
- */
- private SSHReaderDaemon contactSSHReaderDaemon;
-
- /**
- * The id of the contact.
- */
- private String contactID = null;
-
- /**
- * The persistentData of the contact.
- */
- private String persistentData = null;
-
-// /**
-// * This stores the prompt string of shell
-// */
-// private String sshPrompt;
-
- /**
- * The provider that created us.
- */
- private ProtocolProviderServiceSSHImpl parentProvider = null;
-
- /**
- * The identifier of the type of message received from server
- */
- private int messageType;
-
-
-
- /**
- * The identifier for SSH Session with the remote server
- */
- private Session sshSession = null;
-
- /**
- * The identifier for a sshShellChannel with the remote server is of type
- * shell - for an interactive SSH Session with the remote machine
- *
- * Other types
- * sftp - to tranfer files from/to the remote machine
- * exec - X forwarding
- * direct-tcpip - stream forwarding
- */
- private Channel sshShellChannel = null;
-
- /**
- * The identifier for the Shell Input Stream associated with SSH Sesion
- */
- private InputStream shellInputStream = null;
-
- /**
- * The identifier for the Shell Output Stream associated with SSH Sesion
- */
- private OutputStream shellOutputStream = null;
-
- /**
- * Higher wrapper for shellInputStream
- */
- private InputStreamReader shellReader = null;
-
- /**
- * Higher wrapper for shellOutputStream
- */
- private PrintWriter shellWriter = null;
-
- /**
- * The group that belong to.
- */
- private ContactGroupSSHImpl parentGroup = null;
-
- /**
- * The presence status of the contact.
- */
- private PresenceStatus presenceStatus = SSHStatusEnum.NOT_AVAILABLE;
-
- /**
- * Determines whether this contact is persistent, i.e. member of the contact
- * list or whether it is here only temporarily.
- */
- private boolean isPersistent = false;
-
- /**
- * Determines whether the contact has been resolved (i.e. we have a
- * confirmation that it is still on the server contact list).
- */
- private boolean isResolved = true;
-
- /**
- * Determines whether an connection attempt to remote server is already
- * underway
- */
- private boolean isConnectionInProgress = false;
-
- /**
- * Determines whether the message received from remote machine is as a
- * result of command sent to it
- */
- private boolean commandSent = false;
-
- /**
- * A lock to synchronize the access of commandSent boolean object
- * with the reader thread.
- */
- private final Object lock = new Object();
-
- /**
- * Creates an instance of a meta contact with the specified string used
- * as a name and identifier.
- *
- * @param id the identifier of this contact (also used as a name).
- * @param parentProvider the provider that created us.
- */
- public ContactSSHImpl(
- String id,
- ProtocolProviderServiceSSHImpl parentProvider)
- {
- this.contactID = id;
- this.parentProvider = parentProvider;
-
- this.sshConfigurationForm =
- new SSHContactInfo(this);
-
- this.savePersistentDetails();
- }
-
- /**
- * Initializes the reader and writers associated with shell of this contact
- *
- * @param shellInputStream The InputStream of stack
- * @param shellOutputStream The OutputStream of stack
- */
- public void initializeShellIO(
- InputStream shellInputStream,
- OutputStream shellOutputStream)
- {
- this.shellInputStream = shellInputStream;
- this.shellOutputStream = shellOutputStream;
- shellReader = new InputStreamReader(shellInputStream);
- shellWriter = new PrintWriter(shellOutputStream);
-
- contactSSHReaderDaemon = new SSHReaderDaemon(this);
- contactSSHReaderDaemon.setDaemon(true);
- contactSSHReaderDaemon.isActive(true);
- contactSSHReaderDaemon.start();
- }
-
- /**
- * Closes the readers and writer associated with shell of this contact
- */
- public void closeShellIO()
- {
- try
- {
- shellReader.close();
- shellInputStream.close();
- }
- catch(IOException ex)
- {}
-
- try
- {
- shellWriter.close();
- shellOutputStream.close();
- }
- catch(IOException ex)
- {}
-
- shellInputStream = null;
-
- shellReader = null;
-
- shellOutputStream = null;
-
- shellWriter = null;
-
- try
- {
- sshShellChannel.disconnect();
- }
- catch(Exception e)
- {}
-
- // Removing the reference to current channel
- // a new shell channel will be created for the next message
- sshShellChannel = null;
-
- // remove the reference of session if it were also disconnected
- // like in the case of exit command
- if(!sshSession.isConnected())
- {
- sshSession = null;
- jsch = null;
- }
-
- ((OperationSetPersistentPresenceSSHImpl)
- getParentPresenceOperationSet()).
- changeContactPresenceStatus(this, SSHStatusEnum.ONLINE);
- }
-
- /**
- * Sends a message a line to remote machine via the Shell Writer
- *
- * @param message to be sent
- */
- public void sendLine(String message)
- throws IOException
- {
-// logger.debug("SSH TO: " + this.contactID + ": " + message);
- shellWriter.println(message);
- shellWriter.flush();
- }
-
- /**
- * Reads a line from the remote machine via the Shell Reader
- *
- * @return message read
- */
-// public String getLine()
-// throws IOException
-// {
-// String line = shellReader.readLine();
-//// logger.debug("SSH FROM: " + this.contactID + ": " + line);
-//
-// // null is never returned normally, the reading attempt returs a
-// // string
-// // or blocks until one line is available
-// if(line == null)
-// {
-// sshShellChannel.disconnect();
-// sshShellChannel = null;
-// sshSession = null;
-// throw(new IOException("Unexpected Reply from remote Server"));
-// }
-// return line;
-// }
-
- /**
- * Starts the timer and its task to periodically update the status of
- * remote machine
- */
- public void startTimerTask()
- {
- timer.scheduleAtFixedRate(new ContactTimerSSHImpl(this),
- 2000, sshConfigurationForm.getUpdateInterval()*1000);
- }
-
- /**
- * Stops the timer and its task to stop updating the status of
- * remote machine
- */
- public void stopTimerTask()
- {
- timer.cancel();
- }
-
-
- /**
- * Saves the details of contact in persistentData seperated by
- * separator
- * Passowrd is saved unsecurely using Base64 encoding
- */
- public void savePersistentDetails()
- {
- persistentData =
- this.sshConfigurationForm.getHostName() +
- separator +
- this.sshConfigurationForm.getUserName() +
- separator +
- new String(Base64.encode(this.sshConfigurationForm.getPassword()
- .getBytes())) +
- separator + sshConfigurationForm.getPort() +
- separator +
- sshConfigurationForm.getTerminalType() +
- separator +
- sshConfigurationForm.getUpdateInterval();
- }
-
- /**
- * Stores persistent data in fields of the contact seperated by
- * separator.
- *
- * @param persistentData of the contact
- */
- public void setPersistentData(String persistentData)
- {
- try
- {
- this.persistentData = persistentData;
- int firstCommaIndex = this.persistentData.indexOf(separator);
- int secondCommaIndex = this.persistentData.indexOf(separator,
- firstCommaIndex +1);
- int thirdCommaIndex = this.persistentData.indexOf(separator,
- secondCommaIndex +1);
- int fourthCommaIndex = this.persistentData.indexOf(separator,
- thirdCommaIndex +1);
- int fifthCommaIndex = this.persistentData.indexOf(separator,
- fourthCommaIndex +1);
-
- if (logger.isDebugEnabled())
- logger.debug("Commas: " + firstCommaIndex + " " + secondCommaIndex + " "
- + thirdCommaIndex + " " +fourthCommaIndex + " "
- +fifthCommaIndex);
-
- this.sshConfigurationForm.setHostNameField(
- this.persistentData.substring(0,firstCommaIndex));
-
- this.sshConfigurationForm.setUserNameField(
- this.persistentData.substring(firstCommaIndex+1,
- secondCommaIndex));
-
- if( (thirdCommaIndex - secondCommaIndex) > 1)
- {
- if(this.persistentData.substring(secondCommaIndex+1).length()>0)
- this.sshConfigurationForm.setPasswordField(
- new String(Base64.decode(this.persistentData
- .substring(secondCommaIndex+1, thirdCommaIndex))));
- }
-
-
- this.sshConfigurationForm.setPort(
- this.persistentData.substring(thirdCommaIndex + 1,
- fourthCommaIndex));
-
- this.sshConfigurationForm.setTerminalType(
- this.persistentData.substring(fourthCommaIndex + 1,
- fifthCommaIndex));
-
- this.sshConfigurationForm.setUpdateInterval(
- Integer.parseInt(this.persistentData.substring(fifthCommaIndex+1)));
- }
- catch(Exception ex)
- {
- logger.error("Error setting persistent data!", ex);
- }
- }
-
- /**
- * Determines whether a connection to a remote server is already underway
- *
- * @return isConnectionInProgress
- */
- public boolean isConnectionInProgress()
- {
- return this.isConnectionInProgress;
- }
-
- /**
- * Sets the status of connection attempt to remote server
- * This method is synchronized
- *
- * @param isConnectionInProgress
- */
- public synchronized void setConnectionInProgress(
- boolean isConnectionInProgress)
- {
- this.isConnectionInProgress = isConnectionInProgress;
- }
-
- /**
- * Returns the SSHContactInfo associated with this contact
- *
- * @return sshConfigurationForm
- */
- public SSHContactInfo getSSHConfigurationForm()
- {
- return this.sshConfigurationForm;
- }
-
- /**
- * Returns the JSch Stack identified associated with this contact
- *
- * @return jsch
- */
- public JSch getJSch()
- {
- return this.jsch;
- }
-
- /**
- * Sets the JSch Stack identified associated with this contact
- *
- * @param jsch to be associated
- */
- public void setJSch(JSch jsch)
- {
- this.jsch = jsch;
- }
-
- /**
- * This method is only called when the contact is added to a new
- * <tt>ContactGroupSSHImpl</tt> by the
- * <tt>ContactGroupSSHImpl</tt> itself.
- *
- * @param newParentGroup the <tt>ContactGroupSSHImpl</tt> that is now
- * parent of this <tt>ContactSSHImpl</tt>
- */
- public void setParentGroup(ContactGroupSSHImpl newParentGroup)
- {
- this.parentGroup = newParentGroup;
- }
-
- /**
- * Returns the Hostname associated with this contact
- *
- * @return hostName
- */
- public String getHostName()
- {
- return sshConfigurationForm.getHostName();
- }
-
- /**
- * Returns a String that can be used for identifying the contact.
- *
- * @return a String id representing and uniquely identifying the contact.
- */
- public String getAddress()
- {
- return contactID;
- }
-
- /**
- * Returns a String that could be used by any user interacting modules
- * for referring to this contact.
- *
- * @return a String that can be used for referring to this contact when
- * interacting with the user.
- */
- public String getDisplayName()
- {
- return contactID;
- }
-
- /**
- * Returns a byte array containing an image (most often a photo or an
- * avatar) that the contact uses as a representation.
- *
- * @return byte[] an image representing the contact.
- */
- public byte[] getImage()
- {
- return null;
- }
-
- /**
- * Returns true if a command has been sent whos reply was not received yet
- * false otherwise
- *
- * @return commandSent
- */
- public boolean isCommandSent()
- {
- return this.commandSent;
- }
-
- /**
- * Set the state of commandSent variable which determines whether a reply
- * to a command sent is awaited
- */
- public void setCommandSent(boolean commandSent)
- {
- synchronized(lock)
- {
- this.commandSent = commandSent;
- }
- }
-
- /**
- * Return the type of message received from remote server
- *
- * @return messageType
- */
- public int getMessageType()
- {
- return this.messageType;
- }
-
- /**
- * Sets the type of message received from remote server
- *
- * @param messageType
- */
- public void setMessageType(int messageType)
- {
- this.messageType = messageType;
- }
-
- /**
- * Returns the status of the contact.
- *
- * @return presenceStatus
- */
- public PresenceStatus getPresenceStatus()
- {
- return this.presenceStatus;
- }
-
- /**
- * Sets <tt>sshPresenceStatus</tt> as the PresenceStatus that this
- * contact is currently in.
- * @param sshPresenceStatus the <tt>SSHPresenceStatus</tt>
- * currently valid for this contact.
- */
- public void setPresenceStatus(PresenceStatus sshPresenceStatus)
- {
- this.presenceStatus = sshPresenceStatus;
- }
-
- /**
- * Returns a reference to the protocol provider that created the contact.
- *
- * @return a refererence to an instance of the ProtocolProviderService
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return parentProvider;
- }
-
- /**
- * Determines whether or not this contact represents our own identity.
- *
- * @return true
- */
- public boolean isLocal()
- {
- return true;
- }
-
- /**
- * Returns the group that contains this contact.
- * @return a reference to the <tt>ContactGroupSSHImpl</tt> that
- * contains this contact.
- */
- public ContactGroup getParentContactGroup()
- {
- return this.parentGroup;
- }
-
- /**
- * Returns a string representation of this contact, containing most of its
- * representative details.
- *
- * @return a string representation of this contact.
- */
- @Override
- public String toString()
- {
- StringBuffer buff
- = new StringBuffer("ContactSSHImpl[ DisplayName=")
- .append(getDisplayName()).append("]");
-
- return buff.toString();
- }
-
- /**
- * Determines whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @return true if the contact is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Specifies whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @param isPersistent true if the contact is persistent and false
- * otherwise.
- */
- public void setPersistent(boolean isPersistent)
- {
- this.isPersistent = isPersistent;
- }
-
-
- /**
- * Returns persistent data of the contact.
- *
- * @return persistentData of the contact
- */
- public String getPersistentData()
- {
- return persistentData;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- *
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Makes the contact resolved or unresolved.
- *
- * @param resolved true to make the contact resolved; false to
- * make it unresolved
- */
- public void setResolved(boolean resolved)
- {
- this.isResolved = resolved;
- }
-
- /**
- * Returns the persistent presence operation set that this contact belongs
- * to.
- *
- * @return the <tt>OperationSetPersistentPresenceSSHImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetPersistentPresence
- getParentPresenceOperationSet()
- {
- return
- parentProvider
- .getOperationSet(OperationSetPersistentPresence.class);
- }
-
- /**
- * Returns the BasicInstant Messaging operation set that this contact
- * belongs to.
- *
- * @return the <tt>OperationSetBasicInstantMessagingSSHImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetBasicInstantMessaging
- getParentBasicInstantMessagingOperationSet()
- {
- return
- parentProvider
- .getOperationSet(OperationSetBasicInstantMessaging.class);
- }
-
- /**
- * Returns the File Transfer operation set that this contact belongs
- * to.
- *
- * @return the <tt>OperationSetFileTransferSSHImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetFileTransfer
- getFileTransferOperationSet()
- {
- return parentProvider.getOperationSet(OperationSetFileTransfer.class);
- }
-
-
- /**
- * Returns the SSH Session associated with this contact
- *
- * @return sshSession
- */
- public Session getSSHSession()
- {
- return this.sshSession;
- }
-
- /**
- * Sets the SSH Session associated with this contact
- *
- * @param sshSession the newly created SSH Session to be associated
- */
- public void setSSHSession(Session sshSession)
- {
- this.sshSession = sshSession;
- }
-
- /**
- * Returns the SSH Shell Channel associated with this contact
- *
- * @return sshShellChannel
- */
- public Channel getShellChannel()
- {
- return this.sshShellChannel;
- }
-
- /**
- * Sets the SSH Shell channel associated with this contact
- *
- * @param sshShellChannel to be associated with SSH Session of this contact
- */
- public void setShellChannel(Channel sshShellChannel)
- {
- this.sshShellChannel = sshShellChannel;
- }
-
- /**
- * Returns the Input Stream associated with SSH Channel of this contact
- *
- * @return shellInputStream associated with SSH Channel of this contact
- */
- public InputStream getShellInputStream()
- {
- return this.shellInputStream;
- }
-
-// /**
-// * Sets the Input Stream associated with SSH Channel of this contact
-// *
-// * @param shellInputStream to be associated with SSH Channel of
-// * this contact
-// */
-// public void setShellInputStream(InputStream shellInputStream)
-// {
-// this.shellInputStream = shellInputStream;
-// }
-
- /**
- * Returns the Output Stream associated with SSH Channel of this contact
- *
- * @return shellOutputStream associated with SSH Channel of this contact
- */
- public OutputStream getShellOutputStream()
- {
- return this.shellOutputStream;
- }
-
-// /**
-// * Sets the Output Stream associated with SSH Channel of this contact
-// *
-// * @param shellOutputStream to be associated with SSH Channel of this contact
-// */
-// public void setShellOutputStream(OutputStream shellOutputStream)
-// {
-// this.shellOutputStream = shellOutputStream;
-// }
-
- /**
- * Returns the BufferedReader associated with SSH Channel of this contact
- *
- * @return shellReader associated with SSH Channel of this contact
- */
- public InputStreamReader getShellReader()
- {
- return this.shellReader;
- }
-
-// /**
-// * Sets the BufferedReader associated with SSH Channel of this contact
-// *
-// * @param shellReader to be associated with SSH Channel of this contact
-// */
-// public void setShellReader(BufferedReader shellReader)
-// {
-// this.shellReader = shellReader;
-// }
-
- /**
- * Returns the PrintWriter associated with SSH Channel of this contact
- *
- * @return shellWriter associated with SSH Channel of this contact
- */
- public PrintWriter getShellWriter()
- {
- return this.shellWriter;
- }
-
-// /**
-// * Sets the PrintWriter associated with SSH Channel of this contact
-// *
-// * @param shellWriter to be associated with SSH Channel of this contact
-// */
-// public void setShellWriter(PrintWriter shellWriter)
-// {
-// this.shellWriter = shellWriter;
-// }
-
- /**
- * Returns the userName associated with SSH Channel of this contact
- *
- * @return userName associated with SSH Channel of this contact
- */
- public String getUserName()
- {
- return sshConfigurationForm.getUserName();
- }
-
- /**
- * Returns the password associated with SSH Channel of this contact
- *
- * @return password associated with SSH Channel of this contact
- */
- public String getPassword()
- {
- return sshConfigurationForm.getPassword();
- }
-
- /**
- * Sets the Password associated with this contact
- *
- * @param password
- */
- public void setPassword(String password)
- {
- this.sshConfigurationForm.setPasswordField(password);
- savePersistentDetails();
- }
-
-// /**
-// * Sets the PS1 prompt of the current shell of Contact
-// *
-// * @param sshPrompt to be associated
-// */
-// public void setShellPrompt(String sshPrompt)
-// {
-// this.sshPrompt = sshPrompt;
-// }
-//
-// /**
-// * Returns the PS1 prompt of the current shell of Contact
-// *
-// * @return sshPrompt
-// */
-// public String getShellPrompt()
-// {
-// return this.sshPrompt;
-// }
-
- /**
- * Return the current status message of this contact.
- *
- * @return the current status message
- */
- public String getStatusMessage()
- {
- return presenceStatus.getStatusName();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ContactTimerSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/ContactTimerSSHImpl.java
deleted file mode 100644
index 4e3664d..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ContactTimerSSHImpl.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.util.*;
-
-/**
- * Timer Task to update the reachability status of SSH Contact in contact list.
- * (Reachability of remote machine from user's machine)
- * The timer is started at either of the two places
- * - A new contact - OperationSetPersistentPresenceSSHImpl
- * .createUnresolvedContact
- * - Existing Contact - OperationSetPersistentPresenceSSHImpl.subscribe
- *
- * @author Shobhit Jindal
- */
-public class ContactTimerSSHImpl
- extends TimerTask
-{
- private static final Logger logger
- = Logger.getLogger(OperationSetFileTransferSSHImpl.class);
-
- /**
- * The contact ID of the remote machine
- */
- private ContactSSH sshContact;
-
- /**
- * PersistentPresence Identifer assoiciated with SSH Contact
- */
- private OperationSetPersistentPresenceSSHImpl persistentPresence;
-
- /**
- * The method which is called at regular intervals to update the status
- * of remote machines
- *
- * Presently only ONLINE and OFFILINE status are checked
- */
- @Override
- public void run()
- {
- try
- {
- InetAddress remoteMachine = InetAddress.getByName(
- sshContact.getSSHConfigurationForm().getHostName());
-
- //check if machine is reachable
- if(remoteMachine.isReachable(
- sshContact.getSSHConfigurationForm().getUpdateInterval()))
- {
- if (sshContact.getPresenceStatus().equals(SSHStatusEnum.OFFLINE)
- || sshContact.getPresenceStatus().equals(SSHStatusEnum
- .NOT_AVAILABLE))
- {
- // change status to online
- persistentPresence.changeContactPresenceStatus(
- sshContact, SSHStatusEnum.ONLINE);
-
- if (logger.isDebugEnabled())
- logger.debug("SSH Host " + sshContact
- .getSSHConfigurationForm().getHostName() + ": Online");
- }
-
- }
- else throw new IOException();
-
- }
- catch (IOException ex)
- {
- if (sshContact.getPresenceStatus().equals(SSHStatusEnum.ONLINE)
- || sshContact.getPresenceStatus().equals(
- SSHStatusEnum.NOT_AVAILABLE))
- {
- persistentPresence.changeContactPresenceStatus(
- sshContact, SSHStatusEnum.OFFLINE);
-
- if (logger.isDebugEnabled())
- logger.debug("SSH Host " + sshContact.getSSHConfigurationForm()
- .getHostName() + ": Offline");
- }
- }
- }
- /**
- * Creates a new instance of ContactTimerSSHImpl
- *
- * @param sshContact the <tt>Contact</tt>
- */
- public ContactTimerSSHImpl(ContactSSH sshContact)
- {
- super();
- this.sshContact = sshContact;
- this.persistentPresence = (OperationSetPersistentPresenceSSHImpl)
- sshContact.getParentPresenceOperationSet();
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/FileTransferSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/FileTransferSSHImpl.java
deleted file mode 100644
index 1e95032..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/FileTransferSSHImpl.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * SSH implementation of the <tt>AbstractFileTransfer</tt>.
- *
- * @author Yana Stamcheva
- */
-public class FileTransferSSHImpl
- extends AbstractFileTransfer
-{
- private final SSHFileTransferDaemon fileTransfer;
-
- private final Date initialDate;
-
- /**
- * Creates an SSH implementation of the file transfer interface.
- *
- * @param fileTransfer the SSH file transfer
- * @param date the initial date of the transfer
- */
- public FileTransferSSHImpl( SSHFileTransferDaemon fileTransfer,
- Date date)
- {
- this.fileTransfer = fileTransfer;
- this.initialDate = date;
- }
-
- /**
- * Cancels this file transfer. When this method is called transfer should
- * be interrupted.
- */
- @Override
- public void cancel()
- {
- // TODO: Implement cancel() for SSH file transfer.
- }
-
- /**
- * Returns the number of bytes already transfered through this file transfer.
- *
- * @return the number of bytes already transfered through this file transfer
- */
- @Override
- public long getTransferedBytes()
- {
- // TODO: Implement getTransferedBytes() for SSH file transfer.
- return 0;
- }
-
- public int getDirection()
- {
- return IN;
- }
-
- public File getLocalFile()
- {
- return null;
- }
-
- public Contact getContact()
- {
- return null;
- }
-
- public String getID()
- {
- return null;
- }
-
- public Date getInitialDate()
- {
- return initialDate;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/MessageSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/MessageSSHImpl.java
deleted file mode 100644
index a8324f7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/MessageSSHImpl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Very simple message implementation for the SSH protocol.
- *
- * @author Shobhit Jindal
- * @author Lubomir Marinov
- */
-public class MessageSSHImpl
- extends AbstractMessage
-{
-
- /**
- * The content type of the message.
- */
- public static String contentType = "text/plain";
-
- /**
- * Creates a message instance according to the specified parameters.
- *
- * @param content the message body
- * @param contentType message content type or null for text/plain
- * @param contentEncoding message encoding or null for UTF8
- * @param subject the subject of the message or null for no subject.
- */
- public MessageSSHImpl(String content, String contentType,
- String contentEncoding, String subject)
- {
- super(content, null, contentEncoding, subject);
-
- MessageSSHImpl.contentType = contentType;
- }
-
- /**
- * Returns the type of the content of this message.
- *
- * @return the type of the content of this message.
- */
- @Override
- public String getContentType()
- {
- return contentType;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetBasicInstantMessagingSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetBasicInstantMessagingSSHImpl.java
deleted file mode 100644
index 9073ad5..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetBasicInstantMessagingSSHImpl.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-
-/**
- * Instant messaging functionality for the SSH protocol.
- *
- * @author Shobhit Jindal
- */
-public class OperationSetBasicInstantMessagingSSHImpl
- extends AbstractOperationSetBasicInstantMessaging
-{
-
- /**
- * The currently valid persistent presence operation set..
- */
- private OperationSetPersistentPresenceSSHImpl opSetPersPresence = null;
-
- /**
- * The currently valid file transfer operation set
- */
- private OperationSetFileTransferSSHImpl fileTransfer;
-
- /**
- * The protocol provider that created us.
- */
- private ProtocolProviderServiceSSHImpl parentProvider = null;
-
- /**
- * Creates an instance of this operation set keeping a reference to the
- * parent protocol provider and presence operation set.
- *
- * @param provider The provider instance that creates us.
- */
- public OperationSetBasicInstantMessagingSSHImpl(
- ProtocolProviderServiceSSHImpl provider)
- {
- this.parentProvider = provider;
-
- this.opSetPersPresence
- = (OperationSetPersistentPresenceSSHImpl)
- provider
- .getOperationSet(OperationSetPersistentPresence.class);
- }
-
- @Override
- public Message createMessage(String content, String contentType,
- String encoding, String subject)
- {
- return new MessageSSHImpl(content, contentType, encoding, subject);
- }
-
- /**
- * Sends the <tt>message</tt> to the destination indicated by the
- * <tt>to</tt> contact. An attempt is made to re-establish the shell
- * connection if the current one is invalid.
- * The reply from server is sent by a seperate reader thread
- *
- * @param to the <tt>Contact</tt> to send <tt>message</tt> to
- * @param message the <tt>Message</tt> to send.
- * @throws IllegalStateException if the underlying ICQ stack is not
- * registered and initialized.
- * @throws IllegalArgumentException if <tt>to</tt> is not an instance
- * belonging to the underlying implementation.
- */
- public void sendInstantMessage(
- Contact to,
- Message message)
- throws IllegalStateException,
- IllegalArgumentException
- {
- if( !(to instanceof ContactSSHImpl) )
- throw new IllegalArgumentException(
- "The specified contact is not a SSH contact."
- + to);
-
- ContactSSH sshContact = (ContactSSH)to;
-
- // making sure no messages are sent and no new threads are triggered,
- // until a thread trying to connect to remote server returns
- if(sshContact.isConnectionInProgress())
- {
- deliverMessage(
- createMessage("A connection attempt is in progress"),
- (ContactSSHImpl)to);
- return;
- }
-
- if( !parentProvider.isShellConnected(sshContact) )
- {
-
- try
- {
- /**
- * creating a new SSH session / shell channel
- * - first message
- * - session is timed out
- * - network problems
- */
- parentProvider.connectShell(sshContact, message);
-
- //the first message is ignored
- return;
- }
- catch (Exception ex)
- {
- throw new IllegalStateException(ex.getMessage());
- }
- }
-
- if(wrappedMessage(message.getContent(), sshContact))
- {
- fireMessageDelivered(message, to);
- return;
- }
-
- try
- {
- sshContact.sendLine(message.getContent());
- sshContact.setCommandSent(true);
- }
- catch (IOException ex)
- {
- // Closing IO Streams
- sshContact.closeShellIO();
-
- throw new IllegalStateException(ex.getMessage());
- }
-
- fireMessageDelivered(message, to);
- }
-
- /**
- * Check the message for wrapped Commands
- * All commands begin with /
- *
- * @param message from user
- * @param sshContact of the remote machine
- *
- * @return true if the message had commands, false otherwise
- */
- private boolean wrappedMessage(
- String message,
- ContactSSH sshContact)
- {
- if(message.startsWith("/upload"))
- {
- int firstSpace = message.indexOf(' ');
-
- try
- {
- sshContact.getFileTransferOperationSet().sendFile(
- sshContact,
- null,
- message.substring(message.indexOf(' ', firstSpace+1) + 1),
- message.substring(
- firstSpace+1,
- message.indexOf(' ', firstSpace+1)));
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
- return true;
- }
- else if(message.startsWith("/download"))
- {
- int firstSpace = message.indexOf(' ');
-
- try
- {
- sshContact.getFileTransferOperationSet().sendFile(
- null,
- sshContact,
- message.substring(firstSpace+1, message.indexOf(' ',
- firstSpace+1)),
- message.substring(message.indexOf(' ', firstSpace+1) + 1));
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- return true;
- }
- return false;
- }
-
- /**
- * In case the <tt>to</tt> Contact corresponds to another ssh
- * protocol provider registered with SIP Communicator, we deliver
- * the message to them, in case the <tt>to</tt> Contact represents us, we
- * fire a <tt>MessageReceivedEvent</tt>, and if <tt>to</tt> is simply
- * a contact in our contact list, then we simply echo the message.
- *
- * @param message the <tt>Message</tt> the message to deliver.
- * @param to the <tt>Contact</tt> that we should deliver the message to.
- */
- void deliverMessage(
- Message message,
- ContactSSH to)
- {
- String userID = to.getAddress();
-
- //if the user id is owr own id, then this message is being routed to us
- //from another instance of the ssh provider.
- if (userID.equals(this.parentProvider.getAccountID().getUserID()))
- {
- //check who is the provider sending the message
- String sourceUserID
- = to.getProtocolProvider().getAccountID().getUserID();
-
- //check whether they are in our contact list
- Contact from = opSetPersPresence.findContactByID(sourceUserID);
-
- //and if not - add them there as volatile.
- if(from == null)
- {
- from = opSetPersPresence.createVolatileContact(sourceUserID);
- }
-
- //and now fire the message received event.
- fireMessageReceived(message, from);
- }
- else
- {
- //if userID is not our own, try an check whether another provider
- //has that id and if yes - deliver the message to them.
- ProtocolProviderServiceSSHImpl sshProvider
- = this.opSetPersPresence.findProviderForSSHUserID(userID);
- if(sshProvider != null)
- {
- OperationSetBasicInstantMessagingSSHImpl opSetIM
- = (OperationSetBasicInstantMessagingSSHImpl)
- sshProvider
- .getOperationSet(
- OperationSetBasicInstantMessaging.class);
- opSetIM.deliverMessage(message, to);
- }
- else
- {
- //if we got here then "to" is simply someone in our contact
- //list so let's just echo the message.
- fireMessageReceived(message, to);
- }
- }
- }
-
- /**
- * Notifies all registered message listeners that a message has been
- * received.
- *
- * @param message the <tt>Message</tt> that has been received.
- * @param from the <tt>Contact</tt> that <tt>message</tt> was received from.
- */
- @Override
- protected void fireMessageReceived(Message message, Contact from)
- {
- fireMessageEvent(
- new MessageReceivedEvent(
- message,
- from,
- new Date(),
- ((ContactSSH) from).getMessageType()));
- }
-
- /**
- * Determines whether the SSH protocol provider supports
- * sending and receiving offline messages.
- *
- * @return <tt>false</tt>
- */
- public boolean isOfflineMessagingSupported()
- {
- return false;
- }
-
- /**
- * Determines wheter the protocol supports the supplied content type
- *
- * @param contentType the type we want to check
- * @return <tt>true</tt> if the protocol supports it and
- * <tt>false</tt> otherwise.
- */
- public boolean isContentTypeSupported(String contentType)
- {
- return MessageSSHImpl.contentType.equals(contentType);
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java
deleted file mode 100644
index 61d8160..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * This class provides operations to upload/download files to remote machines
- *
- * @author Shobhit Jindal
- */
-public class OperationSetFileTransferSSHImpl
- implements OperationSetFileTransfer
-{
- private static final Logger logger
- = Logger.getLogger(OperationSetFileTransferSSHImpl.class);
-
- /**
- * Currently registered message listeners.
- */
- private Vector<FileTransferListener> fileTransferListeners
- = new Vector<FileTransferListener>();
-
- /**
- * The protocol provider that created us.
- */
- private ProtocolProviderServiceSSHImpl parentProvider = null;
-
-
- /**
- * Creates a new instance of OperationSetFileTransferSSHImpl
- *
- * @param parentProvider the parent protocol provider service
- */
- public OperationSetFileTransferSSHImpl(
- ProtocolProviderServiceSSHImpl parentProvider)
- {
- this.parentProvider = parentProvider;
- }
-
- /**
- * Registers a FileTransferListener with this operation set so that it gets
- * notifications of start, complete, failure of file transfers
- *
- * @param listener the <tt>FileListener</tt> to register.
- */
- public void addFileTransferListener(
- FileTransferListener listener)
- {
- synchronized (fileTransferListeners)
- {
- if(!fileTransferListeners.contains(listener))
- fileTransferListeners.add(listener);
- }
- }
-
- public void removeFileTransferListener(
- FileTransferListener listener)
- {
- synchronized (fileTransferListeners)
- {
- fileTransferListeners.remove(listener);
- }
- }
-
- /**
- * Sends a file transfer request to the given <tt>toContact</tt>.
- * @param toContact the contact that should receive the file
- * @param file the file to send
- */
- public FileTransfer sendFile( Contact toContact,
- File file)
- {
- return this.sendFile( toContact,
- null,
- file.getAbsolutePath(),
- file.getAbsolutePath());
- }
-
- /**
- * The file transfer method to/from the remote machine
- * either toContact is null(we are downloading file from remote machine
- * or fromContact is null(we are uploading file to remote machine
- *
- * @param toContact - the file recipient
- * @param fromContact - the file sender
- * @param remotePath - the identifier for the remote file
- * @param localPath - the identifier for the local file
- */
- public FileTransfer sendFile(
- Contact toContact,
- Contact fromContact,
- String remotePath,
- String localPath)
- {
- if(toContact == null)
- {
- SSHFileTransferDaemon fileTransferDaemon
- = new SSHFileTransferDaemon(
- (ContactSSH)fromContact,
- parentProvider);
-
- if(localPath.endsWith(System.getProperty("file.separator")))
- localPath += remotePath.substring(remotePath.lastIndexOf(
- System.getProperty("file.separator")) + 1);
-
- fileTransferDaemon.downloadFile(
- remotePath,
- localPath);
-
- return new FileTransferSSHImpl(fileTransferDaemon, new Date());
- }
- else if(fromContact == null)
- {
- SSHFileTransferDaemon fileTransferDaemon
- = new SSHFileTransferDaemon(
- (ContactSSH) toContact,
- parentProvider);
-
- fileTransferDaemon.uploadFile(
- remotePath,
- localPath);
-
- return new FileTransferSSHImpl(fileTransferDaemon, new Date());
- }
-
- // code should not reach here
- // assert false;
- logger.error("we should not be here !");
- return null;
- }
-
- /**
- * Returns the maximum file length supported by the protocol in bytes.
- * @return the file length that is supported.
- */
- public long getMaximumFileLength()
- {
- return 2048*1024*1024;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetPersistentPresenceSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetPersistentPresenceSSHImpl.java
deleted file mode 100644
index d4c63bd..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetPersistentPresenceSSHImpl.java
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-import org.osgi.framework.*;
-
-/**
- * A SSH implementation of a persistent presence operation set. In order
- * to simulate server persistence, this operation set would simply accept all
- * unresolved contacts and resolve them immediately. A real world protocol
- * implementation would save it on a server using methods provided by the
- * protocol stack.
- *
- * @author Shobhit Jindal
- */
-public class OperationSetPersistentPresenceSSHImpl
- extends AbstractOperationSetPersistentPresence<ProtocolProviderServiceSSHImpl>
-{
- private static final Logger logger =
- Logger.getLogger(OperationSetPersistentPresenceSSHImpl.class);
-
- /**
- * The root of the ssh contact list.
- */
- private ContactGroupSSHImpl contactListRoot = null;
-
- /**
- * The currently active status message.
- */
- private String statusMessage = "Online";
-
- /**
- * Our default presence status.
- */
- private PresenceStatus presenceStatus = SSHStatusEnum.ONLINE;
-
- /**
- * Creates an instance of this operation set keeping a reference to the
- * specified parent <tt>provider</tt>.
- * @param provider the ProtocolProviderServiceSSHImpl instance that
- * created us.
- */
- public OperationSetPersistentPresenceSSHImpl(
- ProtocolProviderServiceSSHImpl provider)
- {
- super(provider);
-
- contactListRoot = new ContactGroupSSHImpl("RootGroup", provider);
-
- //add our unregistration listener
- parentProvider.addRegistrationStateChangeListener(
- new UnregistrationListener());
- }
-
- /**
- * This function changes the status of contact as well as that of the
- * provider
- *
- * @param sshContact the contact of the remote machine
- * @param newStatus new status of the contact
- */
- public void changeContactPresenceStatus(
- ContactSSH sshContact,
- PresenceStatus newStatus)
- {
- PresenceStatus oldStatus = sshContact.getPresenceStatus();
- sshContact.setPresenceStatus(newStatus);
- fireContactPresenceStatusChangeEvent(
- sshContact
- , sshContact.getParentContactGroup()
- , oldStatus);
- fireProviderStatusChangeEvent(oldStatus);
- }
-
- /**
- * Creates a group with the specified name and parent in the server
- * stored contact list.
- *
- * @param parent the group where the new group should be created
- * @param groupName the name of the new group to create.
- */
- public void createServerStoredContactGroup(
- ContactGroup parent,
- String groupName)
- {
- ContactGroupSSHImpl newGroup
- = new ContactGroupSSHImpl(groupName, parentProvider);
-
- ((ContactGroupSSHImpl)parent).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
- /**
- * A SSH Provider method to use for fast filling of a contact list.
- *
- * @param contactGroup the group to add
- */
- public void addSSHGroup(ContactGroupSSHImpl contactGroup)
- {
- contactListRoot.addSubgroup(contactGroup);
- }
-
- /**
- * A SSH Provider method to use for fast filling of a contact list.
- * This method would add both the group and fire an event.
- *
- * @param parent the group where <tt>contactGroup</tt> should be added.
- * @param contactGroup the group to add
- */
- public void addSSHGroupAndFireEvent(
- ContactGroupSSHImpl parent,
- ContactGroupSSHImpl contactGroup)
- {
- parent.addSubgroup(contactGroup);
-
- this.fireServerStoredGroupEvent(
- contactGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
-
- /**
- * Returns a reference to the contact with the specified ID in case we
- * have a subscription for it and null otherwise/
- *
- * @param contactID a String identifier of the contact which we're
- * seeking a reference of.
- * @return a reference to the Contact with the specified
- * <tt>contactID</tt> or null if we don't have a subscription for the
- * that identifier.
- */
- public Contact findContactByID(String contactID)
- {
- return contactListRoot.findContactByID(contactID);
- }
-
- /**
- * Sets the specified status message.
- * @param statusMessage a String containing the new status message.
- */
- public void setStatusMessage(String statusMessage)
- {
- this.statusMessage = statusMessage;
- }
-
- /**
- * Returns the status message that was last set through
- * setCurrentStatusMessage.
- *
- * @return the last status message that we have requested and the aim
- * server has confirmed.
- */
- public String getCurrentStatusMessage()
- {
- return statusMessage;
- }
-
- /**
- * Returns the protocol specific contact instance representing the local
- * user.
- *
- * @return the Contact (address, phone number, or uin) that the Provider
- * implementation is communicating on behalf of.
- */
- public Contact getLocalContact()
- {
- return null;
- }
-
- /**
- * Returns a PresenceStatus instance representing the state this provider
- * is currently in.
- *
- * @return the PresenceStatus last published by this provider.
- */
- public PresenceStatus getPresenceStatus()
- {
- return presenceStatus;
- }
-
- /**
- * Returns the root group of the server stored contact list.
- *
- * @return the root ContactGroup for the ContactList stored by this
- * service.
- */
- public ContactGroup getServerStoredContactListRoot()
- {
- return contactListRoot;
- }
-
- /**
- * Returns the set of PresenceStatus objects that a user of this service
- * may request the provider to enter.
- *
- * @return Iterator a PresenceStatus array containing "enterable" status
- * instances.
- */
- public Iterator<PresenceStatus> getSupportedStatusSet()
- {
- return SSHStatusEnum.supportedStatusSet();
- }
-
- /**
- * Removes the specified contact from its current parent and places it
- * under <tt>newParent</tt>.
- *
- * @param contactToMove the <tt>Contact</tt> to move
- * @param newParent the <tt>ContactGroup</tt> where <tt>Contact</tt>
- * would be placed.
- */
- public void moveContactToGroup(
- Contact contactToMove,
- ContactGroup newParent)
- {
- ContactSSHImpl sshContact
- = (ContactSSHImpl)contactToMove;
-
- ContactGroupSSHImpl parentSSHGroup
- = findContactParent(sshContact);
-
- parentSSHGroup.removeContact(sshContact);
-
- //if this is a volatile contact then we haven't really subscribed to
- //them so we'd need to do so here
- if(!sshContact.isPersistent())
- {
- //first tell everyone that the volatile contact was removed
- fireSubscriptionEvent(sshContact
- , parentSSHGroup
- , SubscriptionEvent.SUBSCRIPTION_REMOVED);
-
- try
- {
- //now subscribe
- this.subscribe(newParent, contactToMove.getAddress());
-
- //now tell everyone that we've added the contact
- fireSubscriptionEvent(sshContact
- , newParent
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
- }
- catch (Exception ex)
- {
- logger.error("Failed to move contact "
- + sshContact.getAddress()
- , ex);
- }
- }
- else
- {
- ( (ContactGroupSSHImpl) newParent)
- .addContact(sshContact);
-
- fireSubscriptionMovedEvent(contactToMove
- , parentSSHGroup
- , newParent);
- }
- }
-
- /**
- * Requests the provider to enter into a status corresponding to the
- * specified paramters.
- *
- * @param status the PresenceStatus as returned by
- * getRequestableStatusSet
- * @param statusMessage the message that should be set as the reason to
- * enter that status
- * @throws IllegalArgumentException if the status requested is not a
- * valid PresenceStatus supported by this provider.
- * @throws IllegalStateException if the provider is not currently
- * registered.
- */
- public void publishPresenceStatus(
- PresenceStatus status,
- String statusMessage)
- throws IllegalArgumentException,
- IllegalStateException
- {
- PresenceStatus oldPresenceStatus = this.presenceStatus;
- this.presenceStatus = status;
- this.statusMessage = statusMessage;
-
- this.fireProviderStatusChangeEvent(oldPresenceStatus);
-
-
-// //since we are not a real protocol, we set the contact presence status
-// //ourselves and make them have the same status as ours.
-// changePresenceStatusForAllContacts( getServerStoredContactListRoot()
-// , getPresenceStatus());
-//
-// //now check whether we are in someone else's contact list and modify
-// //our status there
-// List contacts = findContactsPointingToUs();
-//
-// Iterator contactsIter = contacts.iterator();
-// while (contactsIter.hasNext())
-// {
-// ContactSSHImpl contact
-// = (ContactSSHImpl) contactsIter.next();
-//
-// PresenceStatus oldStatus = contact.getPresenceStatus();
-// contact.setPresenceStatus(status);
-// contact.getParentPresenceOperationSet()
-// .fireContactPresenceStatusChangeEvent(
-// contact
-// , contact.getParentContactGroup()
-// , oldStatus);
-//
-// }
- }
-
-
-
- /**
- * Get the PresenceStatus for a particular contact.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * we're interested in.
- * @return PresenceStatus the <tt>PresenceStatus</tt> of the specified
- * <tt>contact</tt>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * retrieving the status fails due to errors experienced during
- * network communication
- */
- public PresenceStatus queryContactStatus(String contactIdentifier)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- return findContactByID(contactIdentifier).getPresenceStatus();
- }
-
- /**
- * Sets the presence status of <tt>contact</tt> to <tt>newStatus</tt>.
- *
- * @param contact the <tt>ContactSSHImpl</tt> whose status we'd like
- * to set.
- * @param newStatus the new status we'd like to set to <tt>contact</tt>.
- */
- private void changePresenceStatusForContact(
- ContactSSH contact,
- PresenceStatus newStatus)
- {
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(newStatus);
-
- fireContactPresenceStatusChangeEvent(
- contact, findContactParent(contact), oldStatus);
- }
-
- /**
- * Sets the presence status of all <tt>contact</tt>s in our contact list
- * (except those that correspond to another provider registered with SC)
- * to <tt>newStatus</tt>.
- *
- * @param newStatus the new status we'd like to set to <tt>contact</tt>.
- * @param parent the group in which we'd have to update the status of all
- * direct and indirect child contacts.
- */
- private void changePresenceStatusForAllContacts(
- ContactGroup parent,
- PresenceStatus newStatus)
- {
- //first set the status for contacts in this group
- Iterator<Contact> childContacts = parent.contacts();
-
- while(childContacts.hasNext())
- {
- ContactSSHImpl contact
- = (ContactSSHImpl)childContacts.next();
-
- if(findProviderForSSHUserID(contact.getAddress()) != null)
- {
- //this is a contact corresponding to another SIP Communicator
- //provider so we won't change it's status here.
- continue;
- }
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(newStatus);
-
- fireContactPresenceStatusChangeEvent(
- contact, parent, oldStatus);
- }
-
- //now call this method recursively for all subgroups
- Iterator<ContactGroup> subgroups = parent.subgroups();
-
- while(subgroups.hasNext())
- {
- ContactGroup subgroup = subgroups.next();
- changePresenceStatusForAllContacts(subgroup, newStatus);
- }
- }
-
- /**
- * Returns the group that is parent of the specified sshGroup or null
- * if no parent was found.
- * @param sshGroup the group whose parent we're looking for.
- * @return the ContactGroupSSHImpl instance that sshGroup
- * belongs to or null if no parent was found.
- */
- public ContactGroupSSHImpl findGroupParent(
- ContactGroupSSHImpl sshGroup)
- {
- return contactListRoot.findGroupParent(sshGroup);
- }
-
- /**
- * Returns the group that is parent of the specified sshContact or
- * null if no parent was found.
- * @param sshContact the contact whose parent we're looking for.
- * @return the ContactGroupSSHImpl instance that sshContact
- * belongs to or null if no parent was found.
- */
- public ContactGroupSSHImpl findContactParent(
- ContactSSH sshContact)
- {
- return (ContactGroupSSHImpl)sshContact
- .getParentContactGroup();
- }
-
-
- /**
- * Removes the specified group from the server stored contact list.
- *
- * @param group the group to remove.
- *
- * @throws IllegalArgumentException if <tt>group</tt> was not found in this
- * protocol's contact list.
- */
- public void removeServerStoredContactGroup(ContactGroup group)
- throws IllegalArgumentException
- {
- ContactGroupSSHImpl sshGroup
- = (ContactGroupSSHImpl)group;
-
- ContactGroupSSHImpl parent = findGroupParent(sshGroup);
-
- if(parent == null)
- {
- throw new IllegalArgumentException(
- "group " + group
- + " does not seem to belong to this protocol's contact "
- + "list.");
- }
-
- parent.removeSubGroup(sshGroup);
-
- this.fireServerStoredGroupEvent(
- sshGroup, ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
- }
-
- /**
- * Renames the specified group from the server stored contact list.
- *
- * @param group the group to rename.
- * @param newName the new name of the group.
- */
- public void renameServerStoredContactGroup(
- ContactGroup group,
- String newName)
- {
- ((ContactGroupSSHImpl)group).setGroupName(newName);
-
- this.fireServerStoredGroupEvent(
- group, ServerStoredGroupEvent
- .GROUP_RENAMED_EVENT);
- }
-
-
- /**
- * Persistently adds a subscription for the presence status of the
- * contact corresponding to the specified contactIdentifier and indicates
- * that it should be added to the specified group of the server stored
- * contact list.
- *
- * @param parent the parent group of the server stored contact list
- * where the contact should be added. <p>
- * @param contactIdentifier the contact whose status updates we are
- * subscribing for.
- * @throws IllegalArgumentException if <tt>contact</tt> or
- * <tt>parent</tt> are not a contact known to the underlying protocol
- * provider.
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(
- ContactGroup parent,
- String contactIdentifier)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- ContactSSH sshContact = new ContactSSHImpl(contactIdentifier,
- parentProvider);
-
-/* ProtocolProviderServiceSSHImpl.getUIService().getConfigurationWindow()
- .setVisible(true);
-*/
- sshContact.setParentGroup((ContactGroupSSHImpl)parent);
- sshContact.getSSHConfigurationForm().setVisible(true);
-
-
-
-/* Gets the domain name or IP address of the sshContact machine via the
- * UI Service Interface
- sshContact.setPersistentData(ProtocolProviderServiceSSHImpl
- .getUIService().getPopupDialog()
- .showInputPopupDialog("Enter Domain Name or IP Address of "
- + sshContact.getDisplayName()));
-
- // contact is added to list later after the user has provided
- // details in SSHConfigurationForm
-
- // addContactToList method is called
-*/
- }
-
- /**
- * Add a contact to the specified group
- *
- * @param parent the group
- * @param sshContact the contact
- */
- public void addContactToList(
- ContactGroup parent,
- ContactSSH sshContact)
- {
- // Adds the sshContact to the sshContact list
-
- ((ContactGroupSSHImpl)parent).addContact(sshContact);
-
- fireSubscriptionEvent(sshContact,
- parent,
- SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- //notify presence listeners for the status change.
- fireContactPresenceStatusChangeEvent(sshContact
- , parent
- , SSHStatusEnum.NOT_AVAILABLE);
-
- sshContact.startTimerTask();
- }
-
- /**
- * Adds a subscription for the presence status of the contact
- * corresponding to the specified contactIdentifier.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * updates we are subscribing for. <p>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(String contactIdentifier) throws
- IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- subscribe(contactListRoot, contactIdentifier);
-
- }
-
- /**
- * Removes a subscription for the presence status of the specified
- * contact.
- *
- * @param contact the contact whose status updates we are unsubscribing
- * from.
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * unsubscribing fails due to errors experienced during network
- * communication
- */
- public void unsubscribe(Contact contact) throws
- IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- ContactGroupSSHImpl parentGroup
- = (ContactGroupSSHImpl)((ContactSSHImpl)contact)
- .getParentContactGroup();
-
- parentGroup.removeContact((ContactSSHImpl)contact);
-
- fireSubscriptionEvent(contact,
- ((ContactSSHImpl)contact).getParentContactGroup()
- , SubscriptionEvent.SUBSCRIPTION_REMOVED);
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created Contact
- * against the server. The protocol provider may will later try and resolve
- * the contact. When this happens the corresponding event would notify
- * interested subscription listeners.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(
- String address,
- String persistentData)
- {
- return createUnresolvedContact(address
- , persistentData
- , getServerStoredContactListRoot());
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created Contact
- * against the server. The protocol provider may will later try and resolve
- * the contact. When this happens the corresponding event would notify
- * interested subscription listeners.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @param parent the group where the unresolved contact is
- * supposed to belong to.
- *
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(
- String address,
- String persistentData,
- ContactGroup parent)
- {
- ContactSSH contact = new ContactSSHImpl(
- address,
- parentProvider);
-
- contact.setPersistentData(persistentData);
- contact.startTimerTask();
-
- // SSH Contacts are resolved by default
- contact.setResolved(true);
-
- ( (ContactGroupSSHImpl) parent).addContact(contact);
-
- fireSubscriptionEvent(contact,
- parent,
- SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- //since we don't have any server, we'll simply resolve the contact
- //ourselves as if we've just received an event from the server telling
- //us that it has been resolved.
- fireSubscriptionEvent(
- contact, parent, SubscriptionEvent.SUBSCRIPTION_RESOLVED);
-
- return contact;
- }
-
- /**
- * Looks for a ssh protocol provider registered for a user id matching
- * <tt>sshUserID</tt>.
- *
- * @param sshUserID the ID of the SSH user whose corresponding
- * protocol provider we'd like to find.
- * @return ProtocolProviderServiceSSHImpl a ssh protocol
- * provider registered for a user with id <tt>sshUserID</tt> or null
- * if there is no such protocol provider.
- */
- public ProtocolProviderServiceSSHImpl
- findProviderForSSHUserID(String sshUserID)
- {
- BundleContext bc = SSHActivator.getBundleContext();
-
- String osgiQuery = "(&"
- + "(" + ProtocolProviderFactory.PROTOCOL
- + "=" + ProtocolNames.SSH + ")"
- + "(" + ProtocolProviderFactory.USER_ID
- + "=" + sshUserID + ")"
- + ")";
-
- ServiceReference[] refs = null;
- try
- {
- refs = bc.getServiceReferences(
- ProtocolProviderService.class.getName()
- ,osgiQuery);
- }
- catch (InvalidSyntaxException ex)
- {
- logger.error("Failed to execute the following osgi query: "
- + osgiQuery
- , ex);
- }
-
- if(refs != null && refs.length > 0)
- {
- return (ProtocolProviderServiceSSHImpl)bc.getService(refs[0]);
- }
-
- return null;
- }
-
- /**
- * Looks for ssh protocol providers that have added us to their
- * contact list and returns list of all contacts representing us in these
- * providers.
- *
- * @return a list of all contacts in other providers' contact lists that
- * point to us.
- */
- public List<Contact> findContactsPointingToUs()
- {
- List<Contact> contacts = new LinkedList<Contact>();
- BundleContext bc = SSHActivator.getBundleContext();
-
- String osgiQuery =
- "(" + ProtocolProviderFactory.PROTOCOL
- + "=SSH)";
-
- ServiceReference[] refs = null;
- try
- {
- refs = bc.getServiceReferences(
- ProtocolProviderService.class.getName()
- ,osgiQuery);
- }
- catch (InvalidSyntaxException ex)
- {
- logger.error("Failed to execute the following osgi query: "
- + osgiQuery
- , ex);
- }
-
- for (int i =0; refs != null && i < refs.length; i++)
- {
- ProtocolProviderServiceSSHImpl gibProvider
- = (ProtocolProviderServiceSSHImpl)bc.getService(refs[i]);
-
- OperationSetPersistentPresenceSSHImpl opSetPersPresence
- = (OperationSetPersistentPresenceSSHImpl)gibProvider
- .getOperationSet(OperationSetPersistentPresence.class);
-
- Contact contact = opSetPersPresence.findContactByID(
- parentProvider.getAccountID().getUserID());
-
- if (contact != null)
- contacts.add(contact);
- }
-
- return contacts;
- }
-
-
- /**
- * Creates and returns a unresolved contact group from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created
- * <tt>ContactGroup</tt> against the server or the contact itself. The
- * protocol provider will later resolve the contact group. When this happens
- * the corresponding event would notify interested subscription listeners.
- *
- * @param groupUID an identifier, returned by ContactGroup's getGroupUID,
- * that the protocol provider may use in order to create the group.
- * @param persistentData a String returned ContactGroups's
- * getPersistentData() method during a previous run and that has been
- * persistently stored locally.
- * @param parentGroup the group under which the new group is to be created
- * or null if this is group directly underneath the root.
- * @return the unresolved <tt>ContactGroup</tt> created from the specified
- * <tt>uid</tt> and <tt>persistentData</tt>
- */
- public ContactGroup createUnresolvedContactGroup(
- String groupUID,
- String persistentData,
- ContactGroup parentGroup)
- {
- ContactGroupSSHImpl newGroup
- = new ContactGroupSSHImpl(
- ContactGroupSSHImpl.createNameFromUID(groupUID)
- , parentProvider);
- newGroup.setResolved(false);
-
- //if parent is null then we're adding under root.
- if(parentGroup == null)
- parentGroup = getServerStoredContactListRoot();
-
- ((ContactGroupSSHImpl)parentGroup).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
-
- return newGroup;
- }
-
- private class UnregistrationListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenver
- * a change in the registration state of the corresponding provider had
- * occurred. The method is particularly interested in events stating
- * that the ssh provider has unregistered so that it would fire
- * status change events for all contacts in our buddy list.
- *
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
- if (! evt.getNewState().equals(RegistrationState.UNREGISTERED)
- && !evt.getNewState().equals(RegistrationState
- .AUTHENTICATION_FAILED)
- && !evt.getNewState().equals(RegistrationState.CONNECTION_FAILED))
- {
- return;
- }
-
- //send event notifications saying that all our buddies are
- //offline. The icq protocol does not implement top level buddies
- //nor subgroups for top level groups so a simple nested loop
- //would be enough.
- Iterator<ContactGroup> groupsIter
- = getServerStoredContactListRoot().subgroups();
- while (groupsIter.hasNext())
- {
- ContactGroup group = groupsIter.next();
- Iterator<Contact> contactsIter = group.contacts();
-
- while (contactsIter.hasNext())
- {
- ContactSSHImpl contact
- = (ContactSSHImpl) contactsIter.next();
-
- PresenceStatus oldContactStatus
- = contact.getPresenceStatus();
-
- if (!oldContactStatus.isOnline())
- continue;
-
- contact.setPresenceStatus(SSHStatusEnum.OFFLINE);
-
- fireContactPresenceStatusChangeEvent(
- contact
- , contact.getParentContactGroup()
- , oldContactStatus);
- }
- }
- }
- }
-
- /**
- * Returns the volatile group or null if this group has not yet been
- * created.
- *
- * @return a volatile group existing in our contact list or <tt>null</tt>
- * if such a group has not yet been created.
- */
- private ContactGroupSSHImpl getNonPersistentGroup()
- {
- for (int i = 0
- ; i < getServerStoredContactListRoot().countSubgroups()
- ; i++)
- {
- ContactGroupSSHImpl gr =
- (ContactGroupSSHImpl)getServerStoredContactListRoot()
- .getGroup(i);
-
- if(!gr.isPersistent())
- return gr;
- }
-
- return null;
- }
-
-
- /**
- * Creates a non persistent contact for the specified address. This would
- * also create (if necessary) a group for volatile contacts that would not
- * be added to the server stored contact list. This method would have no
- * effect on the server stored contact list.
- *
- * @param contactAddress the address of the volatile contact we'd like to
- * create.
- * @return the newly created volatile contact.
- */
- public ContactSSHImpl createVolatileContact(String contactAddress)
- {
- //First create the new volatile contact;
- ContactSSHImpl newVolatileContact = new ContactSSHImpl(
- contactAddress,
- this.parentProvider);
-
- newVolatileContact.setPersistent(false);
-
-
- //Check whether a volatile group already exists and if not create
- //one
- ContactGroupSSHImpl theVolatileGroup = getNonPersistentGroup();
-
-
- //if the parent volatile group is null then we create it
- if (theVolatileGroup == null)
- {
- theVolatileGroup = new ContactGroupSSHImpl(
- SSHActivator.getResources().getI18NString(
- "service.gui.NOT_IN_CONTACT_LIST_GROUP_NAME")
- , parentProvider);
- theVolatileGroup.setResolved(false);
- theVolatileGroup.setPersistent(false);
- theVolatileGroup.addContact(newVolatileContact);
-
- this.contactListRoot.addSubgroup(theVolatileGroup);
-
- fireServerStoredGroupEvent(theVolatileGroup
- , ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
- //now add the volatile contact instide it
- theVolatileGroup.addContact(newVolatileContact);
- fireSubscriptionEvent(newVolatileContact
- , theVolatileGroup
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- return newVolatileContact;
- }
-
- /**
- * DUMMY METHOD
- * Handler for incoming authorization requests.
- *
- * @param handler an instance of an AuthorizationHandler for
- * authorization requests coming from other users requesting
- * permission add us to their contact list.
- */
- public void setAuthorizationHandler(AuthorizationHandler handler)
- {
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolIconSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolIconSSHImpl.java
deleted file mode 100644
index 592b2b1..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolIconSSHImpl.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Represents the SSH protocol icon. Implements the <tt>ProtocolIcon</tt>
- * interface in order to provide a SSH logo image in two different sizes.
- *
- * @author Shobhit Jindal
- */
-public class ProtocolIconSSHImpl
- implements ProtocolIcon
-{
- private static Logger logger
- = Logger.getLogger(ProtocolIconSSHImpl.class);
-
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String, byte[]> iconsTable
- = new Hashtable<String, byte[]>();
- static {
- iconsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- getImageInBytes("service.protocol.ssh.SSH_16x16"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- getImageInBytes("service.protocol.ssh.SSH_32x32"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- getImageInBytes("service.protocol.ssh.SSH_48x48"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- getImageInBytes("service.protocol.ssh.SSH_64x64"));
- }
-
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String, String> iconPathsTable
- = new Hashtable<String, String>();
- static {
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- SSHActivator.getResources().getImagePath(
- "service.protocol.ssh.SSH_16x16"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- SSHActivator.getResources().getImagePath(
- "service.protocol.ssh.SSH_32x32"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- SSHActivator.getResources().getImagePath(
- "service.protocol.ssh.SSH_48x48"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- SSHActivator.getResources().getImagePath(
- "service.protocol.ssh.SSH_64x64"));
- }
-
- /**
- * Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns
- * an iterator to a set containing the supported icon sizes.
- * @return an iterator to a set containing the supported icon sizes
- */
- public Iterator<String> getSupportedSizes()
- {
- return iconsTable.keySet().iterator();
- }
-
- /**
- * Returns TRUE if a icon with the given size is supported, FALSE-otherwise.
- *
- * @return TRUE if a icon with the given size is supported, FALSE otherwise
- */
- public boolean isSizeSupported(String iconSize)
- {
- return iconsTable.containsKey(iconSize);
- }
-
- /**
- * Returns the icon image in the given size.
- * @param iconSize the icon size; one of ICON_SIZE_XXX constants
- * @return the icon
- */
- public byte[] getIcon(String iconSize)
- {
- return iconsTable.get(iconSize);
- }
-
- /**
- * Returns a path to the icon with the given size.
- * @param iconSize the size of the icon we're looking for
- * @return the path to the icon with the given size
- */
- public String getIconPath(String iconSize)
- {
- return iconPathsTable.get(iconSize);
- }
-
- /**
- * Returns the icon image used to represent the protocol connecting state.
- * @return the icon image used to represent the protocol connecting state
- */
- public byte[] getConnectingIcon()
- {
- return getImageInBytes("protocolIconSsh");
- }
-
- /**
- * Returns the byte representation of the image corresponding to the given
- * identifier.
- *
- * @param imageID the identifier of the image
- * @return the byte representation of the image corresponding to the given
- * identifier.
- */
- public static byte[] getImageInBytes(String imageID)
- {
- InputStream in = SSHActivator.getResources().
- getImageInputStream(imageID);
-
- if (in == null)
- return null;
- byte[] image = null;
- try
- {
- image = new byte[in.available()];
-
- in.read(image);
- }
- catch (IOException e)
- {
- logger.error("Failed to load image:" + imageID, e);
- }
-
- return image;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderFactorySSH.java b/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderFactorySSH.java
deleted file mode 100644
index 8c38f60..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderFactorySSH.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import net.java.sip.communicator.service.protocol.*;
-
-import org.osgi.framework.*;
-
-/**
- *
- * @author Shobhit Jindal
- */
-public abstract class ProtocolProviderFactorySSH
- extends ProtocolProviderFactory
-{
- /**
- * The name of a property representing the IDENTITY_FILE of the protocol for
- * a ProtocolProviderFactory.
- */
- public static final String IDENTITY_FILE = "IDENTITY_FILE";
-
- /**
- * The name of a property representing the KNOWN_HOSTS_FILE of the protocol
- * for a ProtocolProviderFactory.
- */
- public static final String KNOWN_HOSTS_FILE = "KNOWN_HOSTS_FILE";
-
- protected ProtocolProviderFactorySSH(BundleContext bundleContext,
- String protocolName)
- {
- super(bundleContext, protocolName);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderFactorySSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderFactorySSHImpl.java
deleted file mode 100644
index 68e33bc..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderFactorySSHImpl.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-import org.osgi.framework.*;
-
-/**
- * The SSH protocol provider factory creates instances of the SSH
- * protocol provider service. One Service instance corresponds to one account.
- *
- * @author Shobhit Jindal
- */
-public class ProtocolProviderFactorySSHImpl
- extends ProtocolProviderFactorySSH
-{
-
- /**
- * Creates an instance of the ProtocolProviderFactorySSHImpl.
- */
- public ProtocolProviderFactorySSHImpl()
- {
- super(SSHActivator.getBundleContext(), ProtocolNames.SSH);
- }
-
- /**
- * Initializaed and creates an account corresponding to the specified
- * accountProperties and registers the resulting ProtocolProvider in the
- * <tt>context</tt> BundleContext parameter.
- *
- * @param userIDStr tha/a user identifier uniquely representing the newly
- * created account within the protocol namespace.
- * @param accountProperties a set of protocol (or implementation)
- * specific properties defining the new account.
- * @return the AccountID of the newly created account.
- */
- @Override
- public AccountID installAccount(
- String userIDStr,
- Map<String, String> accountProperties)
- {
- BundleContext context = SSHActivator.getBundleContext();
- if (context == null)
- throw new NullPointerException("The specified BundleContext was " +
- "null");
-
- if (userIDStr == null)
- throw new NullPointerException("The specified AccountID was null");
-
- if (accountProperties == null)
- throw new NullPointerException("The specified property map was" +
- " null");
-
- accountProperties.put(USER_ID, userIDStr);
-
- AccountID accountID = new SSHAccountID(userIDStr, accountProperties);
-
- //make sure we haven't seen this account id before.
- if (registeredAccounts.containsKey(accountID))
- throw new IllegalStateException(
- "An account for id " + userIDStr + " was already" +
- " installed!");
-
- //first store the account and only then load it as the load generates
- //an osgi event, the osgi event triggers (through the UI) a call to the
- //ProtocolProviderService.register() method and it needs to acces
- //the configuration service and check for a stored password.
- this.storeAccount(accountID, false);
-
- accountID = loadAccount(accountProperties);
-
-/* ServiceReference ppServiceRef = context
- .getServiceReference(ProtocolProviderService.class.getName());
-
- ProtocolProviderService ppService = (ProtocolProviderService)
- context.getService(ppServiceRef);
-
- OperationSetPersistentPresence operationSetPersistentPresence =
- (OperationSetPersistentPresence) ppService.getOperationSet(
- OperationSetPersistentPresence.class);
-
- try
- {
- // The below should never fail for SSH accounts
- operationSetPersistentPresence.subscribe(userIDStr);
-
- }
- catch(OperationFailedException ex)
- {
- ex.printStackTrace();
- }
-*/
- return accountID;
- }
-
- @Override
- protected AccountID createAccountID(String userID, Map<String, String> accountProperties)
- {
- return new SSHAccountID(userID, accountProperties);
- }
-
- @Override
- protected ProtocolProviderService createService(String userID,
- AccountID accountID)
- {
- ProtocolProviderServiceSSHImpl service =
- new ProtocolProviderServiceSSHImpl();
-
- service.initialize(userID, accountID);
- return service;
- }
-
-// /**
-// * Saves the password for the specified account after scrambling it a bit
-// * so that it is not visible from first sight (Method remains highly
-// * insecure).
-// *
-// * @param accountID the AccountID for the account whose password we're
-// * storing.
-// * @param passwd the password itself.
-// *
-// * @throws java.lang.IllegalArgumentException if no account corresponding
-// * to <tt>accountID</tt> has been previously stored.
-// */
-// public void storePassword(AccountID accountID, String passwd)
-// throws IllegalArgumentException
-// {
-// super.storePassword(SSHActivator.getBundleContext(),
-// accountID,
-// String.valueOf(Base64.encode(passwd.getBytes())));
-// }
-//
-// /**
-// * Returns the password last saved for the specified account.
-// *
-// * @param accountID the AccountID for the account whose password we're
-// * looking for..
-// *
-// * @return a String containing the password for the specified accountID.
-// *
-// * @throws java.lang.IllegalArgumentException if no account corresponding
-// * to <tt>accountID</tt> has been previously stored.
-// */
-// public String loadPassword(AccountID accountID)
-// throws IllegalArgumentException
-// {
-// String password = super.loadPassword(SSHActivator.getBundleContext()
-// , accountID );
-// return(String.valueOf(Base64.decode(password)));
-// }
-
- @Override
- public void modifyAccount( ProtocolProviderService protocolProvider,
- Map<String, String> accountProperties)
- throws NullPointerException
- {
- // TODO Auto-generated method stub
-
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderServiceSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderServiceSSHImpl.java
deleted file mode 100644
index a4b16e6..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ProtocolProviderServiceSSHImpl.java
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.Logger;
-
-import org.osgi.framework.*;
-
-import com.jcraft.jsch.*;
-
-/**
- * A SSH implementation of the ProtocolProviderService.
- *
- * @author Shobhit Jindal
- */
-public class ProtocolProviderServiceSSHImpl
- extends AbstractProtocolProviderService
-{
- private static final Logger logger
- = Logger.getLogger(ProtocolProviderServiceSSHImpl.class);
-
- /**
- * The name of this protocol.
- */
- public static final String SSH_PROTOCOL_NAME = ProtocolNames.SSH;
-
-// /**
-// * The identifier for SSH Stack
-// * Java Secure Channel JSch
-// */
-// JSch jsch = new JSch();
-
- /**
- * The test command given after each command to determine the reply length
- * of the command
- */
- //private final String testCommand =
- // Resources.getString("testCommand");
-
- /**
- * A reference to the protocol provider of UIService
- */
- private static ServiceReference ppUIServiceRef;
-
- /**
- * Connection timeout to a remote server in milliseconds
- */
- private static int connectionTimeout = 30000;
-
- /**
- * A reference to UI Service
- */
- private static UIService uiService;
-
- /**
- * The id of the account that this protocol provider represents.
- */
- private AccountID accountID = null;
-
- /**
- * We use this to lock access to initialization.
- */
- private final Object initializationLock = new Object();
-
- private OperationSetBasicInstantMessagingSSHImpl basicInstantMessaging;
-
- private OperationSetFileTransferSSHImpl fileTranfer;
-
- /**
- * Indicates whether or not the provider is initialized and ready for use.
- */
- private boolean isInitialized = false;
-
- /**
- * The logo corresponding to the ssh protocol.
- */
- private ProtocolIconSSHImpl sshIcon
- = new ProtocolIconSSHImpl();
-
- /**
- * The registration state of SSH Provider is taken to be registered by
- * default as it doesn't correspond to the state on remote server
- */
- private RegistrationState currentRegistrationState
- = RegistrationState.REGISTERED;
-
- /**
- * The default constructor for the SSH protocol provider.
- */
- public ProtocolProviderServiceSSHImpl()
- {
- if (logger.isTraceEnabled())
- logger.trace("Creating a ssh provider.");
-
- try
- {
- // converting to milliseconds
- connectionTimeout = Integer.parseInt(Resources.getString(
- "connectionTimeout")) * 1000;
- }
- catch(NumberFormatException ex)
- {
- logger.error("Connection Timeout set to 30 seconds");
- }
- }
-
- /**
- * Initializes the service implementation, and puts it in a sate where it
- * could interoperate with other services. It is strongly recomended that
- * properties in this Map be mapped to property names as specified by
- * <tt>AccountProperties</tt>.
- *
- * @param userID the user id of the ssh account we're currently
- * initializing
- * @param accountID the identifier of the account that this protocol
- * provider represents.
- *
- * @see net.java.sip.communicator.service.protocol.AccountID
- */
- protected void initialize(
- String userID,
- AccountID accountID)
- {
- synchronized(initializationLock)
- {
- this.accountID = accountID;
-
- //initialize the presence operationset
- OperationSetPersistentPresenceSSHImpl persistentPresence =
- new OperationSetPersistentPresenceSSHImpl(this);
-
- addSupportedOperationSet(
- OperationSetPersistentPresence.class,
- persistentPresence);
- //register it once again for those that simply need presence and
- //won't be smart enough to check for a persistent presence
- //alternative
- addSupportedOperationSet(
- OperationSetPresence.class,
- persistentPresence);
-
- //initialize the IM operation set
- basicInstantMessaging = new
- OperationSetBasicInstantMessagingSSHImpl(
- this);
- addSupportedOperationSet(
- OperationSetBasicInstantMessaging.class,
- basicInstantMessaging);
-
- //initialze the file transfer operation set
- fileTranfer = new OperationSetFileTransferSSHImpl(this);
- addSupportedOperationSet(
- OperationSetFileTransfer.class,
- fileTranfer);
-
- isInitialized = true;
- }
- }
-
- /**
- * Determines whether a vaild session exists for the contact of remote
- * machine.
- *
- * @param sshContact ID of SSH Contact
- *
- * @return <tt>true</tt> if the session is connected
- * <tt>false</tt> otherwise
- */
- public boolean isSessionValid(ContactSSH sshContact)
- {
- Session sshSession = sshContact.getSSHSession();
- if( sshSession != null)
- if(sshSession.isConnected())
- return true;
-
- // remove reference to an unconnected SSH Session, if any
- sshContact.setSSHSession(null);
- return false;
- }
-
- /**
- * Determines whether the contact is connected to shell of remote machine
- * as a precheck for any further operation
- *
- * @param sshContact ID of SSH Contact
- *
- * @return <tt>true</tt> if the contact is connected
- * <tt>false</tt> if the contact is not connected
- */
- public boolean isShellConnected(ContactSSH sshContact)
- {
- // a test command may also be run here
-
- if(isSessionValid(sshContact))
- {
- return(sshContact.getShellChannel() != null);
- }
-
- /*
- * Above should be return(sshContact.getShellChannel() != null
- * && sshContact.getShellChannel().isConnected());
- *
- * but incorrect reply from stack for isConnected()
- */
-
- return false;
- }
-
- /**
- * Creates a shell channel to the remote machine
- * a new jsch session is also created if the current one is invalid
- *
- * @param sshContact the contact of the remote machine
- * @param firstMessage the first message
- */
- public void connectShell(
- final ContactSSH sshContact,
- final Message firstMessage)
- {
- sshContact.setConnectionInProgress(true);
-
- final Thread newConnection = new Thread((new Runnable()
- {
- public void run()
- {
- OperationSetPersistentPresenceSSHImpl persistentPresence
- = (OperationSetPersistentPresenceSSHImpl)sshContact
- .getParentPresenceOperationSet();
-
- persistentPresence.changeContactPresenceStatus(
- sshContact,
- SSHStatusEnum.CONNECTING);
-
- try
- {
- if(!isSessionValid(sshContact))
- createSSHSessionAndLogin(sshContact);
-
- createShellChannel(sshContact);
-
- //initializing the reader and writers of ssh contact
-
- persistentPresence.changeContactPresenceStatus(
- sshContact,
- SSHStatusEnum.CONNECTED);
-
- showWelcomeMessage(sshContact);
-
- sshContact.setMessageType(ContactSSH
- .CONVERSATION_MESSAGE_RECEIVED);
-
- sshContact.setConnectionInProgress(false);
-
- Thread.sleep(1500);
-
- sshContact.setCommandSent(true);
-
- basicInstantMessaging.sendInstantMessage(
- sshContact,
- firstMessage);
- }
- // rigorous Exception Checking in future
- catch (Exception ex)
- {
- persistentPresence.changeContactPresenceStatus(
- sshContact,
- SSHStatusEnum.NOT_AVAILABLE);
-
- ex.printStackTrace();
- }
- finally
- {
- sshContact.setConnectionInProgress(false);
- }
- }
- }));
-
- newConnection.start();
- }
-
- /**
- * Creates a channel for shell type in the current session
- * channel types = shell, sftp, exec(X forwarding),
- * direct-tcpip(stream forwarding) etc
- *
- * @param sshContact ID of SSH Contact
- * @throws IOException if the shell channel cannot be created
- */
- public void createShellChannel(ContactSSH sshContact)
- throws IOException
- {
- try
- {
- Channel shellChannel = sshContact.getSSHSession()
- .openChannel("shell");
-
- //initalizing the reader and writers of ssh contact
- sshContact.initializeShellIO(shellChannel.getInputStream(),
- shellChannel.getOutputStream());
-
- ((ChannelShell)shellChannel).setPtyType(
- sshContact.getSSHConfigurationForm().getTerminalType());
-
- //initializing the shell
- shellChannel.connect(1000);
-
- sshContact.setShellChannel(shellChannel);
-
- sshContact.sendLine("export PS1=");
- }
- catch (JSchException ex)
- {
- sshContact.setSSHSession(null);
- throw new IOException("Unable to create shell channel to remote" +
- " server");
- }
- }
-
- /**
- * Closes the Shell channel are associated IO Streams
- *
- * @param sshContact ID of SSH Contact
- * @throws JSchException if something went wrong in JSch
- * @throws IOException if I/O exception occurred
- */
- public void closeShellChannel(ContactSSH sshContact) throws
- JSchException,
- IOException
- {
- sshContact.closeShellIO();
- sshContact.getShellChannel().disconnect();
- sshContact.setShellChannel(null);
- }
-
- /**
- * Creates a SSH Session with a remote machine and tries to login
- * according to the details specified by Contact
- * An appropriate message is shown to the end user in case the login fails
- *
- * @param sshContact ID of SSH Contact
- *
- * @throws JSchException if a JSch is unable to create a SSH Session with
- * the remote machine
- * @throws InterruptedException if the thread is interrupted before session
- * connected or is timed out
- * @throws OperationFailedException if not of above reasons :-)
- */
- public void createSSHSessionAndLogin(ContactSSH sshContact) throws
- JSchException,
- OperationFailedException,
- InterruptedException
- {
- if (logger.isInfoEnabled())
- logger.info("Creating a new SSH Session to "
- + sshContact.getHostName());
-
- // creating a new JSch Stack identifier for contact
- JSch jsch = new JSch();
-
- String knownHosts =
- accountID.getAccountPropertyString("KNOWN_HOSTS_FILE");
-
- if(!knownHosts.equals("Optional"))
- jsch.setKnownHosts(knownHosts);
-
- String identitiyKey =
- accountID.getAccountPropertyString("IDENTITY_FILE");
-
- String userName = sshContact.getUserName();
-
- // use the name of system user if the contact has not supplied SSH
- // details
- if(userName.equals(""))
- userName = System.getProperty("user.name");
-
- if(!identitiyKey.equals("Optional"))
- jsch.addIdentity(identitiyKey);
-
- // creating a new session for the contact
- Session session = jsch.getSession(
- userName,
- sshContact.getHostName(),
- sshContact.getSSHConfigurationForm().getPort());
-
- /**
- * Creating and associating User Info with the session
- * User Info passes authentication from sshContact to SSH Stack
- */
- SSHUserInfo sshUserInfo = new SSHUserInfo(sshContact);
-
- session.setUserInfo(sshUserInfo);
-
- /**
- * initializing the session
- */
- session.connect(connectionTimeout);
-
- int count = 0;
-
- // wait for session to get connected
- while(!session.isConnected() && count<=30000)
- {
- Thread.sleep(1000);
- count += 1000;
- if (logger.isTraceEnabled())
- logger.trace("SSH:" + sshContact.getHostName()
- + ": Sleep zzz .. " );
- }
-
- // if timeout have exceeded
- if(count>30000)
- {
- sshContact.setSSHSession(null);
- JOptionPane.showMessageDialog(
- null,
- "SSH Connection attempt to "
- + sshContact.getHostName() + " timed out");
-
- // error codes are not defined yet
- throw new OperationFailedException("SSH Connection attempt to " +
- sshContact.getHostName() + " timed out", 2);
- }
-
- sshContact.setJSch(jsch);
- sshContact.setSSHSession(session);
-
- if (logger.isInfoEnabled())
- logger.info("A new SSH Session to " + sshContact.getHostName()
- + " Created");
- }
-
- /**
- * Closes the SSH Session associated with the contact
- *
- * @param sshContact ID of SSH Contact
- */
- void closeSSHSession(ContactSSH sshContact)
- {
- sshContact.getSSHSession().disconnect();
- sshContact.setSSHSession(null);
- }
-
- /**
- * Presents the login welcome message to user
- *
- * @param sshContact ID of SSH Contact
- * @throws IOException if I/O exception occurred
- */
- public void showWelcomeMessage(ContactSSH sshContact)
- throws IOException
- {
-/* //sending the command
- sshContact.sendLine(testCommand);
-
- String reply = "", line = "";
-
- // message is extracted until the test Command ie echoed back
- while(line.indexOf(testCommand) == -1)
- {
- reply += line + "\n";
- line = sshContact.getLine();
- }
-
- uiService.getPopupDialog().showMessagePopupDialog
- (reply,"Message from " + sshContact.getDisplayName(),
- uiService.getPopupDialog().INFORMATION_MESSAGE);
-
- if(line.startsWith(testCommand))
- while(!sshContact.getLine().contains(testCommand));
-
- //one line output of testCommand
- sshContact.getLine();
-*/
- if (logger.isDebugEnabled())
- logger.debug("SSH: Welcome message shown");
- }
-
- /**
- * Returns a reference to UIServce for accessing UI related services
- *
- * @return uiService a reference to UIService
- */
- public static UIService getUIService()
- {
- return uiService;
- }
-
- /**
- * Returns the AccountID that uniquely identifies the account represented
- * by this instance of the ProtocolProviderService.
- *
- * @return the id of the account represented by this provider.
- */
- public AccountID getAccountID()
- {
- return accountID;
- }
-
- /**
- * Returns the short name of the protocol that the implementation of this
- * provider is based upon (like SIP, Jabber, ICQ/AIM, or others for
- * example).
- *
- * @return a String containing the short name of the protocol this
- * service is implementing (most often that would be a name in
- * ProtocolNames).
- */
- public String getProtocolName()
- {
- return SSH_PROTOCOL_NAME;
- }
-
- /**
- * Returns the state of the registration of this protocol provider with
- * the corresponding registration service.
- *
- * @return ProviderRegistrationState
- */
- public RegistrationState getRegistrationState()
- {
- return currentRegistrationState;
- }
-
- /**
- * Starts the registration process.
- *
- * @param authority the security authority that will be used for
- * resolving any security challenges that may be returned during the
- * registration or at any moment while wer're registered.
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void register(SecurityAuthority authority)
- throws OperationFailedException
- {
- RegistrationState oldState = currentRegistrationState;
- currentRegistrationState = RegistrationState.REGISTERED;
-
- //get a reference to UI Service via its Service Reference
- ppUIServiceRef = SSHActivator.getBundleContext()
- .getServiceReference(UIService.class.getName());
-
- uiService = (UIService)SSHActivator.getBundleContext()
- .getService(ppUIServiceRef);
-
- fireRegistrationStateChanged(
- oldState
- , currentRegistrationState
- , RegistrationStateChangeEvent.REASON_USER_REQUEST
- , null);
-
- }
-
- /**
- * Makes the service implementation close all open sockets and release
- * any resources that it might have taken and prepare for
- * shutdown/garbage collection.
- */
- public void shutdown()
- {
- if(!isInitialized)
- {
- return;
- }
- if (logger.isTraceEnabled())
- logger.trace("Killing the SSH Protocol Provider.");
-
- if(isRegistered())
- {
- try
- {
- //do the unregistration
- unregister();
- }
- catch (OperationFailedException ex)
- {
- //we're shutting down so we need to silence the exception here
- logger.error(
- "Failed to properly unregister before shutting down. "
- + getAccountID()
- , ex);
- }
- }
-
- isInitialized = false;
- }
-
- /**
- * Ends the registration of this protocol provider with the current
- * registration service.
- *
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void unregister()
- throws OperationFailedException
- {
- RegistrationState oldState = currentRegistrationState;
- currentRegistrationState = RegistrationState.UNREGISTERED;
-
- fireRegistrationStateChanged(
- oldState
- , currentRegistrationState
- , RegistrationStateChangeEvent.REASON_USER_REQUEST
- , null);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see net.java.sip.communicator.service.protocol.ProtocolProviderService#
- * isSignallingTransportSecure()
- */
- public boolean isSignalingTransportSecure()
- {
- return false;
- }
-
- /**
- * Returns the "transport" protocol of this instance used to carry the
- * control channel for the current protocol service.
- *
- * @return The "transport" protocol of this instance: TCP.
- */
- public TransportProtocol getTransportProtocol()
- {
- return TransportProtocol.TCP;
- }
-
- /**
- * Returns the ssh protocol icon.
- * @return the ssh protocol icon
- */
- public ProtocolIcon getProtocolIcon()
- {
- return sshIcon;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/Resources.java b/src/net/java/sip/communicator/impl/protocol/ssh/Resources.java
deleted file mode 100644
index 48b9b49..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/Resources.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import net.java.sip.communicator.service.resources.*;
-
-/**
- * @author Shobhit Jindal
- */
-public class Resources
-{
- /**
- * The SSH logo imageID.
- */
- public static ImageID SSH_LOGO = new ImageID("protocolIconSsh");
-
- /**
- * Returns an string corresponding to the given key.
- *
- * @param key The key of the string.
- *
- * @return a string corresponding to the given key.
- */
- public static String getString(String key)
- {
- return SSHActivator.getResources().getI18NString(key);
- }
-
- /**
- * Loads an image from a given image identifier.
- * @param imageID The identifier of the image.
- * @return The image for the given identifier.
- */
- public static byte[] getImage(ImageID imageID)
- {
- return SSHActivator.getResources().getImageInBytes(imageID.getId());
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/SSHAccountID.java b/src/net/java/sip/communicator/impl/protocol/ssh/SSHAccountID.java
deleted file mode 100644
index 8f9dda7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/SSHAccountID.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The SSH implementation of a sip-communicator account id.
- * @author Shobhit Jindal
- */
-public class SSHAccountID
- extends AccountID
-{
- /**
- * Creates an account id from the specified id and account properties.
- *
- * @param userID the user identifier correspnding to thi account
- * @param accountProperties any other properties necessary for the account.
- */
- SSHAccountID(String userID, Map<String, String> accountProperties)
- {
- super(userID
- , accountProperties
- , "SSH"
- , "sip-communicator.org");
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/SSHActivator.java b/src/net/java/sip/communicator/impl/protocol/ssh/SSHActivator.java
deleted file mode 100644
index 7108020..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/SSHActivator.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.resources.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.resources.*;
-import org.osgi.framework.*;
-
-/**
- * Loads the SSH provider factory and registers its services in the OSGI
- * bundle context.
- *
- * @author Shobhit Jindal
- */
-public class SSHActivator
- implements BundleActivator
-{
- private static final Logger logger
- = Logger.getLogger(SSHActivator.class);
-
- /**
- * A reference to the registration of our SSH protocol provider
- * factory.
- */
- private ServiceRegistration sshPpFactoryServReg = null;
-
- /**
- * A reference to the SSH protocol provider factory.
- */
- private static ProtocolProviderFactorySSHImpl
- sshProviderFactory = null;
-
- /**
- * The currently valid bundle context.
- */
- private static BundleContext bundleContext = null;
-
- private static ResourceManagementService resourcesService;
-
- /**
- * Called when this bundle is started. In here we'll export the
- * ssh ProtocolProviderFactory implementation so that it could be
- * possible to register accounts with it in SIP Communicator.
- *
- * @param context The execution context of the bundle being started.
- * @throws Exception If this method throws an exception, this bundle is
- * marked as stopped and the Framework will remove this bundle's
- * listeners, unregister all services registered by this bundle, and
- * release all services used by this bundle.
- */
- public void start(BundleContext context)
- throws Exception
- {
- bundleContext = context;
-
- Hashtable<String, String> hashtable = new Hashtable<String, String>();
- hashtable.put(ProtocolProviderFactory.PROTOCOL, "SSH");
-
- sshProviderFactory = new ProtocolProviderFactorySSHImpl();
-
- //reg the ssh provider factory.
- sshPpFactoryServReg = context.registerService(
- ProtocolProviderFactory.class.getName(),
- sshProviderFactory,
- hashtable);
-
- if (logger.isInfoEnabled())
- logger.info("SSH protocol implementation [STARTED].");
- }
-
- /**
- * Returns a reference to the bundle context that we were started with.
- * @return bundleContext a reference to the BundleContext instance
- * that we were started with.
- */
- public static BundleContext getBundleContext()
- {
- return bundleContext;
- }
-
- /**
- * Retrurns a reference to the protocol provider factory that we have
- * registered.
- * @return a reference to the <tt>ProtocolProviderFactoryJabberImpl</tt>
- * instance that we have registered from this package.
- */
- public static ProtocolProviderFactorySSHImpl
- getProtocolProviderFactory()
- {
- return sshProviderFactory;
- }
-
-
- /**
- * Called when this bundle is stopped so the Framework can perform the
- * bundle-specific activities necessary to stop the bundle.
- *
- * @param context The execution context of the bundle being stopped.
- * @throws Exception If this method throws an exception, the bundle is
- * still marked as stopped, and the Framework will remove the bundle's
- * listeners, unregister all services registered by the bundle, and
- * release all services used by the bundle.
- */
- public void stop(BundleContext context)
- throws Exception
- {
- sshProviderFactory.stop();
- sshPpFactoryServReg.unregister();
- if (logger.isInfoEnabled())
- logger.info("SSH protocol implementation [STOPPED].");
- }
-
- /**
- * Returns the <tt>ResourceManagementService</tt>.
- *
- * @return the <tt>ResourceManagementService</tt>.
- */
- public static ResourceManagementService getResources()
- {
- if (resourcesService == null)
- resourcesService =
- ResourceManagementServiceUtils.getService(bundleContext);
- return resourcesService;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/SSHContactInfo.java b/src/net/java/sip/communicator/impl/protocol/ssh/SSHContactInfo.java
deleted file mode 100644
index 47bb484..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/SSHContactInfo.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.text.*;
-
-import javax.swing.*;
-import javax.swing.text.*;
-
-import net.java.sip.communicator.plugin.desktoputil.*;
-
-/**
- * @author Shobhit Jindal
- */
-class SSHContactInfo
- extends SIPCommDialog
-{
- /**
- * Serial version UID.
- */
- private static final long serialVersionUID = 0L;
-
- private ContactSSH sshContact;
-
- private JPanel mainPanel = new TransparentPanel();
- private JPanel machinePanel = new TransparentPanel();
- private JPanel detailNamesPanel = new TransparentPanel();
- private JPanel detailFieldsPanel = new TransparentPanel();
- private JPanel detailsPanel = new TransparentPanel();
-
- private JCheckBox addDetailsCheckBox = new SIPCommCheckBox("Add Details");
-
- private JButton doneButton = new JButton("Done");
- private JLabel machineID = new JLabel("Hostname / IP: ");
- private JTextField machineIDField = new JTextField();
- private JLabel userName = new JLabel("User Name: ");
- private JTextField userNameField = new JTextField();
- private JLabel password = new JLabel("Password: ");
- private JTextField passwordField = new JPasswordField();
- private JLabel port = new JLabel("Port: ");
-
- private JFormattedTextField portField;
- private JLabel secs = new JLabel("secs");
- private JLabel statusUpdate = new JLabel("Update Interval: ");
- private JLabel terminalType = new JLabel("Terminal Type: ");
- private JTextField terminalTypeField = new JTextField("SIP Communicator");
- private JSpinner updateTimer = new JSpinner();
-
- private JPanel emptyPanel1 = new TransparentPanel();
-
- private JPanel emptyPanel2 = new TransparentPanel();
-
- private JPanel emptyPanel3 = new TransparentPanel();
-
- private JPanel emptyPanel4 = new TransparentPanel();
-
- private JPanel emptyPanel5 = new TransparentPanel();
-
- private JPanel emptyPanel6 = new TransparentPanel();
-
- private JPanel emptyPanel7 = new TransparentPanel();
-
- private JPanel emptyPanel8 = new TransparentPanel();
-
- private JPanel emptyPanel9 = new TransparentPanel();
-
- private JPanel emptyPanel10 = new TransparentPanel();
-
- private JPanel emptyPanel11 = new TransparentPanel();
-
-// private ContactGroup contactGroup = null;
-
- /**
- * Creates a new instance of SSHContactInfo
- *
- * @param sshContact the concerned contact
- */
- public SSHContactInfo(ContactSSH sshContact) {
- super(true);
-
- this.sshContact = sshContact;
- initForm();
-
- this.getContentPane().add(mainPanel);
-
- this.setSize(370, 325);
-
- this.setResizable(false);
-
- this.setTitle("SSH: Account Details of " + sshContact.getDisplayName());
-
- Toolkit toolkit = Toolkit.getDefaultToolkit();
- Dimension screenSize = toolkit.getScreenSize();
-
- int x = (screenSize.width - this.getWidth()) / 2;
- int y = (screenSize.height - this.getHeight()) / 2;
-
- this.setLocation(x,y);
-
-// ProtocolProviderServiceSSHImpl.getUIService().getConfigurationWindow().
-// addConfigurationForm(this);
- }
-
- /**
- * initialize the form.
- */
- public void initForm() {
- updateTimer.setValue(30);
- MaskFormatter maskFormatter = new MaskFormatter();
- try {
- maskFormatter.setMask("#####");
- } catch (ParseException ex) {
- ex.printStackTrace();
- }
- maskFormatter.setAllowsInvalid(false);
- portField = new JFormattedTextField(maskFormatter);
- portField.setValue(22);
-
- userNameField.setEnabled(false);
- passwordField.setEditable(false);
- portField.setEnabled(false);
- terminalTypeField.setEnabled(false);
- updateTimer.setEnabled(false);
-
- mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
- machinePanel.setLayout(new BoxLayout(machinePanel, BoxLayout.X_AXIS));
- detailNamesPanel.setLayout(new BoxLayout(detailNamesPanel,
- BoxLayout.Y_AXIS));
- detailFieldsPanel.setLayout(new BoxLayout(detailFieldsPanel,
- BoxLayout.Y_AXIS));
- detailsPanel.setLayout(new BoxLayout(detailsPanel, BoxLayout.X_AXIS));
-
- machinePanel.add(machineID);
- machinePanel.add(machineIDField);
-
- detailNamesPanel.add(userName);
- detailNamesPanel.add(emptyPanel1);
- detailNamesPanel.add(password);
- detailNamesPanel.add(emptyPanel2);
- detailNamesPanel.add(port);
- detailNamesPanel.add(emptyPanel3);
- detailNamesPanel.add(statusUpdate);
- detailNamesPanel.add(emptyPanel4);
- detailNamesPanel.add(terminalType);
-
- detailFieldsPanel.add(userNameField);
- detailFieldsPanel.add(emptyPanel5);
- detailFieldsPanel.add(passwordField);
- detailFieldsPanel.add(emptyPanel6);
- detailFieldsPanel.add(portField);
- detailFieldsPanel.add(emptyPanel7);
- detailFieldsPanel.add(updateTimer);
- detailFieldsPanel.add(emptyPanel8);
- detailFieldsPanel.add(terminalTypeField);
-
- detailsPanel.add(detailNamesPanel);
- detailsPanel.add(detailFieldsPanel);
-
- detailsPanel.setBorder(BorderFactory.createTitledBorder("Details"));
-
- mainPanel.add(emptyPanel9);
- mainPanel.add(machinePanel);
- mainPanel.add(addDetailsCheckBox);
- mainPanel.add(detailsPanel);
- mainPanel.add(emptyPanel10);
- mainPanel.add(doneButton);
- mainPanel.add(emptyPanel11);
-
- addDetailsCheckBox.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent event) {
- addDetailsCheckBox.setEnabled(false);
- userNameField.setEnabled(true);
- passwordField.setEditable(true);
- portField.setEnabled(true);
- terminalTypeField.setEnabled(true);
- updateTimer.setEnabled(true);
-
- userNameField.grabFocus();
- }
- });
-
- doneButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent event) {
- if(machineIDField.getText().equals("")) {
- machineIDField.setText("Field needed");
- return;
- }
-
- sshContact.savePersistentDetails();
-
- //add contact to contact list
- ((OperationSetPersistentPresenceSSHImpl)sshContact
- .getParentPresenceOperationSet())
- .addContactToList(
- sshContact.getParentContactGroup(),
- sshContact);
-
- setVisible(false);
- }
- });
- }
-
- /**
- * Return the ssh icon
- *
- * @return the ssh icon
- */
- public byte[] getIcon() {
- return Resources.getImage(Resources.SSH_LOGO);
- }
-
-//
-// public void setContactGroup(ContactGroup contactGroup)
-// {
-// this.contactGroup = contactGroup;
-// }
-//
-// public ContactGroup getContactGroup()
-// {
-// return this.contactGroup;
-// }
-
- /**
- * Sets the UserName of the dialog
- *
- * @param userName to be associated
- */
- public void setUserNameField(String userName) {
- this.userNameField.setText(userName);
- }
-
- /**
- * Sets the Password of the dialog
- *
- * @param password to be associated
- */
- public void setPasswordField(String password) {
- this.passwordField.setText(password);
- }
-
- /**
- * Return the hostname
- *
- * @return the hostname
- */
- public String getHostName() {
- return this.machineIDField.getText();
- }
-
- /**
- * Return the username
- *
- * @return the username
- */
- public String getUserName() {
- return this.userNameField.getText();
- }
-
- /**
- * Return the password
- *
- * @return the password in a clear form
- */
- public String getPassword() {
- return this.passwordField.getText();
- }
-
- /**
- * Return the terminal type
- *
- * @return the terminal type
- */
- public String getTerminalType() {
- return this.terminalTypeField.getText();
- }
-
- /**
- * Return the port
- *
- * @return the port value
- */
- public int getPort() {
- return Integer.parseInt(this.portField.getText().trim());
- }
-
- /**
- * Return the update interval
- *
- * @return the update interval
- */
- public int getUpdateInterval() {
- return Integer.parseInt(String.valueOf(this.updateTimer.getValue()));
- }
-
- /**
- * Sets the HostName of the dialog
- *
- * @param hostName to be associated
- */
- public void setHostNameField(String hostName) {
- this.machineIDField.setText(hostName);
- }
-
- /**
- * Sets the Terminal Type of the dialog
- *
- * @param termType to be associated
- */
- public void setTerminalType(String termType) {
- this.terminalTypeField.setText(termType);
- }
-
- /**
- * Sets the Update Interval of the dialog
- *
- * @param interval to be associated
- */
- public void setUpdateInterval(int interval) {
- this.updateTimer.setValue(interval);
- }
-
- /**
- * Sets the Port of the dialog
- *
- * @param port to be associated
- */
- public void setPort(String port) {
- this.portField.setText(port);
- }
-
- @Override
- protected void close(boolean isEscaped)
- {
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/SSHFileTransferDaemon.java b/src/net/java/sip/communicator/impl/protocol/ssh/SSHFileTransferDaemon.java
deleted file mode 100644
index 3b522ed..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/SSHFileTransferDaemon.java
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.Logger;
-
-import com.jcraft.jsch.*;
-
-/**
- * @author Shobhit Jindal
- */
-public class SSHFileTransferDaemon
- extends Thread
-{
- private static final Logger logger =
- Logger.getLogger(SSHFileTransferDaemon .class);
-
- /**
- * The contact of the remote machine
- */
- private ContactSSH sshContact;
-
- /**
- * The currently valid ssh protocol provider
- */
- private ProtocolProviderServiceSSHImpl ppService;
-
- /**
- * JSch Channel to be used for file transfer
- */
- private Channel fileTransferChannel;
-
- /**
- * The identifier for the Input Stream associated with SCP Channel
- */
- private InputStream scpInputStream = null;
-
- /**
- * The identifier for the Output Stream associated with SCP Channel
- */
- private OutputStream scpOutputStream = null;
-
- /**
- * Identifier of local file
- */
- private String localPath;
-
- /**
- * Identifier of remote file
- */
- private String remotePath;
-
- /**
- * File to be uploaded or saved
- */
- private File file;
-
- /**
- * The file input stream associated with the file to be uploaded
- */
- private FileInputStream fileInputStream;
-
- /**
- * The file output stream associated with the file to be uploaded
- */
- private FileOutputStream fileOutputStream;
-
- /**
- * The boolean which determines whether we are uploading or downloading
- * files
- */
- private boolean uploadFile;
-
- /**
- * The currently valid ssh persistent presence operation set
- */
- private OperationSetPersistentPresenceSSHImpl opSetPersPresence = null;
-
- /**
- * The currently valid ssh instant messaging operation set
- */
- private OperationSetBasicInstantMessagingSSHImpl instantMessaging = null;
-
- /**
- * Creates a new instance of SSHFileTransferDaemon
- *
- *
- * @param sshContact The contact of the remote machine
- * @param ppService The current ssh protocol provider
- */
- public SSHFileTransferDaemon(
- ContactSSH sshContact,
- ProtocolProviderServiceSSHImpl ppService)
- {
- super();
- this.sshContact = sshContact;
- this.opSetPersPresence = (OperationSetPersistentPresenceSSHImpl)
- ppService.getOperationSet(OperationSetPersistentPresence.class);
- this.instantMessaging = (OperationSetBasicInstantMessagingSSHImpl)
- ppService.getOperationSet(
- OperationSetBasicInstantMessaging.class);
- this.ppService = ppService;
- }
-
- /**
- * This method is called when file is to be transfered from local machine
- * to remote machine
- *
- * @param remotePath - the identifier for the remote file
- * @param localPath - the identifier for the local file
- */
- public void uploadFile(
- String remotePath,
- String localPath)
- {
- this.uploadFile = true;
- this.remotePath = remotePath;
- this.localPath = localPath;
-
- file = new File(localPath);
-
- start();
- }
-
- /**
- * This method is called when a file is to be downloaded from remote machine
- * to local machine
- *
- * @param remotePath - the identifier for the remote file
- * @param localPath - the identifier for the local file
- */
- public void downloadFile(
- String remotePath,
- String localPath)
- {
- this.uploadFile = false;
- this.remotePath = remotePath;
- this.localPath = localPath;
-
- file = new File(localPath);
-
- start();
- }
-
- /**
- * Background thread for the file transfer
- */
- @Override
- public void run()
- {
- //oldStatus to be resumed earlier
- PresenceStatus oldStatus = sshContact.getPresenceStatus();
-
- opSetPersPresence.changeContactPresenceStatus(
- sshContact,
- SSHStatusEnum.CONNECTING);
-
- try
- {
- //create a new JSch session if current is invalid
- if( !ppService.isSessionValid(sshContact))
- ppService.createSSHSessionAndLogin(sshContact);
-
- fileTransferChannel = sshContact.getSSHSession()
- .openChannel("exec");
- String command;
-
- // -p = Preserves modification times, access times, and modes from
- // the original file
- if(uploadFile)
- command = "scp -p -t " + remotePath;
- else
- command = "scp -f " + remotePath;
-
- //the command to be executed on the remote terminal
- ((ChannelExec)fileTransferChannel).setCommand(command);
-
- scpInputStream = fileTransferChannel.getInputStream();
- scpOutputStream = fileTransferChannel.getOutputStream();
-
- fileTransferChannel.connect();
-
- //file transfer is setup
- opSetPersPresence.changeContactPresenceStatus(
- sshContact,
- SSHStatusEnum.FILE_TRANSFER);
-
- if(uploadFile)
- {
- instantMessaging.deliverMessage(
- instantMessaging.createMessage(
- "Uploading " + file.getName() + " to server"),
- sshContact);
-
- upload();
- }
- else
- {
- instantMessaging.deliverMessage(
- instantMessaging.createMessage(
- "Downloading " + file.getName() + " from server"),
- sshContact);
-
- download();
- }
-
- }
- catch(Exception ex)
- {
- //presently errors(any type) are directly logged directly in chat
- instantMessaging.deliverMessage(
- instantMessaging.createMessage(ex.getMessage()),
- sshContact);
-
- logger.error(ex.getMessage());
-
- try
- {
- if(fileInputStream!=null)
- {
- fileInputStream.close();
- }
-
- if(fileOutputStream!=null)
- {
- fileOutputStream.close();
- }
- }
- catch(Exception e)
- {}
- }
-
- // restore old status
- opSetPersPresence.changeContactPresenceStatus(
- sshContact,
- oldStatus);
- }
-
- /**
- * Check for error in reading stream of remote machine
- *
- * @return 0 for success, 1 for error, 2 for fatal error, -1 otherwise
- * @throws IOException when the network goes down
- */
- private int checkAck(InputStream inputStream)
- throws IOException
- {
- int result = inputStream.read();
-
- // read error message
- if(result==1 || result==2)
- {
- StringBuffer buffer = new StringBuffer();
-
- int ch;
-
- do
- {
- //read a line of message
- ch = inputStream.read();
- buffer.append((char)ch);
-
- }while(ch != '\n');
-
- ProtocolProviderServiceSSHImpl
- .getUIService()
- .getPopupDialog()
- .showMessagePopupDialog(
- buffer.toString(),
- "File Transfer Error: "
- + sshContact.getDisplayName(),
- PopupDialog.ERROR_MESSAGE);
-
- logger.error(buffer.toString());
- }
-
- return result;
- }
-
- /**
- * Uploads the file to the remote server
- *
- * @throws IOException when the network goes down
- * @throws OperationFailedException when server behaves unexpectedly
- */
- private void upload()
- throws IOException,
- OperationFailedException
- {
- fileInputStream = new FileInputStream(file);
-
- byte[] buffer = new byte[1024];
- int result, bytesRead;
-
- if( (result = checkAck(scpInputStream)) !=0)
- throw new OperationFailedException("Error in Ack", result);
-
- // send "C0644 filesize filename", where filename should not include '/'
- long filesize= file.length();
- String command = "C0644 " + filesize + " ";
-
-// if(lfile.lastIndexOf('/')>0)
-// {
-// command+=lfile.substring(lfile.lastIndexOf('/')+1);
-// }
-// else
-// {
-// command+=lfile;
-// }
-
- command += file.getName() + "\n";
- if (logger.isTraceEnabled())
- logger.trace(command);
- scpOutputStream.write(command.getBytes());
- scpOutputStream.flush();
-
- if( (result = checkAck(scpInputStream)) !=0)
- throw new OperationFailedException("Error in Ack", result);
-
- while(true)
- {
- bytesRead = fileInputStream.read(buffer, 0, buffer.length);
- if(bytesRead <= 0)
- break;
-
- scpOutputStream.write(buffer, 0, bytesRead); //out.flush();
- }
- fileInputStream.close();
- fileInputStream = null;
-
- // send '\0'
- buffer[0]=0; scpOutputStream.write(buffer, 0, 1);
- scpOutputStream.flush();
-
- if( (result = checkAck(scpInputStream)) !=0)
- throw new OperationFailedException("Error in Ack", result);
-
- scpInputStream.close();
- scpOutputStream.close();
-
- fileTransferChannel.disconnect();
-
- instantMessaging.deliverMessage(
- instantMessaging.createMessage(file.getName()
- + " uploaded to Server"),
- sshContact);
- }
-
- /**
- * Downloads a file from the remote machine
- *
- * @throws IOException when the network goes down
- * @throws OperationFailedException when server behaves unexpectedly
- */
- private void download()
- throws IOException,
- OperationFailedException
- {
- fileOutputStream = new FileOutputStream(file);
-
- int result;
-
- byte[] buffer = new byte[1024];
-
- // send '\0'
- buffer[0]=0;
-
- scpOutputStream.write(buffer, 0, 1);
- scpOutputStream.flush();
-
- int ch = checkAck(scpInputStream);
-
- if(ch!='C')
- {
- throw new OperationFailedException("Invalid reply from server", 12);
- }
-
- // read '0644 '
- scpInputStream.read(buffer, 0, 5);
-
- long filesize=0L;
- while(true)
- {
- if(scpInputStream.read(buffer, 0, 1) < 0)
- {
- // error
- break;
- }
- if(buffer[0]==' ')break;
- filesize=filesize*10L+buffer[0]-'0';
- }
-
- String file=null;
- for(int i=0;true;i++)
- {
- scpInputStream.read(buffer, i, 1);
- if(buffer[i]==(byte)0x0a)
- {
- file=new String(buffer, 0, i);
- break;
- }
- }
-
- //System.out.println("filesize="+filesize+", file="+file);
-
- // send '\0'
- buffer[0]=0;
- scpOutputStream.write(buffer, 0, 1);
- scpOutputStream.flush();
-
- // read a content of lfile
- int foo;
- while(true)
- {
- if(buffer.length<filesize)
- foo=buffer.length;
- else
- foo=(int)filesize;
-
- foo = scpInputStream.read(buffer, 0, foo);
- if(foo<0)
- break;
-
- fileOutputStream.write(buffer, 0, foo);
- filesize-=foo;
- if(filesize==0L) break;
- }
- fileOutputStream.close();
- fileOutputStream=null;
-
- if( (result = checkAck(scpInputStream)) !=0)
- throw new OperationFailedException("Error in Ack", result);
-
- // send '\0'
- buffer[0]=0;
- scpOutputStream.write(buffer, 0, 1);
- scpOutputStream.flush();
-
- scpInputStream.close();
- scpOutputStream.close();
-
- fileTransferChannel.disconnect();
-
- instantMessaging.deliverMessage(
- instantMessaging.createMessage(
- this.file.getName() + " downloaded from Server"),
- sshContact);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/SSHReaderDaemon.java b/src/net/java/sip/communicator/impl/protocol/ssh/SSHReaderDaemon.java
deleted file mode 100644
index 2c33b5d..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/SSHReaderDaemon.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.io.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- *
- * @author Shobhit Jindal
- */
-public class SSHReaderDaemon
- extends Thread
-{
-
- /**
- * A Buffer to aggregate replies to be sent as one message
- */
- private StringBuffer replyBuffer;
-
- /**
- * The identifier of Contact representing the remote machine
- */
- private ContactSSHImpl sshContact;
-
- /**
- * The identifier of the message received from server
- */
- private String message;
-
- /**
- * An identifier representing the state of Reader Daemon
- */
- private boolean isActive = false;
-
- /**
- * This OperationSet delivers incoming message
- */
- private OperationSetBasicInstantMessagingSSHImpl instantMessaging;
-
- /**
- * Input Stream of remote user to be read
- */
- private InputStream shellInputStream;
-
- /**
- * Buffered Reader associated with above input stream
- */
- private InputStreamReader shellReader;
-
-// /**
-// * This OperationSet delivers incoming message
-// */
-// private OperationSetPersistentPresenceSSHImpl persistentPresence;
-
- /**
- * Bytes available in Input Stream before reading
- */
- private int bytesAvailable;
-
- private int bytesRead;
-
- int bufferCount;
-
- char buf;
-
- /**
- * Creates a new instance of SSHReaderDaemon
- */
- public SSHReaderDaemon(ContactSSH sshContact)
- {
- this.sshContact = (ContactSSHImpl)sshContact;
- instantMessaging =
- (OperationSetBasicInstantMessagingSSHImpl)
- sshContact
- .getProtocolProvider()
- .getOperationSet(
- OperationSetBasicInstantMessaging.class);
- }
-
- /**
- * Reads the remote machine, updating the chat window as necessary
- * in a background thread
- */
- @Override
- public void run()
- {
- shellInputStream = sshContact.getShellInputStream();
- shellReader = sshContact.getShellReader();
- replyBuffer = new StringBuffer();
-
-
- try
- {
- do
- {
- bytesAvailable = shellInputStream.available();
-
- if(bytesAvailable == 0 )
- {
- // wait if more data is available
- // for a slower connection this value need to be raised
- // to avoid splitting of messages
- Thread.sleep(250);
- continue;
- }
-
- bufferCount = 0;
-
-// if(replyBuffer > 0)
-
- do
- {
- // store the responses in a buffer
- storeMessage(replyBuffer);
-
- Thread.sleep(250);
-
- bytesAvailable = shellInputStream.available();
-
- }while(bytesAvailable > 0 && bufferCount<16384);
-
- message = replyBuffer.toString();
-
- if(sshContact.isCommandSent())
- {
- // if the response is as a result of a command sent
- sshContact.setMessageType(
- ContactSSH.CONVERSATION_MESSAGE_RECEIVED);
-
- message = message.substring(message.indexOf('\n') + 1);
-
- sshContact.setCommandSent(false);
- }
- else
- {
- // server sent an asynchronous message to the terminal
- // display it as a system message
- sshContact.setMessageType(
- ContactSSH.SYSTEM_MESSAGE_RECEIVED);
-
- //popup disabled
-// JOptionPane.showMessageDialog(
-// null,
-// message,
-// "Message from " + sshContact.getDisplayName(),
-// JOptionPane.INFORMATION_MESSAGE);
- }
-
- instantMessaging.deliverMessage(
- instantMessaging.createMessage(message),
- sshContact);
-
- replyBuffer.delete(0, replyBuffer.length());
-
- }while(isActive);
- }
- catch(Exception ex)
- {
- ex.printStackTrace();
- }
- }
-
- /**
- * Stores the response from server in a temporary buffer
- * the bytes available are determined before the function is called
- *
- * @param replyBuffer to store the response from server
- *
- * @throws IOException if the network goes down
- */
- private void storeMessage(StringBuffer replyBuffer) throws IOException
- {
- do
- {
- buf = (char)shellInputStream.read();
-
-// System.out.println(String.valueOf(buf)+ " " + (int)buf);
-
- replyBuffer.append(String.valueOf(buf));
-
-// logger.debug(shellReader.readLine());
-
- bufferCount++;
-
- bytesAvailable--;
-
- }while(bytesAvailable>0 && bufferCount<32700);
- }
-
- public void isActive(boolean isActive)
- {
- this.isActive = isActive;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/SSHStatusEnum.java b/src/net/java/sip/communicator/impl/protocol/ssh/SSHStatusEnum.java
deleted file mode 100644
index 0877399..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/SSHStatusEnum.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * An implementation of <tt>PresenceStatus</tt> that enumerates all states that
- * a SSH contact can fall into.
- *
- * @author Shobhit Jindal
- */
-public class SSHStatusEnum
- extends PresenceStatus
-{
-
- /**
- * Indicates an Offline status or status with 0 connectivity.
- */
- public static final SSHStatusEnum OFFLINE
- = new SSHStatusEnum(
- 0,
- "Offline",
- ProtocolIconSSHImpl
- .getImageInBytes("service.protocol.ssh.OFFLINE_STATUS_ICON"));
-
- /**
- * The Not Available status. Indicates that the user has connectivity
- * but might not be able to immediately act (i.e. even less immediately
- * than when in an Away status ;-P ) upon initiation of communication.
- *
- */
- public static final SSHStatusEnum NOT_AVAILABLE
- = new SSHStatusEnum(
- 35,
- "Not Available",
- ProtocolIconSSHImpl
- .getImageInBytes("service.protocol.ssh.NA_STATUS_ICON"));
-
- /**
- * The Connecting status. Indicate that the user is connecting to remote
- * server
- */
- public static final SSHStatusEnum CONNECTING
- = new SSHStatusEnum(
- 55,
- "Connecting",
- ProtocolIconSSHImpl
- .getImageInBytes("service.protocol.ssh.CONNECTING_ICON"));
-
- /**
- * The Online status. Indicate that the user is able and willing to
- * communicate.
- */
- public static final SSHStatusEnum ONLINE
- = new SSHStatusEnum(
- 65,
- "Online",
- ProtocolIconSSHImpl
- .getImageInBytes("service.protocol.ssh.SSH_16x16"));
-
-
- /**
- * The Connecting status. Indicate that the user is connecting to remote
- * server
- */
- public static final SSHStatusEnum CONNECTED
- = new SSHStatusEnum(
- 70,
- "Connecting",
- ProtocolIconSSHImpl
- .getImageInBytes("service.protocol.ssh.CONNECTED_ICON"));
-
- /**
- * The File Transfer status. Indicate that the user is transfering a file
- * to/from a remote server
- */
- public static final SSHStatusEnum FILE_TRANSFER
- = new SSHStatusEnum(
- 75,
- "Transfering File",
- ProtocolIconSSHImpl
- .getImageInBytes("service.protocol.ssh.FILE_TRANSFER_ICON"));
-
- /**
- * Initialize the list of supported status states.
- */
- private static List<PresenceStatus> supportedStatusSet = new LinkedList<PresenceStatus>();
- static
- {
- supportedStatusSet.add(OFFLINE);
-// supportedStatusSet.add(NOT_AVAILABLE);
- supportedStatusSet.add(ONLINE);
-// supportedStatusSet.add(CONNECTING);
- }
-
- /**
- * Creates an instance of <tt>SSHPresneceStatus</tt> with the
- * specified parameters.
- * @param status the connectivity level of the new presence status instance
- * @param statusName the name of the presence status.
- * @param statusIcon the icon associated with this status
- */
- private SSHStatusEnum(int status,
- String statusName,
- byte[] statusIcon)
- {
- super(status, statusName, statusIcon);
- }
-
- /**
- * Returns an iterator over all status instances supproted by the ssh
- * provider.
- * @return an <tt>Iterator</tt> over all status instances supported by the
- * ssh provider.
- */
- static Iterator<PresenceStatus> supportedStatusSet()
- {
- return supportedStatusSet.iterator();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/SSHUserInfo.java b/src/net/java/sip/communicator/impl/protocol/ssh/SSHUserInfo.java
deleted file mode 100644
index 082b05f..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/SSHUserInfo.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.java.sip.communicator.impl.protocol.ssh;
-
-import javax.swing.*;
-
-import com.jcraft.jsch.*;
-
-/**
- * SSHUserInfo passes authentication details to JSch SSH Stack
- *
- * @author Shobhit Jindal
- */
-class SSHUserInfo
- implements UserInfo,
- UIKeyboardInteractive
-{
- /**
- * The Contact of the remote machine
- */
- private ContactSSH sshContact;
-
- /**
- * Identifier for failure of authentication
- * more explanation below in promptPassword function
- */
- private boolean failedOnce = false;
-
- /**
- * Password field for requesting auth details from user
- */
- JTextField passwordField=new JPasswordField(20);
-
- /**
- * Creates a UserInfo instance
- *
- * @param sshContact the contact concerned
- */
- SSHUserInfo(ContactSSH sshContact)
- {
- this.sshContact = sshContact;
- }
-
- /**
- * Returns the password of account associated with this contact
- *
- * @return the password of account associated with this contact
- */
- public String getPassword()
- {
- return sshContact.getPassword();
- }
-
- /**
- * Prompt for accepting the cipher information of the remote server
- *
- * @param str the string to display
- *
- * @return the user's answer
- */
- public boolean promptYesNo(String str)
- {
- Object[] options={ "yes", "no" };
- int foo=JOptionPane.showOptionDialog(null,
- str,
- "Warning",
- JOptionPane.DEFAULT_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- null, options, options[0]);
- return foo==0;
- }
-
- /**
- * Passphrase authentication presently not implemented
- *
- * @return null
- */
- public String getPassphrase()
- { return null; }
-
- /**
- * Passphrase authentication presently not implemented
- *
- * @return true
- */
- public boolean promptPassphrase(String message)
- { return true; }
-
- /**
- * Asks user to re-enter password information in case of an auth failure
- *
- * @param message the message to display
- *
- * @return the user's answer
- */
- public boolean promptPassword(String message)
- {
- /**
- * Auth always fails for the first time for Redhat based machines.
- * Trying again with the same password
- */
- if(!failedOnce)
- {
- failedOnce = true;
- return true;
- }
-
- Object[] ob={passwordField};
- int result=JOptionPane.showConfirmDialog(null, ob, "Auth Failed: "
- + message,
- JOptionPane.OK_CANCEL_OPTION);
-
- if(result==JOptionPane.OK_OPTION)
- {
- sshContact.setPassword(passwordField.getText());
- return true;
- }
-
- return false;
- }
-
- /**
- * Shows a message from server
- *
- * @param message The message to display
- */
- public void showMessage(String message)
- {
- JOptionPane.showMessageDialog(null, message);
- }
-
- /**
- * Keyboard Interactive Auth - not implemented
- */
- public String[] promptKeyboardInteractive(
- String destination,
- String name,
- String instruction,
- String[] prompt,
- boolean[] echo)
- {
- String response[] = new String[prompt.length];
- response[0] = sshContact.getPassword();
- return response;
- }
-
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/ssh.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/ssh/ssh.provider.manifest.mf
deleted file mode 100644
index eb9472f..0000000
--- a/src/net/java/sip/communicator/impl/protocol/ssh/ssh.provider.manifest.mf
+++ /dev/null
@@ -1,20 +0,0 @@
-Bundle-Activator: net.java.sip.communicator.impl.protocol.ssh.SSHActivator
-Bundle-Name: SSH Protocol Provider
-Bundle-Description: A bundle providing support for the SSH protocol.
-Bundle-Vendor: jitsi.org
-Bundle-Version: 0.0.1
-Bundle-SymbolicName: net.java.sip.communicator.protocol.ssh
-Import-Package: org.osgi.framework,
- javax.crypto,
- javax.crypto.interfaces,
- javax.crypto.spec,
- javax.swing,
- javax.swing.border,
- javax.swing.text,
- org.jitsi.service.configuration,
- net.java.sip.communicator.service.gui,
- net.java.sip.communicator.service.protocol,
- net.java.sip.communicator.service.protocol.event,
- org.jitsi.service.resources, net.java.sip.communicator.service.resources,
- net.java.sip.communicator.util,
- net.java.sip.communicator.plugin.desktoputil
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/AbstractContactGroupYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/AbstractContactGroupYahooImpl.java
deleted file mode 100644
index 0514c16..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/AbstractContactGroupYahooImpl.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The Yahoo implementation of the service.protocol.ContactGroup interface. There
- * are two types of groups possible here. <tt>RootContactGroupYahooImpl</tt>
- * which is the root node of the ContactList itself and
- * <tt>ContactGroupYahooImpl</tt> which represents standard groups. The
- * reason for having those 2 is that generally, Yahoo groups may not contain
- * subgroups. A contact list on the other hand may not directly contain buddies.
- *
- *
- * The reason for having an abstract class is only - being able to esily
- * recognize our own (Yahoo) contacts.
- * @author Damian Minkov
- */
-public abstract class AbstractContactGroupYahooImpl
- implements ContactGroup
-{
-
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/AdHocChatRoomInvitationYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/AdHocChatRoomInvitationYahooImpl.java
deleted file mode 100644
index e849f6c..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/AdHocChatRoomInvitationYahooImpl.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The Yahoo implementation of the <tt>AdHocChatRoomInvitation</tt> interface.
- *
- * @author Rupert Burchardi
- * @author Valentin Martinet
- */
-public class AdHocChatRoomInvitationYahooImpl
- implements AdHocChatRoomInvitation
-{
- /**
- * Corresponding chat room instance.
- */
- private AdHocChatRoom chatRoom;
- /**
- * The name of the inviter
- */
- private String inviter;
-
- /**
- * The invitation reason.
- */
- private String reason;
-
-
- /**
- * Creates an instance of the <tt>ChatRoomInvitationMsnImpl</tt> by
- * specifying the targetChatRoom, the inviter, the reason.
- *
- * @param targetChatRoom The <tt>AdHocChatRoom</tt> for which the invitation
- * is
- * @param inviter The <tt>Contact</tt>, which sent the invitation
- * @param reason The Reason for the invitation
- */
- public AdHocChatRoomInvitationYahooImpl( AdHocChatRoom targetChatRoom,
- String inviter,
- String reason)
- {
- this.chatRoom = targetChatRoom;
- this.inviter = inviter;
- this.reason = reason;
- }
-
- /**
- * Returns the corresponding chat room.
- * @return The ad-hoc chat room
- */
- public AdHocChatRoom getTargetAdHocChatRoom()
- {
- return chatRoom;
- }
-
- /**
- * Returns the corresponding inviter.
- * @return The name of the inviter
- */
- public String getInviter()
- {
- return inviter;
- }
-
- /**
- * Returns the invitation reason.
- * @return the invitation reason
- */
- public String getReason()
- {
- return reason;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/AdHocChatRoomYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/AdHocChatRoomYahooImpl.java
deleted file mode 100644
index 2775f6f..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/AdHocChatRoomYahooImpl.java
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.*;
-
-/**
- * Represents a Yahoo ad-hoc chat room, where multiple chat users could
- * communicate in a many-to-many fashion.
- *
- * @author Rupert Burchardi
- * @author Valentin Martinet
- */
-public class AdHocChatRoomYahooImpl
- implements AdHocChatRoom
-{
- private static final Logger logger = Logger
- .getLogger(AdHocChatRoomYahooImpl.class);
-
- /**
- * Listeners that will be notified of changes in member status in the room
- * such as member joined, left or being kicked or dropped.
- */
- private Vector<AdHocChatRoomParticipantPresenceListener> memberListeners
- = new Vector<AdHocChatRoomParticipantPresenceListener>();
-
- /**
- * Listeners that will be notified every time a new message is received on
- * this ad-hoc chat room.
- */
- private Vector<AdHocChatRoomMessageListener> messageListeners
- = new Vector<AdHocChatRoomMessageListener>();
-
- /**
- * The protocol provider that created us
- */
- private ProtocolProviderServiceYahooImpl provider = null;
-
- /**
- * The operation set that created us.
- */
- private OperationSetAdHocMultiUserChatYahooImpl opSetMuc = null;
-
- /**
- * The list of participants of this chat room.
- */
- private Hashtable<String, Contact> participants
- = new Hashtable<String, Contact>();
-
- /**
- * The nickname of this chat room local user participant.
- */
- private String nickname;
-
- /**
- * The yahoo conference model of this ad-hoc chat room, its the
- * representation of an ad-hoc chat room in the lib for this protocol.
- */
- private YahooConference yahooConference = null;
-
- /**
- * Creates an instance of a chat room that has been.
- *
- * @param multiUserChat
- * MultiUserChat
- * @param provider
- * a reference to the currently valid jabber protocol provider.
- */
- public AdHocChatRoomYahooImpl( YahooConference multiUserChat,
- ProtocolProviderServiceYahooImpl provider)
- {
- this.yahooConference = multiUserChat;
- this.provider = provider;
- this.opSetMuc = (OperationSetAdHocMultiUserChatYahooImpl) provider
- .getOperationSet(OperationSetAdHocMultiUserChat.class);
- }
-
- /**
- * Registers <tt>listener</tt> so that it would receive events every time a
- * new message is received on this chat room.
- *
- * @param listener A <tt>MessageListener</tt> that would be notified every
- * time a new message is received on this chat room.
- */
- public void addMessageListener(AdHocChatRoomMessageListener listener)
- {
- synchronized (messageListeners)
- {
- if (!messageListeners.contains(listener))
- messageListeners.add(listener);
- }
- }
-
- /**
- * Removes <tt>listener</tt> so that it won't receive any further message
- * events from this room.
- *
- * @param listener The <tt>MessageListener</tt> to remove from this room
- */
- public void removeMessageListener(AdHocChatRoomMessageListener listener)
- {
- synchronized (messageListeners)
- {
- messageListeners.remove(listener);
- }
- }
-
- /**
- * Adds a listener that will be notified of changes in our status in the
- * room.
- *
- * @param listener A participant status listener.
- */
- public void addParticipantPresenceListener(
- AdHocChatRoomParticipantPresenceListener listener)
- {
- synchronized (memberListeners)
- {
- if (!memberListeners.contains(listener))
- memberListeners.add(listener);
- }
- }
-
- /**
- * Removes a listener that was being notified of changes in the status of
- * other chat room participants.
- *
- * @param listener A participant status listener.
- */
- public void removeParticipantPresenceListener(
- AdHocChatRoomParticipantPresenceListener listener)
- {
- synchronized (memberListeners)
- {
- memberListeners.remove(listener);
- }
- }
-
- /**
- * Create a Message instance for sending a simple text messages with default
- * (text/plain) content type and encoding.
- *
- * @param messageText
- * the string content of the message.
- * @return Message the newly created message
- */
- public Message createMessage(String messageText)
- {
- Message msg = new MessageYahooImpl(messageText,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_ENCODING, null);
- return msg;
- }
-
- /**
- * Returns a <tt>List</tt> of <tt>Contact</tt>s corresponding to all members
- * currently participating in this room.
- *
- * @return a <tt>List</tt> of <tt>Contact</tt> corresponding to all room
- * members.
- */
- public List<Contact> getParticipants()
- {
- return new LinkedList<Contact>(participants.values());
- }
-
- /**
- * Updates the member list of the chat room.
- *
- */
- public void updateParticipantsList()
- {
- Iterator<?> it = yahooConference.getMembers().iterator();
-
- while (it.hasNext())
- {
- YahooUser user = (YahooUser) it.next();
- Contact contact;
- OperationSetPersistentPresenceYahooImpl presenceOpSet
- = (OperationSetPersistentPresenceYahooImpl) this
- .getParentProvider().getOperationSet(
- OperationSetPersistentPresence.class);
-
- contact = presenceOpSet.findContactByID(user.getId());
-
- if(!participants.containsKey(contact.getDisplayName()))
- {
- participants.put(contact.getDisplayName(), contact);
- }
- }
- }
-
- /**
- * Returns the identifier of this <tt>AdHocChatRoom</tt>.
- *
- * @return a <tt>String</tt> containing the identifier of this
- * <tt>AdHocChatRoom</tt>.
- */
- public String getIdentifier()
- {
- return yahooConference.getName();
- }
-
- /**
- * Returns the number of participants that are currently in this ad-hoc chat
- * room.
- *
- * @return the number of <tt>Contact</tt>s, currently participating in
- * this ad-hoc room.
- */
- public int getParticipantsCount()
- {
- return yahooConference.getMembers().size();
- }
-
- /**
- * Returns the name of this <tt>AdHocChatRoom</tt>.
- *
- * @return a <tt>String</tt> containing the name of this
- * <tt>AdHocChatRoom</tt>.
- */
- public String getName()
- {
- return yahooConference.getName();
- }
-
- /**
- * Returns the protocol provider service that created us.
- *
- * @return the protocol provider service that created us.
- */
- public ProtocolProviderService getParentProvider()
- {
- return provider;
- }
-
- /**
- * Returns the local user's nickname in the context of this chat room or
- * <tt>null</tt> if not currently joined.
- *
- * @return the nickname currently being used by the local user in the
- * context of the local ad-hoc chat room.
- */
-
- public String getUserNickname()
- {
- if(nickname == null)
- nickname = provider.getYahooSession().getLoginIdentity().getId();
-
- return nickname;
- }
-
- /**
- * Invites another user to this room. If we're not joined nothing will
- * happen.
- *
- * @param userAddress The identifier of the contact (email address or yahoo
- * id)
- * @param reason The invite reason, which is send to the invitee.
- */
- public void invite(String userAddress, String reason)
- {
- try
- {
- provider.getYahooSession().extendConference(yahooConference,
- userAddress, reason);
- }
- catch (IOException ioe)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to invite the user: " + userAddress
- + " Error: " + ioe);
- }
- }
-
- /**
- * Indicates whether or not this chat room is corresponding to a server
- * channel. Note: Returns always <code>false</code>.
- *
- * @return Always <code>false</code> since system chat room can't be joined
- * with current yahoo library.
- */
- public boolean isSystem()
- {
- return false;
- }
-
- /**
- * Joins this chat room with the nickname of the local user so that the user
- * would start receiving events and messages for it.
- *
- * @throws OperationFailedException with the corresponding code if an error
- * occurs while joining the room.
- */
- public void join() throws OperationFailedException
- {
- this.nickname = provider.getAccountID().getUserID();
- try
- {
- provider.getYahooSession().acceptConferenceInvite(yahooConference);
-
- // We don't specify a reason.
- opSetMuc.fireLocalUserPresenceEvent(this,
- LocalUserAdHocChatRoomPresenceChangeEvent.LOCAL_USER_JOINED,
- null);
- }
- catch (Exception e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Couldn't join the chat room: "
- + yahooConference.getName() + e);
- }
- }
-
- /**
- * Leave this chat room. Once this method is called, the user won't be
- * listed as a member of the chat room any more and no further chat events
- * will be delivered. Depending on the underlying protocol and
- * implementation leave() might cause the room to be destroyed if it has
- * been created by the local user.
- */
- public void leave()
- {
- try
- {
- provider.getYahooSession().leaveConference(yahooConference);
-
- Iterator< Map.Entry<String, Contact>> membersSet
- = participants.entrySet().iterator();
-
- while (membersSet.hasNext())
- {
- Map.Entry<String, Contact> memberEntry = membersSet.next();
- Contact participant = memberEntry.getValue();
-
- fireParticipantPresenceEvent(participant,
- AdHocChatRoomParticipantPresenceChangeEvent.CONTACT_LEFT,
- "Local user has left the chat room.");
- }
- }
- catch (IOException ioe)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to leave the chat room: "
- + yahooConference.getName() + " Error: " + ioe);
- }
-
- participants.clear();
- }
-
- /**
- * Sends the <tt>message</tt> to the destination indicated by the
- * <tt>to</tt> contact.
- *
- * @param message The <tt>Message</tt> to send.
- * @throws OperationFailedException if the underlying stack is not
- * registered or initialized or if the chat room is not joined.
- */
- public void sendMessage(Message message) throws OperationFailedException
- {
- assertConnected();
-
- try
- {
- provider.getYahooSession().sendConferenceMessage(yahooConference,
- message.getContent());
-
- AdHocChatRoomMessageDeliveredEvent msgDeliveredEvt
- = new AdHocChatRoomMessageDeliveredEvent(
- this,
- new Date(),
- message,
- ChatRoomMessageDeliveredEvent.CONVERSATION_MESSAGE_DELIVERED);
-
- fireMessageEvent(msgDeliveredEvt);
- }
- catch (Exception e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to send a conference message.");
- }
- }
-
- /**
- * Notifies all interested listeners that a
- * <tt>AdHocChatRoomMessageDeliveredEvent</tt>,
- * <tt>AdHocChatRoomMessageReceivedEvent</tt> or a
- * <tt>AdHocChatRoomMessageDeliveryFailedEvent</tt> has been fired.
- * @param evt The specific event
- */
- public void fireMessageEvent(EventObject evt)
- {
- Iterator<AdHocChatRoomMessageListener> listeners = null;
- synchronized (messageListeners)
- {
- listeners = new ArrayList<AdHocChatRoomMessageListener>(
- messageListeners).iterator();
- }
-
- while (listeners.hasNext())
- {
- AdHocChatRoomMessageListener listener = listeners.next();
-
- if (evt instanceof AdHocChatRoomMessageDeliveredEvent)
- {
- listener.messageDelivered(
- (AdHocChatRoomMessageDeliveredEvent) evt);
- }
- else if (evt instanceof AdHocChatRoomMessageReceivedEvent)
- {
- listener.messageReceived(
- (AdHocChatRoomMessageReceivedEvent) evt);
- }
- else if (evt instanceof AdHocChatRoomMessageDeliveryFailedEvent)
- {
- listener.messageDeliveryFailed(
- (AdHocChatRoomMessageDeliveryFailedEvent) evt);
- }
- }
- }
-
- /**
- * Creates the corresponding AdHocChatRoomParticipantPresenceChangeEvent and
- * notifies all <tt>AdHocChatRoomParticipantPresenceListener</tt>s that a
- * Contact has joined or left this <tt>AdHocChatRoom</tt>.
- *
- * @param participant the <tt>Contact</tt> that this
- * @param eventID the identifier of the event
- * @param eventReason the reason of the event
- */
- public void fireParticipantPresenceEvent(Contact participant, String eventID,
- String eventReason)
- {
- AdHocChatRoomParticipantPresenceChangeEvent evt
- = new AdHocChatRoomParticipantPresenceChangeEvent(this,
- participant,
- eventID,
- eventReason);
-
- if (logger.isTraceEnabled())
- logger.trace("Will dispatch the following ChatRoom event: " + evt);
-
- Iterator<AdHocChatRoomParticipantPresenceListener> listeners = null;
- synchronized (memberListeners)
- {
- listeners = new ArrayList<AdHocChatRoomParticipantPresenceListener>
- (memberListeners).iterator();
- }
-
- while (listeners.hasNext())
- {
- AdHocChatRoomParticipantPresenceListener listener = listeners.next();
-
- listener.participantPresenceChanged(evt);
- }
- }
-
- /**
- * Finds the participant of this ad-hoc chat room corresponding to the
- * given address.
- *
- * @param address the address to search for.
- * @return the participant of this chat room corresponding to the given
- * nick name.
- */
- public Contact findParticipantForAddress(String address)
- {
- Iterator<Contact> participantsIter
- = this.participants.values().iterator();
-
- while (participantsIter.hasNext())
- {
- Contact contact = participantsIter.next();
-
- if (contact.getAddress().equals(address))
- {
- return contact;
- }
- }
-
- return null;
- }
-
- /**
- * Removes the specified ad-hoc chat room participant from the participants
- * list of this ad-hoc chat room.
- * @param participant The member, who should be removed from the ad-hoc chat room
- * participants list.
- */
- public void removeChatRoomParticipant(Contact participant)
- {
- if(participant == null)
- return;
-
- participants.remove(participant.getDisplayName());
-
- fireParticipantPresenceEvent(participant,
- AdHocChatRoomParticipantPresenceChangeEvent.CONTACT_LEFT, null);
- }
-
- /**
- * Adds a participant to the ad-hoc chat room participant list.
- * @param participant The participant, who should be added to the ad-hoc
- * chat room participant list.
- */
- public void addChatRoomParticipant(Contact participant)
- {
- if (participant == null)
- return;
-
- if (!participants.containsKey(participant.getDisplayName()))
- {
- participants.put(participant.getDisplayName(), participant);
-
- fireParticipantPresenceEvent(participant,
- AdHocChatRoomParticipantPresenceChangeEvent.CONTACT_JOINED,
- null);
- }
- }
-
- /**
- * Returns the yahoo conference model of this chat room.
- * @return The yahoo conference.
- */
- public YahooConference getYahooConference()
- {
- return yahooConference;
- }
-
- /**
- * Utility method throwing an exception if the stack is not properly
- * initialized.
- * @throws java.lang.IllegalStateException if the underlying stack is
- * not registered and initialized.
- */
- private void assertConnected() throws IllegalStateException
- {
- if (provider == null)
- throw new IllegalStateException(
- "The provider must be non-null and signed on the "
- +"service before being able to communicate.");
- if (!provider.isRegistered())
- throw new IllegalStateException(
- "The provider must be signed on the service before "
- +"being able to communicate.");
- }
-
- /**
- * Determines whether this chat room should be stored in the configuration
- * file or not. If the chat room is persistent it still will be shown after a
- * restart in the chat room list. A non-persistent chat room will be only in
- * the chat room list until the the program is running.
- *
- * @return true if this chat room is persistent, false otherwise
- */
- public boolean isPersistent()
- {
- return false;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/ContactGroupYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/ContactGroupYahooImpl.java
deleted file mode 100644
index 1f73aac..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/ContactGroupYahooImpl.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import ymsg.network.*;
-
-/**
- * The Yahoo implementation of the ContactGroup interface. Intances of this class
- * (contrary to <tt>RootContactGroupYahooImpl</tt>) may only contain buddies
- * and cannot have sub groups. Note that instances of this class only use the
- * corresponding smack source group for reading their names and only
- * initially fill their <tt>buddies</tt> <tt>java.util.List</tt> with
- * the ContactYahooImpl objects corresponding to those contained in the source
- * group at the moment it is being created. They would, however, never try to
- * sync or update their contents ulteriorly. This would have to be done through
- * the addContact()/removeContact() methods.
- * The content of buddies is created on creating of the group and when the smack
- * source group is changed.
- *
- * @author Damian Minkov
- * @author Emil Ivov
- */
-public class ContactGroupYahooImpl
- extends AbstractContactGroupYahooImpl
-{
- private final Map<String, Contact> buddies
- = new Hashtable<String, Contact>();
-
- private boolean isResolved = false;
-
- /**
- * The Yahoo Group corresponding to this contact group.
- */
- private YahooGroup yahooGroup = null;
-
- /**
- * a list that would always remain empty. We only use it so that we're able
- * to extract empty iterators
- */
- private final List<ContactGroup> dummyGroupsList
- = new LinkedList<ContactGroup>();
-
- private String tempId = null;
-
- private final ServerStoredContactListYahooImpl ssclCallback;
-
- /**
- * Creates an Yahoo group using the specified <tt>YahooGroup</tt> as
- * a source. The newly created group will always return the name of the
- * underlying RosterGroup and would thus automatically adapt to changes.
- * It would, however, not receive or try to poll for modifications of the
- * buddies it contains and would therefore have to be updated manually by
- * ServerStoredContactListImpl update will only be done if source group
- * is changed.
-
- * @param yahooGroup the Yahoo Group correspoinding to the group
- * @param groupMembers the group members that we should add to the group.
- * @param ssclCallback a callback to the server stored contact list
- * we're creating.
- * @param isResolved a boolean indicating whether or not the group has been
- * resolved against the server.
- */
- ContactGroupYahooImpl(
- YahooGroup yahooGroup,
- Vector<YahooUser> groupMembers,
- ServerStoredContactListYahooImpl ssclCallback,
- boolean isResolved)
- {
- this.yahooGroup = yahooGroup;
- this.isResolved = isResolved;
- this.ssclCallback = ssclCallback;
-
- for (YahooUser yahooUser : groupMembers)
- {
- //only add the contact if it doesn't already exist in some other
- //group. this would be necessary if Yahoo! one day start allowing
- //the same contact in more than one group, which is not quite
- //unlikely since most of the other protocols do it.
- if(ssclCallback.findContactByYahooUser(yahooUser) != null)
- {
- continue;
- }
-
-
- addContact(
- new ContactYahooImpl(yahooUser,ssclCallback, true, true));
- }
- }
-
- ContactGroupYahooImpl( String id,
- ServerStoredContactListYahooImpl ssclCallback)
- {
- this.tempId = id;
- this.isResolved = false;
- this.ssclCallback = ssclCallback;
- }
-
-
- /**
- * Returns the number of <tt>Contact</tt> members of this
- * <tt>ContactGroup</tt>
- *
- * @return an int indicating the number of <tt>Contact</tt>s,
- * members of this <tt>ContactGroup</tt>.
- */
- public int countContacts()
- {
- return buddies.size();
- }
-
- /**
- * Returns a reference to the root group which in Yahoo is the parent of
- * any other group since the protocol does not support subgroups.
- * @return a reference to the root group.
- */
- public ContactGroup getParentContactGroup()
- {
- return ssclCallback.getRootGroup();
- }
-
- /**
- * Adds the specified contact to the end of this group.
- * @param contact the new contact to add to this group
- */
- void addContact(ContactYahooImpl contact)
- {
- buddies.put(contact.getAddress().toLowerCase(), contact);
- }
-
-
- /**
- * Removes the specified contact from this contact group
- * @param contact the contact to remove.
- */
- void removeContact(ContactYahooImpl contact)
- {
- buddies.remove(contact.getAddress().toLowerCase());
- }
-
- /**
- * Returns an Iterator over all contacts, member of this
- * <tt>ContactGroup</tt>.
- *
- * @return a java.util.Iterator over all contacts inside this
- * <tt>ContactGroup</tt>. In case the group doesn't contain any
- * memebers it will return an empty iterator.
- */
- public Iterator<Contact> contacts()
- {
- return buddies.values().iterator();
- }
-
- /**
- * Returns the <tt>Contact</tt> with the specified address or
- * identifier.
- * @param id the addres or identifier of the <tt>Contact</tt> we are
- * looking for.
- * @return the <tt>Contact</tt> with the specified id or address.
- */
- public Contact getContact(String id)
- {
- return this.findContact(id);
- }
-
- /**
- * Returns the name of this group.
- * @return a String containing the name of this group.
- */
- public String getGroupName()
- {
- if(isResolved)
- return ServerStoredContactListYahooImpl
- .replaceIllegalChars(yahooGroup.getName());
- else
- return tempId;
- }
-
- /**
- * Determines whether the group may contain subgroups or not.
- *
- * @return always false since only the root group may contain subgroups.
- */
- public boolean canContainSubgroups()
- {
- return false;
- }
-
- /**
- * Returns the subgroup with the specified index (i.e. always null since
- * this group may not contain subgroups).
- *
- * @param index the index of the <tt>ContactGroup</tt> to retrieve.
- * @return always null
- */
- public ContactGroup getGroup(int index)
- {
- return null;
- }
-
- /**
- * Returns the subgroup with the specified name.
- * @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(String groupName)
- {
- return null;
- }
-
- /**
- * Returns an empty iterator. Subgroups may only be present in the root
- * group.
- *
- * @return an empty iterator
- */
- public Iterator<ContactGroup> subgroups()
- {
- return dummyGroupsList.iterator();
- }
-
- /**
- * Returns the number of subgroups contained by this group, which is
- * always 0 since sub groups in the protocol may only be contained
- * by the root group - <tt>RootContactGroupImpl</tt>.
- * @return a 0 int.
- */
- public int countSubgroups()
- {
- return 0;
- }
-
- /**
- * Returns a hash code value for the object, which is actually the hashcode
- * value of the groupname.
- *
- * @return a hash code value for this ContactGroup.
- */
- @Override
- public int hashCode()
- {
- return getGroupName().hashCode();
- }
-
- /**
- * Indicates whether some other object is "equal to" this group.
- *
- * @param obj the reference object with which to compare.
- * @return <tt>true</tt> if this object is the same as the obj
- * argument; <tt>false</tt> otherwise.
- */
- @Override
- public boolean equals(Object obj)
- {
- if( obj == this )
- return true;
-
- if (obj == null
- || !(obj instanceof ContactGroupYahooImpl) )
- return false;
-
- if(!((ContactGroup)obj).getGroupName().equals(getGroupName()))
- return false;
-
- if(getProtocolProvider() != ((ContactGroup)obj).getProtocolProvider())
- return false;
-
- //since Yahoo does not support having two groups with the same name
- // at this point we could bravely state that the groups are the same
- // and not bother to compare buddies. (gotta check that though)
- return true;
- }
-
- /**
- * Returns the protocol provider that this group belongs to.
- * @return a reference to the ProtocolProviderService instance that this
- * ContactGroup belongs to.
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return this.ssclCallback.getParentProvider();
- }
-
- /**
- * Returns a string representation of this group, in the form
- * YahooGroup.GroupName[size]{ buddy1.toString(), buddy2.toString(), ...}.
- * @return a String representation of the object.
- */
- @Override
- public String toString()
- {
- StringBuffer buff = new StringBuffer("YahooGroup.");
- buff.append(getGroupName());
- buff.append(", childContacts="+countContacts()+":[");
-
- Iterator<Contact> contacts = contacts();
- while (contacts.hasNext())
- {
- Contact contact = contacts.next();
- buff.append(contact.toString());
- if(contacts.hasNext())
- buff.append(", ");
- }
- return buff.append("]").toString();
- }
-
- /**
- * Returns the contact encapsulating with the spcieified name or
- * null if no such contact was found.
- *
- * @param id the id for the contact we're looking for.
- * @return the <tt>ContactYahooImpl</tt> corresponding to the specified
- * screnname or null if no such contact existed.
- */
- ContactYahooImpl findContact(String id)
- {
- if(id == null)
- return null;
- return (ContactYahooImpl)buddies.get(id.toLowerCase());
- }
-
- /**
- * Determines whether or not this contact group is being stored by the
- * server. Non persistent contact groups exist for the sole purpose of
- * containing non persistent contacts.
- * @return true if the contact group is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return true;
- }
-
- /**
- * Returns null as no persistent data is required and the contact address is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact group has been resolved against
- * the server. Unresolved group are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts and groups to their corresponding on-line
- * buddies.
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Resolve this contact group against the specified group
- * @param yahooGroup the server stored group
- */
- @SuppressWarnings("unchecked") //jymsg legacy code
- void setResolved(YahooGroup yahooGroup)
- {
- if(isResolved)
- return;
-
- this.isResolved = true;
-
- this.yahooGroup = yahooGroup;
-
- Vector<YahooUser> contacts = yahooGroup.getMembers();
- for (YahooUser item : contacts)
- {
- ContactYahooImpl contact =
- ssclCallback.findContactById(item.getId());
- if(contact != null)
- {
- contact.setResolved(item);
-
- ssclCallback.fireContactResolved(this, contact);
- }
- else
- {
- ContactYahooImpl newContact =
- new ContactYahooImpl(item, ssclCallback, true, true);
- addContact(newContact);
-
- ssclCallback.fireContactAdded(this, newContact);
- }
- }
- }
-
- /**
- * Returns a <tt>String</tt> that uniquely represnets the group. In this we
- * use the name of the group as an identifier. This may cause problems
- * though, in clase the name is changed by some other application between
- * consecutive runs of the sip-communicator.
- *
- * @return a String representing this group in a unique and persistent
- * way.
- */
- public String getUID()
- {
- return getGroupName();
- }
-
- /**
- * The source group we are encapsulating
- * @return YahooGroup
- */
- YahooGroup getSourceGroup()
- {
- return yahooGroup;
- }
-
- /**
- * Change the source group
- * change the buddies
- *
- * @param newGroup YahooGroup
- */
- void setSourceGroup(YahooGroup newGroup)
- {
- this.yahooGroup = newGroup;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/ContactYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/ContactYahooImpl.java
deleted file mode 100644
index b23ee3d..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/ContactYahooImpl.java
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.yahooconstants.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.*;
-
-/**
- * The Yahoo implementation of the service.protocol.Contact interface.
- * @author Damian Minkov
- * @author Emil Ivov
- */
-public class ContactYahooImpl
- extends AbstractContact
-{
- private static final Logger logger =
- Logger.getLogger(ContactYahooImpl.class);
-
- private YahooUser contact = null;
- private byte[] image = null;
- private PresenceStatus status = YahooStatusEnum.OFFLINE;
- private ServerStoredContactListYahooImpl ssclCallback = null;
- private boolean isPersistent = false;
- private boolean isResolved = false;
- private boolean isVolatile = false;
-
- private String yahooID = null;
- private String id = null;
-
- private String statusMessage = null;
-
- /**
- * Creates an YahooContactImpl with custom yahooID
- * @param yahooID sets the contact Id if its different from the YahooUser id
- * @param contact the contact object that we will be encapsulating.
- * @param ssclCallback a reference to the ServerStoredContactListImpl
- * instance that created us.
- * @param isPersistent determines whether this contact is persistent or not.
- * @param isResolved specifies whether the contact has been resolved against
- * the server contact list
- */
- ContactYahooImpl(
- String yahooID,
- YahooUser contact,
- ServerStoredContactListYahooImpl ssclCallback,
- boolean isPersistent,
- boolean isResolved)
- {
- this.yahooID = yahooID;
-
- this.contact = contact;
- this.ssclCallback = ssclCallback;
- this.isPersistent = isPersistent;
- this.isResolved = isResolved;
-
- if(contact != null)
- id = contact.getId();
- else if(yahooID != null)
- id = YahooSession.getYahooUserID(yahooID);
- }
-
- /**
- * Creates an YahooContactImpl
- * @param contact the contact object that we will be encapsulating.
- * @param ssclCallback a reference to the ServerStoredContactListImpl
- * instance that created us.
- * @param isPersistent determines whether this contact is persistent or not.
- * @param isResolved specifies whether the contact has been resolved against
- * the server contact list
- */
- ContactYahooImpl(
- YahooUser contact,
- ServerStoredContactListYahooImpl ssclCallback,
- boolean isPersistent,
- boolean isResolved)
- {
- this(null, contact, ssclCallback, isPersistent, isResolved);
- }
-
- /**
- * Creates volatile or unresolved contact
- */
- ContactYahooImpl(
- String id,
- ServerStoredContactListYahooImpl ssclCallback,
- boolean isResolved,
- boolean isPersistent,
- boolean isVolatile)
- {
- this.yahooID = id;
- this.ssclCallback = ssclCallback;
- this.isPersistent = isPersistent;
- this.isResolved = isResolved;
- this.isVolatile = isVolatile;
-
- if(id != null)
- this.id = YahooSession.getYahooUserID(yahooID);
- }
-
- /**
- * Returns the Yahoo Userid of this contact
- * @return the Yahoo Userid of this contact
- */
- public String getAddress()
- {
- // if the contact is volatile or with custom id return it
- if(yahooID != null)
- return yahooID;
- // otherwise return the supplied contact id
- else
- return contact.getId();
- }
-
- /**
- * Returns the custom yahooID if set
- */
- String getYahooID()
- {
- return yahooID;
- }
-
- /**
- * Returns the contact Id.
- * If contact missing the yahooID without @yahoo.com part is returned
- */
- String getID()
- {
- return id;
- }
-
- /**
- * Returns whether the contact is volatile.
- */
- boolean isVolatile()
- {
- return isVolatile;
- }
-
- /**
- * Returns an avatar if one is already present or <tt>null</tt> in case it
- * is not in which case it the method also queues the contact for image
- * updates.
- *
- * @return the avatar of this contact or <tt>null</tt> if no avatar is
- * currently available.
- */
- public byte[] getImage()
- {
- return getImage(true);
- }
-
- /**
- * Returns a reference to the image assigned to this contact. If no image
- * is present and the retrieveIfNecessary flag is true, we schedule the
- * image for retrieval from the server.
- *
- * @param retrieveIfNecessary specifies whether the method should queue
- * this contact for avatar update from the server.
- *
- * @return a reference to the image currently stored by this contact.
- */
- public byte[] getImage(boolean retrieveIfNecessary)
- {
- try
- {
- if(retrieveIfNecessary)
- {
- if(ssclCallback.getParentProvider() == null
- || !ssclCallback.getParentProvider().isRegistered())
- {
- throw new IllegalStateException(
- "The provider must be signed on the service before "
- +"being able to communicate.");
- }
-
- YahooSession ses = ssclCallback.getParentProvider().
- getYahooSession();
- if(image == null && ses != null)
- ses.requestPicture(id);
- }
- }
- catch (Exception e)
- {
- if (logger.isInfoEnabled())
- logger.info("Error requesting image!", e);
- }
-
- if(logger.isDebugEnabled())
- logger.debug("returning picture " + image);
-
- return image;
- }
-
- /**
- * Used to set the image of the contact if it is updated
- *
- * @param image a photo/avatar associated with this contact.
- */
- protected void setImage(byte[] image)
- {
- if (logger.isInfoEnabled())
- logger.info("setting image " + image);
-
- this.image = image;
- }
-
- /**
- * Returns a string representation of this contact, containing most of its
- * representative details.
- *
- * @return a string representation of this contact.
- */
- @Override
- public String toString()
- {
- StringBuffer buff = new StringBuffer("YahooContact[ id=");
- buff.append(getAddress()).append("]");
-
- return buff.toString();
- }
-
- /**
- * Sets the status that this contact is currently in. The method is to
- * only be called as a result of a status update received from the server.
- *
- * @param status the YahooStatusEnum that this contact is currently in.
- */
- void updatePresenceStatus(PresenceStatus status)
- {
- this.status = status;
- }
-
- /**
- * Returns the status of the contact as per the last status update we've
- * received for it. Note that this method is not to perform any network
- * operations and will simply return the status received in the last
- * status update message. If you want a reliable way of retrieving someone's
- * status, you should use the <tt>queryContactStatus()</tt> method in
- * <tt>OperationSetPresence</tt>.
- * @return the PresenceStatus that we've received in the last status update
- * pertaining to this contact.
- */
- public PresenceStatus getPresenceStatus()
- {
- return status;
- }
-
- /**
- * Returns a String that could be used by any user interacting modules for
- * referring to this contact. An alias is not necessarily unique but is
- * often more human readable than an address (or id).
- * @return a String that can be used for referring to this contact when
- * interacting with the user.
- */
- public String getDisplayName()
- {
- return getAddress();
- }
-
- /**
- * Returns a reference to the contact group that this contact is currently
- * a child of or null if the underlying protocol does not suppord persistent
- * presence.
- * @return a reference to the contact group that this contact is currently
- * a child of or null if the underlying protocol does not suppord persistent
- * presence.
- */
- public ContactGroup getParentContactGroup()
- {
- return ssclCallback.findContactGroup(this);
- }
-
-
- /**
- * Returns a reference to the protocol provider that created the contact.
- * @return a refererence to an instance of the ProtocolProviderService
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return ssclCallback.getParentProvider();
- }
-
- /**
- * Determines whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- * @return true if the contact is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Specifies whether this contact is to be considered persistent or not. The
- * method is to be used _only_ when a non-persistent contact has been added
- * to the contact list and its encapsulated VolatileBuddy has been repalced
- * with a standard buddy.
- * @param persistent true if the buddy is to be considered persistent and
- * false for volatile.
- */
- void setPersistent(boolean persistent)
- {
- this.isPersistent = persistent;
- }
-
- /**
- * Resolve this contact against the given entry
- * @param entry the server stored entry
- */
- void setResolved(YahooUser entry)
- {
- if(isResolved)
- return;
-
- this.isResolved = true;
- contact = entry;
- isVolatile = false;
- }
-
- /**
- * Returns the persistent data
- * @return the persistent data
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- public void setPersistentData(String persistentData)
- {
- }
-
- /**
- * Get source contact
- * @return YahooContact
- */
- YahooUser getSourceContact()
- {
- return contact;
- }
-
- /**
- * Return the current status message of this contact.
- *
- * @return the current status message
- */
- public String getStatusMessage()
- {
- return statusMessage;
- }
-
- /**
- * Sets the current status message for this contact
- * @param statusMessage the message
- */
- protected void setStatusMessage(String statusMessage)
- {
- this.statusMessage = statusMessage;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/FileTransferImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/FileTransferImpl.java
deleted file mode 100644
index 3f42079..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/FileTransferImpl.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The Filetransfer imeplementation for yahoo.
- * @author Damian Minkov
- */
-public class FileTransferImpl
- extends AbstractFileTransfer
-
-{
- private ProtocolProviderServiceYahooImpl yahooProvider;
- private String id = null;
- private Contact contact = null;
- private File file = null;
- private int direction = -1;
- private long transferedBytes;
-
- public FileTransferImpl(ProtocolProviderServiceYahooImpl yahooProvider,
- String id, Contact contact, File file, int direction)
- {
- this.yahooProvider = yahooProvider;
- this.id = id;
- this.contact = contact;
- this.file = file;
- this.direction = direction;
- }
-
- /**
- * Cancels this file transfer. When this method is called transfer should
- * be interrupted.
- */
- @Override
- public void cancel()
- {
- yahooProvider.getYahooSession().cancelRunningFileTransfer(id);
- }
-
- /**
- * Returns the number of bytes already transfered through this file transfer.
- *
- * @return the number of bytes already transfered through this file transfer
- */
- @Override
- public long getTransferedBytes()
- {
- return transferedBytes;
- }
-
- /**
- * Uniquie ID that is identifying the FileTransfer
- * if the request has been accepted.
- *
- * @return the id.
- */
- public String getID()
- {
- return id;
- }
-
- /**
- * The file transfer direction.
- * @return returns the direction of the file transfer : IN or OUT.
- */
- public int getDirection()
- {
- return direction;
- }
-
- /**
- * Returns the file that is transfered.
- *
- * @return the file
- */
- public File getLocalFile()
- {
- return file;
- }
-
- /**
- * Returns the contact that we are transfering files with.
- * @return the contact.
- */
- public Contact getContact()
- {
- return contact;
- }
-
- /**
- * @param transferedBytes the transferedBytes to set
- */
- public void setTransferedBytes(long transferedBytes)
- {
- this.transferedBytes = transferedBytes;
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/IncomingFileTransferRequestYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/IncomingFileTransferRequestYahooImpl.java
deleted file mode 100644
index 25561d0..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/IncomingFileTransferRequestYahooImpl.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-
-/**
- * Implementation of the incoming file transfer request.
- *
- * @author Damian Minkov
- */
-public class IncomingFileTransferRequestYahooImpl
- implements IncomingFileTransferRequest
-{
- private String id;
-
- /**
- * The yahoo provider.
- */
- private ProtocolProviderServiceYahooImpl yahooProvider;
-
- private final OperationSetFileTransferYahooImpl fileTransferOpSet;
-
- private Contact sender;
-
- private Date date;
-
- private String fileName;
-
- private long fileSize;
-
- public IncomingFileTransferRequestYahooImpl(
- ProtocolProviderServiceYahooImpl yahooProvider,
- OperationSetFileTransferYahooImpl fileTransferOpSet,
- Contact sender,
- Date date,
- String fileName,
- String fileSize,
- String id)
- {
- this.yahooProvider = yahooProvider;
- this.fileTransferOpSet = fileTransferOpSet;
- this.sender = sender;
- this.date = date;
- this.fileName = fileName;
-
- try
- {
- this.fileSize = Long.valueOf(fileSize);
- }
- catch (NumberFormatException e)
- {}
-
- this.id = id;
- }
-
- /**
- * Unique ID that is identifying the request and then the FileTransfer
- * if the request has been accepted.
- *
- * @return the id.
- */
- public String getID()
- {
- return id;
- }
-
- /**
- * Returns a String that represents the name of the file that is being
- * received.
- * If there is no name, returns null.
- * @return a String that represents the name of the file
- */
- public String getFileName()
- {
- return fileName;
- }
-
- /**
- * Returns a String that represents the description of the file that is
- * being received.
- * If there is no description available, returns null.
- *
- * @return a String that represents the description of the file
- */
- public String getFileDescription()
- {
- return "";
- }
-
- /**
- * Returns a long that represents the size of the file that is being
- * received.
- * If there is no file size available, returns null.
- *
- * @return a long that represents the size of the file
- */
- public long getFileSize()
- {
- return fileSize;
- }
-
- /**
- * Returns a String that represents the name of the sender of the file
- * being received.
- * If there is no sender name available, returns null.
- *
- * @return a String that represents the name of the sender
- */
- public Contact getSender()
- {
- return sender;
- }
-
- /**
- * Function called to accept and receive the file.
- *
- * @param file the file to accept
- * @return the <tt>FileTransfer</tt> object managing the transfer
- */
- public FileTransfer acceptFile(File file)
- {
- AbstractFileTransfer incomingTransfer = null;
-
- incomingTransfer =
- new FileTransferImpl(yahooProvider,
- id, sender, file, FileTransfer.IN);
-
- yahooProvider.getYahooSession().fileTransferAccept(id, file);
-
- FileTransferCreatedEvent event
- = new FileTransferCreatedEvent(incomingTransfer, new Date());
-
- fileTransferOpSet.fireFileTransferCreated(event);
-
- incomingTransfer.fireStatusChangeEvent(
- FileTransferStatusChangeEvent.PREPARING);
-
- return incomingTransfer;
- }
-
- /**
- * Function called to refuse the file.
- */
- public void rejectFile()
- {
- yahooProvider.getYahooSession().fileTransferReject(id);
-
- fileTransferOpSet.fireFileTransferRequestRejected(
- new FileTransferRequestEvent(
- fileTransferOpSet, this, this.getDate()));
- }
-
- /**
- * @return the date
- */
- public Date getDate()
- {
- return date;
- }
-
- /**
- * Returns the thumbnail contained in this request.
- *
- * @return the thumbnail contained in this request
- */
- public byte[] getThumbnail()
- {
- return null;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/MessageYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/MessageYahooImpl.java
deleted file mode 100644
index e35a3c1..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/MessageYahooImpl.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * A simple implementation of the <tt>Message</tt> interface. Right now the
- * message only supports test contents and no binary data.
- *
- * @author Damian Minkov
- * @author Lubomir Marinov
- */
-public class MessageYahooImpl
- extends AbstractMessage
-{
-
- /**
- * Creates an instance of this Message with the specified parameters.
- *
- * @param content the text content of the message.
- * @param contentType a MIME string indicating the content type of the
- * <tt>content</tt> String.
- * @param contentEncoding a MIME String indicating the content encoding of
- * the <tt>content</tt> String.
- * @param subject the subject of the message or null for empty.
- */
- public MessageYahooImpl(String content, String contentType,
- String contentEncoding, String subject)
- {
- super(content, contentType, contentEncoding, subject);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetAdHocMultiUserChatYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetAdHocMultiUserChatYahooImpl.java
deleted file mode 100644
index dd5f73f..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetAdHocMultiUserChatYahooImpl.java
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.*;
-import ymsg.network.event.*;
-
-/**
- * A Yahoo implementation of the ad-hoc multi user chat operation set.
- *
- * @author Rupert Burchardi
- * @author Valentin Martinet
- * @author Yana Stamcheva
- */
-public class OperationSetAdHocMultiUserChatYahooImpl
-implements OperationSetAdHocMultiUserChat
-{
- private static final Logger logger =
- Logger.getLogger(OperationSetAdHocMultiUserChatYahooImpl.class);
-
- /**
- * A list of listeners subscribed for invitations multi user chat events.
- */
- private final List<AdHocChatRoomInvitationListener> invitationListeners
- = new Vector<AdHocChatRoomInvitationListener>();
-
- /**
- * A list of listeners subscribed for events indicating rejection of a multi
- * user chat invitation sent by us.
- */
- private final List<AdHocChatRoomInvitationRejectionListener>
- invitationRejectionListeners
- = new Vector<AdHocChatRoomInvitationRejectionListener>();
-
- /**
- * Listeners that will be notified of changes in our status in the room such
- * as us being kicked, banned, or granted admin permissions.
- */
- private final List<LocalUserAdHocChatRoomPresenceListener> presenceListeners
- = new Vector<LocalUserAdHocChatRoomPresenceListener>();
-
- /**
- * A list of the rooms that are currently open by this account.
- */
- private final Hashtable<String, AdHocChatRoomYahooImpl> chatRoomCache
- = new Hashtable<String, AdHocChatRoomYahooImpl>();
-
- /**
- * The currently valid Yahoo protocol provider service implementation.
- */
- private final ProtocolProviderServiceYahooImpl yahooProvider;
-
- /**
- * The operation set for the basic instant messaging, provides some message
- * format functions.
- */
- private final OperationSetBasicInstantMessagingYahooImpl opSetBasic;
-
- /**
- * Instantiates the user operation set with a currently valid instance of
- * the Yahoo protocol provider.
- *
- * @param yahooProvider a currently valid instance of
- * ProtocolProviderServiceYahooImpl.
- */
- OperationSetAdHocMultiUserChatYahooImpl(
- ProtocolProviderServiceYahooImpl yahooProvider)
- {
- this.yahooProvider = yahooProvider;
-
- yahooProvider
- .addRegistrationStateChangeListener(new RegistrationStateListener());
-
- opSetBasic =
- (OperationSetBasicInstantMessagingYahooImpl) yahooProvider
- .getOperationSet(OperationSetBasicInstantMessaging.class);
- }
-
- /**
- * Adds a listener to invitation notifications.
- *
- * @param listener An invitation listener.
- */
- public void addInvitationListener(AdHocChatRoomInvitationListener listener)
- {
- synchronized (invitationListeners)
- {
- if (!invitationListeners.contains(listener))
- invitationListeners.add(listener);
- }
- }
-
- /**
- * Removes a listener that was being notified of changes in our status in a
- * room such as us being kicked, banned or dropped.
- *
- * @param listener the <tt>LocalUserAdHocChatRoomPresenceListener</tt>.
- */
- public void removeInvitationListener(
- AdHocChatRoomInvitationListener listener)
- {
- synchronized (invitationListeners)
- {
- invitationListeners.remove(listener);
- }
- }
-
- /**
- * Subscribes <tt>listener</tt> so that it would receive events indicating
- * rejection of a multi user chat invitation that we've sent earlier.
- *
- * @param listener the listener that we'll subscribe for invitation
- * rejection events.
- */
-
- public void addInvitationRejectionListener(
- AdHocChatRoomInvitationRejectionListener listener)
- {
- synchronized (invitationRejectionListeners)
- {
- if (!invitationRejectionListeners.contains(listener))
- invitationRejectionListeners.add(listener);
- }
- }
-
- /**
- * Removes <tt>listener</tt> from the list of invitation listeners
- * registered to receive invitation rejection events.
- *
- * @param listener the invitation listener to remove.
- */
- public void removeInvitationRejectionListener(
- AdHocChatRoomInvitationRejectionListener listener)
- {
- synchronized (invitationRejectionListeners)
- {
- invitationRejectionListeners.remove(listener);
- }
- }
-
- /**
- * Adds a listener that will be notified of changes in our status in a chat
- * room such as us being kicked, banned or dropped.
- *
- * @param listener the <tt>LocalUserAdHocChatRoomPresenceListener</tt>.
- */
- public void addPresenceListener(
- LocalUserAdHocChatRoomPresenceListener listener)
- {
- synchronized (presenceListeners)
- {
- if (!presenceListeners.contains(listener))
- presenceListeners.add(listener);
- }
- }
-
- /**
- * Removes a listener that was being notified of changes in our status in a
- * room such as us being kicked, banned or dropped.
- *
- * @param listener the <tt>LocalUserChatRoomPresenceListener</tt>.
- */
- public void removePresenceListener(
- LocalUserAdHocChatRoomPresenceListener listener)
- {
- synchronized (presenceListeners)
- {
- presenceListeners.remove(listener);
- }
- }
-
- /**
- * Creates a room with the named <tt>roomName</tt> and according to the
- * specified <tt>roomProperties</tt> on the server that this protocol
- * provider is currently connected to. Note the roomProperties also contain
- * users that we like to invite to the chatRoom, this is required in the
- * yahoo protocol.
- *
- * @param roomName the name of the <tt>AdHocChatRoom</tt> to create.
- * @param roomProperties properties specifying how the room should be
- * created.
- *
- * @throws OperationFailedException if the room couldn't be created for some
- * reason (e.g. room already exists; user already joined to an
- * existent room or user has no permissions to create a chat
- * room).
- *
- * @return ChatRoom the chat room that we've just created.
- */
- public AdHocChatRoom createAdHocChatRoom(String roomName,
- Map<String, Object> roomProperties)
- throws OperationFailedException
- {
- return createAdHocChatRoom(roomName, (String[]) null, "");
- }
-
- /**
- * Creates an ad-hoc room with the named <tt>adHocRoomName</tt> and in
- * including to the specified <tt>contacts</tt>. When the method returns the
- * ad-hoc room the local user will have joined it.
- *
- * @return the ad-hoc room that has been just created
- * @param adHocRoomName the name of the room to be created
- * @param contacts the list of contacts ID
- * @param reason the reason for contacts' invitation
- * @throws OperationFailedException if the room couldn't be created for
- * some reason
- */
- public AdHocChatRoom createAdHocChatRoom( String adHocRoomName,
- List<String> contacts,
- String reason)
- throws OperationFailedException
- {
- String[] contactsToInvite = new String[contacts.size()];
- for(int i=0; i<contacts.size(); i++)
- {
- contactsToInvite[i] = contacts.get(i);
- }
- return createAdHocChatRoom(
- adHocRoomName, contactsToInvite, reason);
- }
-
- /**
- * Creates an ad-hoc room with the named <tt>adHocRoomName</tt> and in
- * including to the specified <tt>contacts</tt>. When the method returns the
- * ad-hoc room the local user will have joined it.
- *
- * @param roomName name of the chatroom
- * @param invitedContacts contacts to be invited to this room
- * @param reason reason of this invitation
- * @return AdHocChatRoom the ad-hoc room that has been just created
- * @throws OperationFailedException
- */
- private AdHocChatRoom createAdHocChatRoom(
- String roomName,
- String[] invitedContacts,
- String reason)
- throws OperationFailedException
- {
- if (invitedContacts == null)
- invitedContacts = new String[0];
-
- AdHocChatRoom chatRoom = null;
-
- try
- {
- YahooConference conference =
- yahooProvider.getYahooSession().createConference(
- invitedContacts, // users invited to this conference
- reason, // invite message / topic
- yahooProvider.getYahooSession().getLoginIdentity());
-
- chatRoom = createLocalChatRoomInstance(conference);
- }
- catch (Exception e)
- {
- String errorMessage
- = "Failed to create chat room with name: " + roomName;
-
- if (logger.isDebugEnabled())
- logger.debug(errorMessage, e);
- throw new OperationFailedException(errorMessage,
- OperationFailedException.CHAT_ROOM_NOT_JOINED, e);
- }
- chatRoom.join();
- return chatRoom;
- }
-
- /**
- * Creates a <tt>AdHocChatRoom</tt> instance from the specified Yahoo
- * conference.
- *
- * @param yahooConference The chat room model from the yahoo lib.
- *
- * @return AdHocChatRoom the chat room that we've just created.
- */
- private AdHocChatRoomYahooImpl createLocalChatRoomInstance(
- YahooConference yahooConference)
- {
- synchronized (chatRoomCache)
- {
- AdHocChatRoomYahooImpl newChatRoom
- = new AdHocChatRoomYahooImpl(yahooConference, yahooProvider);
-
- chatRoomCache.put(yahooConference.getName(), newChatRoom);
-
- return newChatRoom;
- }
- }
-
- /**
- * Creates a <tt>AdHocChatRoom</tt> instance (where the inviter is
- * represented by inviterID parameter) from the specified Yahoo conference.
- *
- * @param yahooConference The chat room model from the yahoo lib.
- * @param inviterID inviter's Yahoo ID which has to be added as room member
- *
- * @return AdHocChatRoom the chat room that we've just created.
- */
- private AdHocChatRoomYahooImpl createLocalChatRoomInstance(
- YahooConference yahooConference, String inviterID)
- {
- synchronized (chatRoomCache)
- {
- AdHocChatRoomYahooImpl newChatRoom
- = new AdHocChatRoomYahooImpl(yahooConference, yahooProvider);
-
- OperationSetPersistentPresenceYahooImpl opSetPresence =
- (OperationSetPersistentPresenceYahooImpl) yahooProvider
- .getOperationSet(OperationSetPersistentPresence.class);
-
- newChatRoom.addChatRoomParticipant(
- opSetPresence.findContactByID(inviterID));
- chatRoomCache.put(yahooConference.getName(), newChatRoom);
-
- return newChatRoom;
- }
- }
-
- /**
- * Returns the <tt>AdHocChatRoomYahooImpl</tt> corresponding to the given
- * <tt>conference</tt> if such exists, otherwise returns null.
- *
- * @param conference the <tt>YahooConference</tt>, for which we're searching
- * correspondence
- * @return the <tt>AdHocChatRoomYahooImpl</tt> corresponding to the given
- * <tt>conference</tt> if such exists, otherwise returns null
- */
- private AdHocChatRoomYahooImpl getLocalChatRoomInstance(
- YahooConference conference)
- {
- synchronized (chatRoomCache)
- {
- for (AdHocChatRoomYahooImpl chatRoom : chatRoomCache.values())
- {
- if (chatRoom.getYahooConference().equals(conference))
- return chatRoom;
- }
- }
-
- return null;
- }
-
- /**
- * Informs the sender of an invitation that we decline their invitation.
- *
- * @param invitation the connection to use for sending the rejection.
- * @param rejectReason the reason to reject the given invitation
- */
- public void rejectInvitation(AdHocChatRoomInvitation invitation,
- String rejectReason)
- {
- AdHocChatRoomYahooImpl chatRoom =
- (AdHocChatRoomYahooImpl) invitation.getTargetAdHocChatRoom();
-
- try
- {
- yahooProvider.getYahooSession().declineConferenceInvite(
- chatRoom.getYahooConference(), rejectReason);
- }
- catch (IOException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to reject Invitation: " + e);
- }
- }
-
- /**
- * Delivers a <tt>AdHocChatRoomInvitationReceivedEvent</tt> to all
- * registered <tt>AdHocChatRoomInvitationListener</tt>s.
- *
- * @param targetChatRoom the room that invitation refers to
- * @param inviter the inviter that sent the invitation
- * @param reason the reason why the inviter sent the invitation
- */
- public void fireInvitationEvent(AdHocChatRoom targetChatRoom,
- String inviter, String reason)
- {
- AdHocChatRoomInvitationYahooImpl invitation =
- new AdHocChatRoomInvitationYahooImpl(targetChatRoom, inviter,
- reason);
-
- AdHocChatRoomInvitationReceivedEvent evt =
- new AdHocChatRoomInvitationReceivedEvent(this, invitation,
- new Date(System.currentTimeMillis()));
-
- Iterable<AdHocChatRoomInvitationListener> listeners;
- synchronized (invitationListeners)
- {
- listeners
- = new ArrayList<AdHocChatRoomInvitationListener>(
- invitationListeners);
- }
-
- for (AdHocChatRoomInvitationListener listener : listeners)
- listener.invitationReceived(evt);
- }
-
- /**
- * Delivers a <tt>AdHocChatRoomInvitationRejectedEvent</tt> to all
- * registered <tt>AdHocChatRoomInvitationRejectionListener</tt>s.
- *
- * @param sourceChatRoom the room that invitation refers to
- * @param invitee the name of the invitee that rejected the invitation
- * @param reason the reason of the rejection
- */
- public void fireInvitationRejectedEvent(AdHocChatRoom sourceChatRoom,
- String invitee, String reason)
- {
- AdHocChatRoomInvitationRejectedEvent evt =
- new AdHocChatRoomInvitationRejectedEvent(
- this, sourceChatRoom, invitee,
- reason, new Date(System.currentTimeMillis()));
-
- Iterable<AdHocChatRoomInvitationRejectionListener> listeners;
- synchronized (invitationRejectionListeners)
- {
- listeners
- = new ArrayList<AdHocChatRoomInvitationRejectionListener>(
- invitationRejectionListeners);
- }
-
- for (AdHocChatRoomInvitationRejectionListener listener : listeners)
- listener.invitationRejected(evt);
- }
-
- /**
- * Delivers a <tt>LocalUserAdHocChatRoomPresenceChangeEvent</tt> to all
- * registered <tt>LocalUserAdHocChatRoomPresenceListener</tt>s.
- *
- * @param chatRoom the <tt>ChatRoom</tt> which has been joined, left, etc.
- * @param eventType the type of this event; one of LOCAL_USER_JOINED,
- * LOCAL_USER_LEFT, etc.
- * @param reason the reason
- */
- public void fireLocalUserPresenceEvent(AdHocChatRoom chatRoom,
- String eventType, String reason)
- {
- LocalUserAdHocChatRoomPresenceChangeEvent evt =
- new LocalUserAdHocChatRoomPresenceChangeEvent(
- this, chatRoom, eventType,
- reason);
-
- Iterable<LocalUserAdHocChatRoomPresenceListener> listeners;
- synchronized (presenceListeners)
- {
- listeners =
- new ArrayList<LocalUserAdHocChatRoomPresenceListener>(
- presenceListeners);
- }
-
- for (LocalUserAdHocChatRoomPresenceListener listener : listeners)
- listener.localUserAdHocPresenceChanged(evt);
- }
-
- /**
- * Create a Message instance for sending arbitrary MIME-encoding content.
- *
- * @param content content value
- * @param contentType the MIME-type for <tt>content</tt>
- * @param contentEncoding encoding used for <tt>content</tt>
- * @param subject a <tt>String</tt> subject or <tt>null</tt> for now
- * subject.
- * @return the newly created message.
- * @throws UnsupportedEncodingException missing utf-8 in platform we use.
- */
- private Message createMessage(byte[] content, String contentType,
- String contentEncoding, String subject)
- throws UnsupportedEncodingException
- {
- return new MessageYahooImpl(new String(content, "UTF-8"), contentType,
- contentEncoding, subject);
- }
-
- /**
- * Creates a message by a given message text.
- *
- * @param messageText The message text.
- * @return the newly created message.
- */
- public Message createMessage(String messageText)
- {
- return new MessageYahooImpl(messageText,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_ENCODING, null);
- }
-
- /**
- * Our listener that will tell us when we're registered to yahoo network.
- *
- */
- private class RegistrationStateListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenever a
- * change in the registration state of the corresponding provider had
- * occurred.
- *
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
- if (evt.getNewState() == RegistrationState.REGISTERED)
- {
- yahooProvider.getYahooSession().addSessionListener(
- new YahooMessageListener());
- }
- }
- }
-
- /**
- * Our group chat message listener, it extends the SessionAdapter from the
- * the Yahoo library.
- *
- */
- private class YahooMessageListener
- extends SessionAdapter
- {
-
- @Override
- public void conferenceInviteDeclinedReceived(SessionConferenceEvent ev)
- {
- if (logger.isDebugEnabled())
- logger.debug("Group Chat invite declined received. "
- + ev.toString());
- try
- {
- AdHocChatRoom chatRoom = getLocalChatRoomInstance(ev.getRoom());
-
- fireInvitationRejectedEvent(chatRoom, ev.getFrom(), ev
- .getMessage());
- }
- catch (Exception e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Error: " + e);
- }
- }
-
- @Override
- public void conferenceInviteReceived(SessionConferenceEvent ev)
- {
- if (logger.isDebugEnabled())
- logger.debug("Conference Invite Received: " + ev.toString());
-
- try
- {
- AdHocChatRoom chatRoom = getLocalChatRoomInstance(ev.getRoom());
-
- if (chatRoom == null)
- {
- chatRoom =
- createLocalChatRoomInstance(ev.getRoom(), ev.getFrom());
-
- fireInvitationEvent(
- chatRoom, ev.getFrom(), ev.getMessage());
- }
-
- }
- catch (Exception e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Error: " + e);
- }
- }
-
- @Override
- public void conferenceLogoffReceived(SessionConferenceEvent ev)
- {
- if (logger.isDebugEnabled())
- logger.debug("Conference Logoff Received: " + ev.toString());
-
- try
- {
- AdHocChatRoomYahooImpl chatRoom
- = getLocalChatRoomInstance(ev.getRoom());
-
- if (chatRoom != null)
- {
- Contact participant =
- chatRoom.findParticipantForAddress(ev.getFrom());
-
- chatRoom.removeChatRoomParticipant(participant);
- }
- }
- catch (Exception e)
- {
- logger
- .debug("Failed to remove a user from the chat room. " + e);
- }
- }
-
- @Override
- public void conferenceLogonReceived(SessionConferenceEvent ev)
- {
- if (logger.isDebugEnabled())
- logger.debug("Conference Logon Received: " + ev.toString());
-
- try
- {
- AdHocChatRoomYahooImpl chatRoom
- = getLocalChatRoomInstance(ev.getRoom());
-
- if (chatRoom != null)
- {
- OperationSetPersistentPresenceYahooImpl presenceOpSet =
- (OperationSetPersistentPresenceYahooImpl) chatRoom
- .getParentProvider().getOperationSet(
- OperationSetPersistentPresence.class);
-
- Contact participant =
- presenceOpSet.findContactByID(ev.getFrom());
-
- chatRoom.addChatRoomParticipant(participant);
- }
- }
- catch (Exception e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to add a user to the chat room. " + e);
- }
- }
-
- @Override
- public void conferenceMessageReceived(SessionConferenceEvent ev)
- {
- if (logger.isDebugEnabled())
- logger.debug("Conference Message Received: " + ev.toString());
-
- try
- {
- String formattedMessage = ev.getMessage();
- if (logger.isDebugEnabled())
- logger.debug("original message received : " + formattedMessage);
-
- formattedMessage = opSetBasic.decodeMessage(formattedMessage);
- if (logger.isDebugEnabled())
- logger.debug("formatted Message : " + formattedMessage);
- // As no indications in the protocol is it html or not. No harm
- // to set all messages html - doesn't affect the appearance of
- // the gui
-
- Message newMessage =
- createMessage(
- formattedMessage.getBytes("UTF-8"),
- OperationSetBasicInstantMessaging.HTML_MIME_TYPE,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_ENCODING,
- null);
-
- AdHocChatRoomYahooImpl chatRoom =
- getLocalChatRoomInstance(ev.getRoom());
-
- if (chatRoom != null)
- {
- Contact member =
- chatRoom.findParticipantForAddress(ev.getFrom());
-
- AdHocChatRoomMessageReceivedEvent msgReceivedEvent =
- new AdHocChatRoomMessageReceivedEvent(
- chatRoom,
- member,
- new Date(),
- newMessage,
- AdHocChatRoomMessageReceivedEvent
- .CONVERSATION_MESSAGE_RECEIVED);
-
- chatRoom.fireMessageEvent(msgReceivedEvent);
- }
- }
- catch (Exception e)
- {
- logger
- .debug("Error while receiving a multi user chat message: "
- + e);
- }
-
- }
-
- @Override
- public void connectionClosed(SessionEvent ev)
- {
- if (logger.isDebugEnabled())
- logger.debug("Connection Closed: " + ev.toString());
- }
- }
-
- public List<AdHocChatRoom> getAdHocChatRooms()
- {
- return new ArrayList<AdHocChatRoom>(chatRoomCache.values());
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetBasicInstantMessagingYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetBasicInstantMessagingYahooImpl.java
deleted file mode 100644
index 84059de..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetBasicInstantMessagingYahooImpl.java
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-import java.util.*;
-import java.util.regex.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.event.*;
-import ymsg.support.*;
-
-/**
- * A straightforward implementation of the basic instant messaging operation
- * set.
- *
- * @author Damian Minkov
- * @author Symphorien Wanko
- * @author Keio Kraaner
- */
-public class OperationSetBasicInstantMessagingYahooImpl
- extends AbstractOperationSetBasicInstantMessaging
- implements OperationSetInstantMessageFiltering
-{
- /**
- * Logger for this class
- */
- private static final Logger logger =
- Logger.getLogger(OperationSetBasicInstantMessagingYahooImpl.class);
-
- /**
- * Yahoo has limit of message length. If exceeded
- * message is not delivered and no notification is received for that.
- */
- private static final int MAX_MESSAGE_LENGTH = 800; // 949
-
- /**
- * A regexp that is used to escape some chars in messages.
- */
- private static final Pattern MESSAGE_CHARS_ESCAPE = Pattern.compile("([.()^&$*|])");
-
- /**
- * A list of filters registered for message events.
- */
- private final List<EventFilter> eventFilters = new ArrayList<EventFilter>();
-
- /**
- * The provider that created us.
- */
- private ProtocolProviderServiceYahooImpl yahooProvider = null;
-
- /**
- * Message decoder allows to convert Yahoo formated messages, which can
- * contains some specials characters, to HTML or to plain text.
- */
- private final MessageDecoder messageDecoder = new MessageDecoder();
-
- /**
- * A reference to the persistent presence operation set that we use
- * to match incoming messages to <tt>Contact</tt>s and vice versa.
- */
- private OperationSetPersistentPresenceYahooImpl opSetPersPresence = null;
- private static final Pattern FONT_SIZE_0_PATTERN = Pattern.compile("(<font) (.*) size=\"0\">");
- private static final Pattern FONT_SIZE_INT_PATTERN = Pattern.compile("(<font) (.*) size=\"(\\d+)\">");
-
- /**
- * Creates an instance of this operation set.
- * @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
- * that created us and that we'll use for retrieving the underlying aim
- * connection.
- */
- OperationSetBasicInstantMessagingYahooImpl(
- ProtocolProviderServiceYahooImpl provider)
- {
- this.yahooProvider = provider;
- provider.addRegistrationStateChangeListener(
- new RegistrationStateListener());
- }
-
- /**
- * Determines wheter the protocol provider (or the protocol itself) support
- * sending and receiving offline messages. Most often this method would
- * return true for protocols that support offline messages and false for
- * those that don't. It is however possible for a protocol to support these
- * messages and yet have a particular account that does not (i.e. feature
- * not enabled on the protocol server). In cases like this it is possible
- * for this method to return true even when offline messaging is not
- * supported, and then have the sendMessage method throw an
- * OperationFailedException with code - OFFLINE_MESSAGES_NOT_SUPPORTED.
- *
- * @return <tt>true</tt> if the protocol supports offline messages and
- * <tt>false</tt> otherwise.
- */
- public boolean isOfflineMessagingSupported()
- {
- return true;
- }
-
- /**
- * Determines wheter the protocol supports the supplied content type
- *
- * @param contentType the type we want to check
- * @return <tt>true</tt> if the protocol supports it and
- * <tt>false</tt> otherwise.
- */
- public boolean isContentTypeSupported(String contentType)
- {
- if(contentType.equals(DEFAULT_MIME_TYPE) ||
- contentType.equals(HTML_MIME_TYPE))
- return true;
- else
- return false;
- }
-
- @Override
- public Message createMessage(String content, String contentType,
- String encoding, String subject)
- {
- return new MessageYahooImpl(content, contentType, encoding, subject);
- }
-
- /**
- * Sends the <tt>message</tt> to the destination indicated by the
- * <tt>to</tt> contact.
- *
- * @param to the <tt>Contact</tt> to send <tt>message</tt> to
- * @param message the <tt>Message</tt> to send.
- * @throws IllegalStateException if the underlying stack is
- * not registered and initialized.
- * @throws IllegalArgumentException if <tt>to</tt> is not an
- * instance of ContactImpl.
- */
- public void sendInstantMessage(Contact to, Message message)
- throws IllegalStateException, IllegalArgumentException
- {
- assertConnected();
-
- if( !(to instanceof ContactYahooImpl) )
- throw new IllegalArgumentException(
- "The specified contact is not a Yahoo contact."
- + to);
-
- try
- {
- String toUserID = ((ContactYahooImpl) to).getID();
-
- MessageDeliveredEvent msgDeliveryPendingEvt =
- new MessageDeliveredEvent(message, to, new Date());
-
- MessageDeliveredEvent[] msgDeliveryPendingEvts = messageDeliveryPendingTransform(msgDeliveryPendingEvt);
-
- if (msgDeliveryPendingEvts == null || msgDeliveryPendingEvts.length == 0)
- return;
-
- for (MessageDeliveredEvent event : msgDeliveryPendingEvts)
- {
- byte[] msgBytesToBeSent =
- event.getSourceMessage().getContent().trim()
- .getBytes("UTF-8");
-
- // split the message in parts with max allowed length
- // and send them all
- do
- {
- if (msgBytesToBeSent.length > MAX_MESSAGE_LENGTH)
- {
- byte[] tmp1 = new byte[MAX_MESSAGE_LENGTH];
- System.arraycopy(msgBytesToBeSent, 0, tmp1, 0,
- MAX_MESSAGE_LENGTH);
-
- byte[] tmp2 =
- new byte[msgBytesToBeSent.length
- - MAX_MESSAGE_LENGTH];
- System.arraycopy(msgBytesToBeSent, MAX_MESSAGE_LENGTH,
- tmp2, 0, tmp2.length);
-
- msgBytesToBeSent = tmp2;
-
- yahooProvider.getYahooSession().sendMessage(toUserID,
- new String(tmp1, "UTF-8"));
- }
- else
- {
- yahooProvider.getYahooSession().sendMessage(toUserID,
- new String(msgBytesToBeSent, "UTF-8"));
- }
-
- MessageDeliveredEvent msgDeliveredEvt =
- new MessageDeliveredEvent(message, to, new Date());
-
- if (msgDeliveredEvt != null)
- fireMessageEvent(msgDeliveredEvt);
- }
- while (msgBytesToBeSent.length > MAX_MESSAGE_LENGTH);
- }
- }
- catch (IOException ex)
- {
- logger.fatal("Cannot Send Message! " + ex.getMessage());
- MessageDeliveryFailedEvent evt =
- new MessageDeliveryFailedEvent(
- message,
- to,
- MessageDeliveryFailedEvent.NETWORK_FAILURE);
-
- if (evt != null)
- fireMessageEvent(evt);
- }
- }
-
- /**
- * Utility method throwing an exception if the stack is not properly
- * initialized.
- * @throws IllegalStateException if the underlying stack is
- * not registered and initialized.
- */
- private void assertConnected() throws IllegalStateException
- {
- if (yahooProvider == null)
- throw new IllegalStateException(
- "The provider must be non-null and signed on the "
- +"service before being able to communicate.");
- if (!yahooProvider.isRegistered())
- throw new IllegalStateException(
- "The provider must be signed on the service before "
- +"being able to communicate.");
- }
-
- /**
- * Our listener that will tell us when we're registered to
- */
- private class RegistrationStateListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenver
- * a change in the registration state of the corresponding provider had
- * occurred.
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
- if (logger.isDebugEnabled())
- logger.debug("The provider changed state from: "
- + evt.getOldState()
- + " to: " + evt.getNewState());
-
- if (evt.getNewState() == RegistrationState.REGISTERED)
- {
- opSetPersPresence =
- (OperationSetPersistentPresenceYahooImpl) yahooProvider
- .getOperationSet(OperationSetPersistentPresence.class);
-
- yahooProvider.getYahooSession().
- addSessionListener(new YahooMessageListener());
- }
- }
- }
-
- /**
- * Delivers the specified event to all registered message listeners.
- * @param evt the <tt>EventObject</tt> that we'd like delivered to all
- * registered message listerners.
- */
- @Override
- protected void fireMessageEvent(EventObject evt)
- {
- // check if this event should be filtered out
- Iterator<EventFilter> filters;
- synchronized (eventFilters)
- {
- filters = new ArrayList<EventFilter>(eventFilters).iterator();
- }
- // return if a filter has filtered this event out
- boolean filtered = false;
- while (filters.hasNext())
- {
- try
- {
- if (filters.next().filterEvent(evt))
- {
- filtered = true;
- }
- }
- catch(Exception exc)
- {
- logger.error("An exception occurred while filtering an event.",
- exc);
- }
- }
-
- if (filtered)
- {
- if (logger.isTraceEnabled())
- logger.trace("Message event filtered.");
- return;
- }
-
- super.fireMessageEvent(evt);
- }
-
- /**
- * This class provides methods to listen for yahoo events which interest us.
- */
- private class YahooMessageListener
- extends SessionAdapter
- {
- /**
- * Overrides <tt>messageReceived</tt> from <tt>SessionAdapter</tt>,
- * called when we receive a new intant message.
- *
- * @param ev Event with information on the received message
- */
- @Override
- public void messageReceived(SessionEvent ev)
- {
- handleNewMessage(ev);
- }
-
- /**
- * Overrides <tt>offlineMessageReceived</tt> from <tt>SessionAdapter</tt>,
- * called when we receive a message which has been sent to us
- * when we were offline.
- *
- * @param ev Event with information on the received message
- */
- @Override
- public void offlineMessageReceived(SessionEvent ev)
- {
- handleNewMessage(ev);
- }
-
- /**
- * Overrides <tt>newMailReceived</tt> from <tt>SessionAdapter</tt>,
- * called when yahoo alert us that there is a new message in our mailbox.
- * There is two types of notification, the first one provides only
- * the number of unread mails and the second gives informations about
- * a precise new mail. Here, we care about only the second case in which
- * we should always have the email of the sender of the mail.
- *
- * @param ev Event with information on the received email
- */
- @Override
- public void newMailReceived(SessionNewMailEvent ev)
- {
- // why, if I provide mail@yahoo.FR when registering my account,
- // SC later tells me that my email address is mail@yahoo.COM ??
- // because of this users will always be sent on yahoo.com mail
- // login page rather than their usual (yahoo.XXX) login page.
- String myEmail = yahooProvider.getAccountID().getAccountAddress();
-
- // we don't process incoming email event without source address.
- // it allows us to avoid some spams
- if ((ev.getEmailAddress() == null)
- || (ev.getEmailAddress().indexOf('@') < 0))
- {
- return;
- }
-
- String yahooMailLogon = "http://mail."
- + myEmail.substring(myEmail.indexOf('@') + 1);
-
- yahooMailLogon = "&nbsp;&nbsp;&nbsp;&nbsp;<a href=\""
- + yahooMailLogon + "\">"
- + yahooMailLogon + "</a>";
-
- // FIXME Escape HTML!
- String newMail = YahooActivator.getResources().getI18NString(
- "service.gui.NEW_MAIL",
- new String[]{ev.getFrom(),
- "&lt;" + ev.getEmailAddress() + "&gt;",
- ev.getSubject(),
- "&nbsp;&nbsp;&nbsp;&nbsp;"+yahooMailLogon}) ;
-
- Message newMailMessage = new MessageYahooImpl(
- newMail,
- HTML_MIME_TYPE,
- DEFAULT_MIME_ENCODING,
- null);
-
- Contact sourceContact = opSetPersPresence.
- findContactByID(ev.getEmailAddress());
-
- if (sourceContact == null)
- {
- if (logger.isDebugEnabled())
- logger.debug("received a new mail from an unknown contact: "
- + ev.getFrom()
- + " &lt;" + ev.getEmailAddress() + "&gt;");
- //create the volatile contact
- sourceContact = opSetPersPresence
- .createVolatileContact(ev.getEmailAddress());
- }
- MessageReceivedEvent msgReceivedEvt
- = new MessageReceivedEvent(
- newMailMessage, sourceContact, new Date(),
- MessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED);
-
- fireMessageEvent(msgReceivedEvt);
- }
-
- /**
- * Handle incoming message by creating an appropriate Sip Communicator
- * <tt>Message</tt> and firing a <tt>MessageReceivedEvent</tt>
- * to interested listeners.
- *
- * @param ev The original <tt>SessionEvent</tt> which noticed us
- * of an incoming message.
- */
- private void handleNewMessage(SessionEvent ev)
- {
- if (logger.isDebugEnabled())
- logger.debug("Message received : " + ev);
-
- // to keep things simple, we can decodeToText()
- //String formattedMessage = processLinks(
- // messageDecoder.decodeToText(ev.getMessage()));
-
- String formattedMessage = ev.getMessage();
- if (logger.isDebugEnabled())
- logger.debug("original message received : " + formattedMessage);
-
- formattedMessage = decodeMessage(formattedMessage);
-
- if (logger.isDebugEnabled())
- logger.debug("formatted Message : " + formattedMessage);
- // As no indications in the protocol is it html or not. No harm
- // to set all messages html - doesn't affect the appearance of the
- // gui
- Message newMessage =
- createMessage(formattedMessage, HTML_MIME_TYPE,
- DEFAULT_MIME_ENCODING, null);
-
- Contact sourceContact = opSetPersPresence.
- findContactByID(ev.getFrom());
-
- if(sourceContact == null)
- {
- if (logger.isDebugEnabled())
- logger.debug("received a message from an unknown contact: "
- + ev.getFrom());
- //create the volatile contact
- sourceContact = opSetPersPresence
- .createVolatileContact(ev.getFrom());
- }
-
- MessageReceivedEvent msgReceivedEvt
- = new MessageReceivedEvent(
- newMessage, sourceContact , new Date());
-
- // msgReceivedEvt = messageReceivedTransform(msgReceivedEvt);
-
- if (msgReceivedEvt != null)
- fireMessageEvent(msgReceivedEvt);
- }
- }
-
- /**
- * Decode the received chat message.
- * If the message contains \u001b the following text is decoded by
- * the MessageDecoder of yahoo api
- * Then make http links clickable and fix the font size of html code
- *
- * @param message the chat message
- * @return a decoded message.
- */
- String decodeMessage(String message)
- {
- message = messageDecoder.decodeToHTML(message);
- message = processLinks(message);
- message =
- FONT_SIZE_0_PATTERN.matcher(message)
- .replaceAll("$1 $2 size=\"10\">");
- message =
- FONT_SIZE_INT_PATTERN.matcher(message)
- .replaceAll("$1 $2 style=\"font-size: $3px;\">");
- return message;
- }
-
- /**
- * Format links in the given message. Skips all links, which are already in
- * HTML format and converts all other links.
- *
- * @param message The source message string.
- * @return The message string with properly formatted links.
- */
- public String processLinks(String message)
- {
- StringBuffer msgBuffer = new StringBuffer();
-
- // We match two groups of Strings. The first group is the group of any
- // String. The second group is a well formatted HTML link.
- Pattern p = Pattern.compile("(.*?)(<a[\\s][^<]*(/>|</a>))",
- Pattern.CASE_INSENSITIVE);
-
- Matcher m = p.matcher(message);
-
- int lastMatchIndex = 0;
- while (m.find())
- {
- lastMatchIndex = m.end();
-
- String matchGroup1 = m.group(1);
- String matchGroup2 = m.group(2);
-
- String formattedString = formatLinksToHTML(matchGroup1);
-
- m.appendReplacement(msgBuffer,
- replaceSpecialRegExpChars(formattedString) + matchGroup2);
- }
-
- String tailString = message.substring(lastMatchIndex);
-
- String formattedTailString = formatLinksToHTML(tailString);
-
- msgBuffer.append(formattedTailString);
-
- return msgBuffer.toString();
- }
-
- /**
- * Replaces some chars that are special in a regular expression.
- *
- * @param text The initial text.
- * @return the formatted text
- */
- private static String replaceSpecialRegExpChars(String text)
- {
- return MESSAGE_CHARS_ESCAPE.matcher(text).replaceAll("\\\\$1");
- }
-
- /**
- * Goes through the given text and converts all links to HTML links.
- * <p>
- * For example all occurrences of http://jitsi.org/ will be
- * replaced by <a href="http://jitsi.org/">
- * http://jitsi.org/</a>. The same is true for all strings
- * starting with "www".
- *
- * @param text the text on which the regular expression would be performed
- * @return the initial text containing only HTML links
- */
- private static String formatLinksToHTML(String text)
- {
- String wwwURL = "(www\\." + // Matches the "www" string.
- "[^/?#<\"'\\s]+" + // Matches at least one char of
- // any type except / ? # < " '
- // and space.
- "[\\.]" + // Matches the second point of the link.
- "[^?#<\"'\\s]+" + // Matches at least one char of
- // any type except ? # < " '
- // and space.
- "(\\?[^#<\"'\\s]*)?" +
- "(#.*)?)";
-
- String protocolURL
- = "([^\"'<>:/?#\\s]+" + // Matches at least one char of
- // any type except " ' < > : / ? #
- // and space.
- "://" + // Matches the :// delimiter in links
- "[^/?#<\"'\\s]*" + // Matches any number of times any char
- // except / ? # < " ' and space.
- "[^?#<\"'\\s]*" + // Matches any number of times any char
- // except ? # < " ' and space.
- "(\\?[^#<\"'\\s]*)?" +
- "(#.*)?)";
-
- String url = '(' + wwwURL + '|' + protocolURL + ')';
-
- Pattern p = Pattern.compile(url, Pattern.CASE_INSENSITIVE);
-
- Matcher m = p.matcher(text);
-
- StringBuffer linkBuffer = new StringBuffer();
-
- while (m.find())
- {
- String linkGroup = m.group();
-
- String replacement;
- if (linkGroup.startsWith("www"))
- {
- replacement = "<A href=\"" + "http://"
- + linkGroup + "\">" + linkGroup + "</A>";
- }
- else
- {
- replacement = "<A href=\"" + linkGroup
- + "\">" + linkGroup + "</A>";
- }
-
- m.appendReplacement(linkBuffer,
- replaceSpecialRegExpChars(replacement));
- }
-
- m.appendTail(linkBuffer);
-
- return linkBuffer.toString();
- }
-
- /**
- * Registers an <tt>EventFilter</tt> with this operation set so that
- * events, that do not need processing, are filtered out.
- *
- * @param filter the <tt>EventFilter</tt> to register.
- */
- public void addEventFilter(EventFilter filter)
- {
- synchronized(eventFilters)
- {
- if(!eventFilters.contains(filter))
- {
- eventFilters.add(filter);
- }
- }
- }
-
- /**
- * Unregisteres an <tt>EventFilter</tt> so that it won't check any more
- * if an event should be filtered out.
- *
- * @param filter the <tt>EventFilter</tt> to unregister.
- */
- public void removeEventFilter(EventFilter filter)
- {
- synchronized(eventFilters)
- {
- eventFilters.remove(filter);
- }
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetFileTransferYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetFileTransferYahooImpl.java
deleted file mode 100644
index 85f25b1..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetFileTransferYahooImpl.java
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.event.*;
-
-/**
- * The Yahoo protocol filetransfer OperationSet.
- *
- * @author Damian Minkov
- */
-public class OperationSetFileTransferYahooImpl
- implements OperationSetFileTransfer,
- SessionFileTransferListener
-{
- /**
- * The logger for this class.
- */
- private static final Logger logger =
- Logger.getLogger(OperationSetFileTransferYahooImpl.class);
-
- /**
- * The provider that created us.
- */
- private final ProtocolProviderServiceYahooImpl yahooProvider;
-
- /**
- * A list of listeners registered for file transfer events.
- */
- private ArrayList<FileTransferListener> fileTransferListeners
- = new ArrayList<FileTransferListener>();
-
- /**
- * A list of active fileTransfers.
- */
- private Hashtable<String, Object> activeFileTransfers
- = new Hashtable<String, Object>();
-
- /**
- * Constructor
- * @param provider is the provider that created us
- */
- public OperationSetFileTransferYahooImpl(
- ProtocolProviderServiceYahooImpl provider)
- {
- this.yahooProvider = provider;
-
- provider.addRegistrationStateChangeListener(
- new RegistrationStateListener());
- }
-
- /**
- * Sends a file transfer request to the given <tt>toContact</tt> by
- * specifying the local and remote file path and the <tt>fromContact</tt>,
- * sending the file.
- *
- * @param toContact the contact that should receive the file
- * @param file the file to send
- *
- * @return the transfer object
- *
- * @throws IllegalStateException if the protocol provider is not registered
- * or connected
- * @throws IllegalArgumentException if some of the arguments doesn't fit the
- * protocol requirements
- */
- public FileTransfer sendFile( Contact toContact,
- File file)
- throws IllegalStateException,
- IllegalArgumentException
- {
- try
- {
- assertConnected();
-
- if(file.length() > getMaximumFileLength())
- throw new IllegalArgumentException(
- "File length exceeds the allowed one for this protocol");
-
- ArrayList<String> filesToSend = new ArrayList<String>();
- filesToSend.add(file.getCanonicalPath());
- Date sentDate = new Date();
- String id = yahooProvider.getYahooSession().sendFiles(
- filesToSend, toContact.getAddress());
-
- FileTransferImpl ft =
- new FileTransferImpl(yahooProvider,
- id, toContact, file, FileTransfer.OUT);
-
- // Notify all interested listeners that a file transfer has been
- // created.
- FileTransferCreatedEvent event
- = new FileTransferCreatedEvent(ft, sentDate);
-
- fireFileTransferCreated(event);
-
- ft.fireStatusChangeEvent(FileTransferStatusChangeEvent.PREPARING);
-
- return ft;
- }
- catch(IOException e)
- {
- logger.error("Cannot send fileTransfer", e);
- return null;
- }
- }
-
- /**
- * Sends a file transfer request to the given <tt>toContact</tt> by
- * specifying the local and remote file path and the <tt>fromContact</tt>,
- * sending the file.
- *
- * @param toContact the contact that should receive the file
- * @param fromContact the contact sending the file
- * @param remotePath the remote file path
- * @param localPath the local file path
- *
- * @return the transfer object
- *
- * @throws IllegalStateException if the protocol provider is not registered
- * or connected
- * @throws IllegalArgumentException if some of the arguments doesn't fit the
- * protocol requirements
- */
- public FileTransfer sendFile( Contact toContact,
- Contact fromContact,
- String remotePath,
- String localPath)
- throws IllegalStateException,
- IllegalArgumentException
- {
- return this.sendFile(toContact, new File(localPath));
- }
-
- /**
- * Adds the given <tt>FileTransferListener</tt> that would listen for
- * file transfer requests and created file transfers.
- *
- * @param listener the <tt>FileTransferListener</tt> to add
- */
- public void addFileTransferListener(
- FileTransferListener listener)
- {
- synchronized(fileTransferListeners)
- {
- if(!fileTransferListeners.contains(listener))
- {
- this.fileTransferListeners.add(listener);
- }
- }
- }
-
- /**
- * Removes the given <tt>FileTransferListener</tt> that listens for
- * file transfer requests and created file transfers.
- *
- * @param listener the <tt>FileTransferListener</tt> to remove
- */
- public void removeFileTransferListener(
- FileTransferListener listener)
- {
- synchronized(fileTransferListeners)
- {
- this.fileTransferListeners.remove(listener);
- }
- }
-
- /**
- * Utility method throwing an exception if the stack is not properly
- * initialized.
- * @throws java.lang.IllegalStateException if the underlying stack is
- * not registered and initialized.
- */
- private void assertConnected()
- throws IllegalStateException
- {
- if (yahooProvider == null)
- throw new IllegalStateException(
- "The provider must be non-null and signed on the "
- +"service before being able to send a file.");
- else if (!yahooProvider.isRegistered())
- throw new IllegalStateException(
- "The provider must be signed on the service before "
- +"being able to send a file.");
- }
-
- /**
- * Delivers the file transfer to all registered listeners.
- *
- * @param event the <tt>FileTransferEvent</tt> that we'd like delivered to
- * all registered file transfer listeners.
- */
- void fireFileTransferCreated(FileTransferCreatedEvent event)
- {
- activeFileTransfers.put(
- event.getFileTransfer().getID(), event.getFileTransfer());
-
- Iterator<FileTransferListener> listeners = null;
- synchronized (fileTransferListeners)
- {
- listeners = new ArrayList<FileTransferListener>
- (fileTransferListeners).iterator();
- }
-
- while (listeners.hasNext())
- {
- FileTransferListener listener = listeners.next();
- listener.fileTransferCreated(event);
- }
- }
-
- /**
- * Delivers the specified event to all registered file transfer listeners.
- *
- * @param event the <tt>EventObject</tt> that we'd like delivered to all
- * registered file transfer listeners.
- */
- void fireFileTransferRequestRejected(FileTransferRequestEvent event)
- {
- Iterator<FileTransferListener> listeners = null;
- synchronized (fileTransferListeners)
- {
- listeners = new ArrayList<FileTransferListener>
- (fileTransferListeners).iterator();
- }
-
- while (listeners.hasNext())
- {
- FileTransferListener listener = listeners.next();
-
- listener.fileTransferRequestRejected(event);
- }
- }
-
- /**
- * Delivers the specified event to all registered file transfer listeners.
- *
- * @param event the <tt>EventObject</tt> that we'd like delivered to all
- * registered file transfer listeners.
- */
- private void fireFileTransferRequest(FileTransferRequestEvent event)
- {
- Iterator<FileTransferListener> listeners = null;
- synchronized (fileTransferListeners)
- {
- listeners = new ArrayList<FileTransferListener>
- (fileTransferListeners).iterator();
- }
-
- while (listeners.hasNext())
- {
- FileTransferListener listener = listeners.next();
-
- listener.fileTransferRequestReceived(event);
- }
- }
-
- /**
- * Delivers the specified event to all registered file transfer listeners.
- *
- * @param event the <tt>EventObject</tt> that we'd like delivered to all
- * registered file transfer listeners.
- */
- void fireFileTransferRequestCanceled(FileTransferRequestEvent event)
- {
- Iterator<FileTransferListener> listeners = null;
- synchronized (fileTransferListeners)
- {
- listeners = new ArrayList<FileTransferListener>
- (fileTransferListeners).iterator();
- }
-
- while (listeners.hasNext())
- {
- FileTransferListener listener = listeners.next();
-
- listener.fileTransferRequestCanceled(event);
- }
- }
-
- private int getStateMapping(int s)
- {
- switch(s)
- {
- case SessionFileTransferEvent.REFUSED :
- return FileTransferStatusChangeEvent.REFUSED;
- case SessionFileTransferEvent.CANCEL :
- return FileTransferStatusChangeEvent.CANCELED;
- case SessionFileTransferEvent.FAILED :
- return FileTransferStatusChangeEvent.FAILED;
- case SessionFileTransferEvent.IN_PROGRESS :
- return FileTransferStatusChangeEvent.IN_PROGRESS;
- case SessionFileTransferEvent.RECEIVED :
- return FileTransferStatusChangeEvent.COMPLETED;
- case SessionFileTransferEvent.SENT :
- return FileTransferStatusChangeEvent.COMPLETED;
- default: return FileTransferStatusChangeEvent.WAITING;
- }
- }
-
- /**
- * Starting point for incoming filetransfer.
- * @param ev
- */
- public void fileTransferRequestReceived(SessionFileTransferEvent ev)
- {
- OperationSetPersistentPresenceYahooImpl opSetPersPresence
- = (OperationSetPersistentPresenceYahooImpl)
- yahooProvider.getOperationSet(
- OperationSetPersistentPresence.class);
-
- Contact sender = opSetPersPresence.findContactByID(ev.getFrom());
-
- if(sender == null)
- return;
-
- Date recvDate = new Date();
-
- for(int i = 0; i < ev.getFileNames().size(); i++)
- {
- String fileName = ev.getFileNames().get(i);
- String fileSize = ev.getFileSizes().get(i);
-
- IncomingFileTransferRequest req =
- new IncomingFileTransferRequestYahooImpl(
- yahooProvider, this, sender, recvDate,
- fileName, fileSize,
- ev.getId());
-
- activeFileTransfers.put(ev.getId(), req);
- fireFileTransferRequest(
- new FileTransferRequestEvent(this, req, recvDate));
- }
- }
-
- /**
- * Status changed for filetransfer.
- * @param ev
- */
- public void statusChanged(SessionFileTransferEvent ev)
- {
- if(ev.getId() == null)
- return;
-
- Object ftObj = activeFileTransfers.get(ev.getId());
-
- if(ftObj == null)
- {
- logger.warn("File Transfer or request not found. " + ev.getId() + "/ " + ev.getState());
- return;
- }
-
- int newState = ev.getState();
-
- if(newState == SessionFileTransferEvent.CANCEL
- || newState == SessionFileTransferEvent.FAILED
- || newState == SessionFileTransferEvent.RECEIVED
- || newState == SessionFileTransferEvent.REFUSED
- || newState == SessionFileTransferEvent.SENT)
- {
- // this is an final state so remove it from active filetransfers
- activeFileTransfers.remove(ev.getId());
- }
-
- if(ftObj instanceof IncomingFileTransferRequest)
- {
- if(newState == SessionFileTransferEvent.REFUSED)
- {
- IncomingFileTransferRequestYahooImpl req =
- (IncomingFileTransferRequestYahooImpl)ftObj;
- fireFileTransferRequestCanceled(
- new FileTransferRequestEvent(this, req, req.getDate()));
- return;
- }
- }
-
- if(!(ftObj instanceof FileTransferImpl))
- {
- logger.warn("File Transfer not found." + ftObj);
- return;
- }
-
- FileTransferImpl ft = (FileTransferImpl)ftObj;
-
- if( newState == SessionFileTransferEvent.IN_PROGRESS)
- {
- // if we start sending progress fire that we are in progress
- if(ev.getProgress() == 0)
- ft.fireStatusChangeEvent(
- FileTransferStatusChangeEvent.IN_PROGRESS);
-
- ft.setTransferedBytes(ev.getProgress());
- ft.fireProgressChangeEvent(
- System.currentTimeMillis(), ev.getProgress());
- }
- else
- ft.fireStatusChangeEvent(getStateMapping(newState));
- }
-
- /**
- * Returns the maximum file length supported by the protocol in bytes.
- * Supports up to 256MB.
- *
- * @return the file length that is supported.
- */
- public long getMaximumFileLength()
- {
- return 268435456l;// = 256*1024*1024;
- }
-
- /**
- * Our listener that will tell us when we're registered to
- */
- private class RegistrationStateListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenever
- * a change in the registration state of the corresponding provider had
- * occurred.
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
- if (logger.isDebugEnabled())
- logger.debug("The provider changed state from: "
- + evt.getOldState()
- + " to: " + evt.getNewState());
-
- if (evt.getNewState() == RegistrationState.REGISTERED)
- {
- yahooProvider.getYahooSession().addSessionFileListener(
- OperationSetFileTransferYahooImpl.this);
- }
- else if (evt.getNewState() == RegistrationState.UNREGISTERED)
- {
- YahooSession ys = yahooProvider.getYahooSession();
- if(ys != null)
- ys.removeSessionFileListener(
- OperationSetFileTransferYahooImpl.this);
- }
- }
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetPersistentPresenceYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetPersistentPresenceYahooImpl.java
deleted file mode 100644
index a99bdb7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetPersistentPresenceYahooImpl.java
+++ /dev/null
@@ -1,954 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.service.protocol.yahooconstants.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.*;
-import ymsg.network.event.*;
-
-/**
- * The Yahoo implementation of a Persistent Presence Operation set. This class
- * manages our own presence status as well as subscriptions for the presence
- * status of our buddies. It also offers methods for retrieving and modifying
- * the buddy contact list and adding listeners for changes in its layout.
- *
- * @author Damian Minkov
- */
-public class OperationSetPersistentPresenceYahooImpl
- extends AbstractOperationSetPersistentPresence<ProtocolProviderServiceYahooImpl>
-{
- private static final Logger logger =
- Logger.getLogger(OperationSetPersistentPresenceYahooImpl.class);
-
- /**
- * Contains our current status message. Note that this field would only
- * be changed once the server has confirmed the new status message and
- * not immediately upon setting a new one..
- */
- private String currentStatusMessage = "";
-
- /**
- * The presence status that we were last notified of entering.
- * The initial one is OFFLINE
- */
- private PresenceStatus currentStatus = YahooStatusEnum.OFFLINE;
-
- /**
- * Sometimes status changes are received before the contact list is inited
- * here we store such events so we can show them correctly
- */
-// private Hashtable earlyStatusChange = new Hashtable();
-
- /**
- * The array list we use when returning from the getSupportedStatusSet()
- * method.
- */
- private static final List<PresenceStatus> supportedPresenceStatusSet = new ArrayList<PresenceStatus>();
- static{
- supportedPresenceStatusSet.add(YahooStatusEnum.AVAILABLE);
- supportedPresenceStatusSet.add(YahooStatusEnum.BE_RIGHT_BACK);
- supportedPresenceStatusSet.add(YahooStatusEnum.BUSY);
- supportedPresenceStatusSet.add(YahooStatusEnum.IDLE);
- supportedPresenceStatusSet.add(YahooStatusEnum.INVISIBLE);
- supportedPresenceStatusSet.add(YahooStatusEnum.NOT_AT_DESK);
- supportedPresenceStatusSet.add(YahooStatusEnum.NOT_AT_HOME);
- supportedPresenceStatusSet.add(YahooStatusEnum.NOT_IN_OFFICE);
- supportedPresenceStatusSet.add(YahooStatusEnum.OFFLINE);
- supportedPresenceStatusSet.add(YahooStatusEnum.ON_THE_PHONE);
- supportedPresenceStatusSet.add(YahooStatusEnum.ON_VACATION);
- supportedPresenceStatusSet.add(YahooStatusEnum.OUT_TO_LUNCH);
- supportedPresenceStatusSet.add(YahooStatusEnum.STEPPED_OUT);
- }
-
- /**
- * A map containing bindings between SIP Communicator's yahoo presence status
- * instances and Yahoo status codes
- */
- private static final Map<PresenceStatus, Long> scToYahooModesMappings
- = new Hashtable<PresenceStatus, Long>();
- static{
- scToYahooModesMappings.put(YahooStatusEnum.AVAILABLE,
- StatusConstants.STATUS_AVAILABLE);
- scToYahooModesMappings.put(YahooStatusEnum.BE_RIGHT_BACK,
- StatusConstants.STATUS_BRB);
- scToYahooModesMappings.put(YahooStatusEnum.BUSY,
- StatusConstants.STATUS_BUSY);
- scToYahooModesMappings.put(YahooStatusEnum.IDLE,
- StatusConstants.STATUS_IDLE);
- scToYahooModesMappings.put(YahooStatusEnum.INVISIBLE,
- StatusConstants.STATUS_INVISIBLE);
- scToYahooModesMappings.put(YahooStatusEnum.NOT_AT_DESK,
- StatusConstants.STATUS_NOTATDESK);
- scToYahooModesMappings.put(YahooStatusEnum.NOT_AT_HOME,
- StatusConstants.STATUS_NOTATHOME);
- scToYahooModesMappings.put(YahooStatusEnum.NOT_IN_OFFICE,
- StatusConstants.STATUS_NOTINOFFICE);
- scToYahooModesMappings.put(YahooStatusEnum.OFFLINE,
- StatusConstants.STATUS_OFFLINE);
- scToYahooModesMappings.put(YahooStatusEnum.ON_THE_PHONE,
- StatusConstants.STATUS_ONPHONE);
- scToYahooModesMappings.put(YahooStatusEnum.ON_VACATION,
- StatusConstants.STATUS_ONVACATION);
- scToYahooModesMappings.put(YahooStatusEnum.OUT_TO_LUNCH,
- StatusConstants.STATUS_OUTTOLUNCH);
- scToYahooModesMappings.put(YahooStatusEnum.STEPPED_OUT,
- StatusConstants.STATUS_STEPPEDOUT);
- }
-
- /**
- * The server stored contact list that will be encapsulating smack's
- * buddy list.
- */
- private ServerStoredContactListYahooImpl ssContactList = null;
-
- /**
- * Listens for events that are fired while registering to server.
- * After we are registered instance is cleared and never used.
- */
- private EarlyEventListener earlyEventListener = null;
-
- /**
- * Status events are received before subscription one.
- * And when subscription is received we deliver
- * and the status events.
- */
- private StatusUpdater statusUpdater = new StatusUpdater();
-
- public OperationSetPersistentPresenceYahooImpl(
- ProtocolProviderServiceYahooImpl provider)
- {
- super(provider);
-
- ssContactList = new ServerStoredContactListYahooImpl( this , provider);
-
- parentProvider.addRegistrationStateChangeListener(
- new RegistrationStateListener());
- }
-
- /**
- * Registers a listener that would receive events upong changes in server
- * stored groups.
- *
- * @param listener a ServerStoredGroupChangeListener impl that would
- * receive events upong group changes.
- */
- @Override
- public void addServerStoredGroupChangeListener(ServerStoredGroupListener
- listener)
- {
- ssContactList.addGroupListener(listener);
- }
-
- /**
- * Creates a group with the specified name and parent in the server
- * stored contact list.
- *
- * @param parent the group where the new group should be created
- * @param groupName the name of the new group to create.
- * @throws OperationFailedException if such group already exists
- */
- public void createServerStoredContactGroup(ContactGroup parent,
- String groupName)
- throws OperationFailedException
- {
- assertConnected();
-
- if (!parent.canContainSubgroups())
- throw new IllegalArgumentException(
- "The specified contact group cannot contain child groups. Group:"
- + parent );
-
- ssContactList.createGroup(groupName);
- }
-
- /**
- * Creates a non persistent contact for the specified address. This would
- * also create (if necessary) a group for volatile contacts that would not
- * be added to the server stored contact list. The volatile contact would
- * remain in the list until it is really added to the contact list or
- * until the application is terminated.
- * @param id the address of the contact to create.
- * @return the newly created volatile <tt>ContactImpl</tt>
- */
- public ContactYahooImpl createVolatileContact(String id)
- {
- return ssContactList.createVolatileContact(id);
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @param parentGroup the group where the unresolved contact is supposed
- * to belong to.
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(String address,
- String persistentData,
- ContactGroup parentGroup)
- {
- if(! (parentGroup instanceof ContactGroupYahooImpl ||
- parentGroup instanceof RootContactGroupYahooImpl) )
- throw new IllegalArgumentException(
- "Argument is not an yahoo contact group (group="
- + parentGroup + ")");
-
- ContactYahooImpl contact =
- ssContactList.createUnresolvedContact(parentGroup, address);
-
- contact.setPersistentData(persistentData);
-
- return contact;
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(String address,
- String persistentData)
- {
- return createUnresolvedContact( address
- , persistentData
- , getServerStoredContactListRoot());
- }
-
- /**
- * Creates and returns a unresolved contact group from the specified
- * <tt>address</tt> and <tt>persistentData</tt>.
- *
- * @param groupUID an identifier, returned by ContactGroup's
- * getGroupUID, that the protocol provider may use in order to create
- * the group.
- * @param persistentData a String returned ContactGroups's
- * getPersistentData() method during a previous run and that has been
- * persistently stored locally.
- * @param parentGroup the group under which the new group is to be
- * created or null if this is group directly underneath the root.
- * @return the unresolved <tt>ContactGroup</tt> created from the
- * specified <tt>uid</tt> and <tt>persistentData</tt>
- */
- public ContactGroup createUnresolvedContactGroup(String groupUID,
- String persistentData, ContactGroup parentGroup)
- {
- return ssContactList.createUnresolvedContactGroup(groupUID);
- }
-
- /**
- * Returns a reference to the contact with the specified ID in case we
- * have a subscription for it and null otherwise/
- *
- * @param contactID a String identifier of the contact which we're
- * seeking a reference of.
- * @return a reference to the Contact with the specified
- * <tt>contactID</tt> or null if we don't have a subscription for the
- * that identifier.
- */
- public Contact findContactByID(String contactID)
- {
- return ssContactList.findContactById(contactID);
- }
-
- /**
- * Returns the status message that was confirmed by the serfver
- *
- * @return the last status message that we have requested and the aim
- * server has confirmed.
- */
- public String getCurrentStatusMessage()
- {
- return currentStatusMessage;
- }
-
- /**
- * Returns the protocol specific contact instance representing the local
- * user.
- *
- * @return the Contact (address, phone number, or uin) that the Provider
- * implementation is communicating on behalf of.
- */
- public Contact getLocalContact()
- {
- return null;
- }
-
- /**
- * Returns a PresenceStatus instance representing the state this provider
- * is currently in.
- *
- * @return the PresenceStatus last published by this provider.
- */
- public PresenceStatus getPresenceStatus()
- {
- return currentStatus;
- }
-
- /**
- * Returns the root group of the server stored contact list.
- *
- * @return the root ContactGroup for the ContactList stored by this
- * service.
- */
- public ContactGroup getServerStoredContactListRoot()
- {
- return ssContactList.getRootGroup();
- }
-
- /**
- * Returns the set of PresenceStatus objects that a user of this service
- * may request the provider to enter.
- *
- * @return Iterator a PresenceStatus array containing "enterable" status
- * instances.
- */
- public Iterator<PresenceStatus> getSupportedStatusSet()
- {
- return supportedPresenceStatusSet.iterator();
- }
-
- /**
- * Removes the specified contact from its current parent and places it
- * under <tt>newParent</tt>.
- *
- * @param contactToMove the <tt>Contact</tt> to move
- * @param newParent the <tt>ContactGroup</tt> where <tt>Contact</tt>
- * would be placed.
- */
- public void moveContactToGroup(Contact contactToMove,
- ContactGroup newParent)
- {
- assertConnected();
-
- if( !(contactToMove instanceof ContactYahooImpl) )
- throw new IllegalArgumentException(
- "The specified contact is not an yahoo contact." + contactToMove);
- if( !(newParent instanceof ContactGroupYahooImpl) )
- throw new IllegalArgumentException(
- "The specified group is not an yahoo contact group."
- + newParent);
-
- ssContactList.moveContact((ContactYahooImpl)contactToMove,
- (ContactGroupYahooImpl)newParent);
- }
-
- /**
- * Requests the provider to enter into a status corresponding to the
- * specified paramters.
- *
- * @param status the PresenceStatus as returned by
- * getRequestableStatusSet
- * @param statusMessage the message that should be set as the reason to
- * enter that status
- * @throws IllegalArgumentException if the status requested is not a
- * valid PresenceStatus supported by this provider.
- * @throws IllegalStateException if the provider is not currently
- * registered.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * publishing the status fails due to a network error.
- */
- public void publishPresenceStatus(PresenceStatus status,
- String statusMessage) throws
- IllegalArgumentException, IllegalStateException,
- OperationFailedException
- {
- assertConnected();
-
- if (!(status instanceof YahooStatusEnum))
- throw new IllegalArgumentException(
- status + " is not a valid Yahoo status");
-
- if(status.equals(YahooStatusEnum.OFFLINE))
- {
- parentProvider.unregister();
- return;
- }
-
- try
- {
- if(statusMessage != null && statusMessage.length() != 0)
- {
- boolean isAvailable = false;
-
- if(status.equals(YahooStatusEnum.AVAILABLE))
- isAvailable = true;
-
- // false - away
- // true - available
- parentProvider.getYahooSession().
- setStatus(statusMessage, isAvailable);
- }
-
- parentProvider.getYahooSession().setStatus(
- scToYahooModesMappings.get(status).longValue());
-
- fireProviderStatusChangeEvent(currentStatus, status);
- }
- catch(IOException ex)
- {
- throw new OperationFailedException("Failed to set Status",
- OperationFailedException.NETWORK_FAILURE);
- }
- }
-
- /**
- * Get the PresenceStatus for a particular contact.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * we're interested in.
- * @return PresenceStatus the <tt>PresenceStatus</tt> of the specified
- * <tt>contact</tt>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * retrieving the status fails due to errors experienced during
- * network communication
- */
- public PresenceStatus queryContactStatus(String contactIdentifier) throws
- IllegalArgumentException, IllegalStateException,
- OperationFailedException
- {
-
- ContactYahooImpl contact = ssContactList.findContactById(contactIdentifier);
- if(contact == null)
- {
- if (logger.isInfoEnabled())
- logger.info("Contact not found id :" + contactIdentifier);
- return null;
- }
- else
- return yahooStatusToPresenceStatus(contact.getSourceContact().getStatus());
- }
-
- /**
- * Removes the specified group from the server stored contact list.
- *
- * @param group the group to remove.
- */
- public void removeServerStoredContactGroup(ContactGroup group)
- {
- assertConnected();
-
- if( !(group instanceof ContactGroupYahooImpl) )
- throw new IllegalArgumentException(
- "The specified group is not an yahoo contact group: " + group);
-
- ssContactList.removeGroup(((ContactGroupYahooImpl)group));
- }
-
- /**
- * Removes the specified group change listener so that it won't receive
- * any further events.
- *
- * @param listener the ServerStoredGroupChangeListener to remove
- */
- @Override
- public void removeServerStoredGroupChangeListener(ServerStoredGroupListener
- listener)
- {
- ssContactList.removeGroupListener(listener);
- }
-
- /**
- * Renames the specified group from the server stored contact list.
- *
- * @param group the group to rename.
- * @param newName the new name of the group.
- */
- public void renameServerStoredContactGroup(ContactGroup group,
- String newName)
- {
- assertConnected();
-
- if( !(group instanceof ContactGroupYahooImpl) )
- throw new IllegalArgumentException(
- "The specified group is not an yahoo contact group: " + group);
-
- throw new UnsupportedOperationException("Renaming group not supported!");
- //ssContactList.renameGroup((ContactGroupYahooImpl)group, newName);
- }
-
- /**
- * Handler for incoming authorization requests.
- *
- * @param handler an instance of an AuthorizationHandler for
- * authorization requests coming from other users requesting
- * permission add us to their contact list.
- */
- public void setAuthorizationHandler(AuthorizationHandler handler)
- {
- ssContactList.setAuthorizationHandler(handler);
-
- // we got a handler. Lets process if something has came
- // during login process
- if(earlyEventListener != null)
- {
- earlyEventListener.processEarlyAuthorizations();
- earlyEventListener = null;
- }
- }
-
- /**
- * Persistently adds a subscription for the presence status of the
- * contact corresponding to the specified contactIdentifier and indicates
- * that it should be added to the specified group of the server stored
- * contact list.
- *
- * @param parent the parent group of the server stored contact list
- * where the contact should be added. <p>
- * @param contactIdentifier the contact whose status updates we are
- * subscribing for.
- * @throws IllegalArgumentException if <tt>contact</tt> or
- * <tt>parent</tt> are not a contact known to the underlying protocol
- * provider.
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(ContactGroup parent, String contactIdentifier) throws
- IllegalArgumentException, IllegalStateException,
- OperationFailedException
- {
- assertConnected();
-
- if(! (parent instanceof ContactGroupYahooImpl) )
- throw new IllegalArgumentException(
- "Argument is not an yahoo contact group (group=" + parent + ")");
-
- ssContactList.addContact((ContactGroupYahooImpl)parent, contactIdentifier);
- }
-
- /**
- * Adds a subscription for the presence status of the contact
- * corresponding to the specified contactIdentifier.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * updates we are subscribing for. <p>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(String contactIdentifier) throws
- IllegalArgumentException, IllegalStateException,
- OperationFailedException
- {
- assertConnected();
-
- ssContactList.addContact(contactIdentifier);
- }
-
- /**
- * Removes a subscription for the presence status of the specified
- * contact.
- *
- * @param contact the contact whose status updates we are unsubscribing
- * from.
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * unsubscribing fails due to errors experienced during network
- * communication
- */
- public void unsubscribe(Contact contact) throws IllegalArgumentException,
- IllegalStateException, OperationFailedException
- {
- assertConnected();
-
- if(! (contact instanceof ContactYahooImpl) )
- throw new IllegalArgumentException(
- "Argument is not an yahoo contact (contact=" + contact + ")");
-
- ssContactList.removeContact((ContactYahooImpl)contact);
- }
-
- /**
- * Converts the specified yahoo status to one of the status fields of the
- * YahooStatusEnum class.
- *
- * @param status the yahoo Status
- * @return a PresenceStatus instance representation of the yahoo Status
- * parameter. The returned result is one of the YahooStatusEnum fields.
- */
- YahooStatusEnum yahooStatusToPresenceStatus(long status)
- {
- if(status == StatusConstants.STATUS_AVAILABLE)
- return YahooStatusEnum.AVAILABLE;
- else if(status == StatusConstants.STATUS_BRB)
- return YahooStatusEnum.BE_RIGHT_BACK;
- else if(status == StatusConstants.STATUS_BUSY)
- return YahooStatusEnum.BUSY;
- else if(status == StatusConstants.STATUS_NOTATHOME)
- return YahooStatusEnum.NOT_AT_HOME;
- else if(status == StatusConstants.STATUS_NOTATDESK)
- return YahooStatusEnum.NOT_AT_DESK;
- else if(status == StatusConstants.STATUS_NOTINOFFICE)
- return YahooStatusEnum.NOT_IN_OFFICE;
- else if(status == StatusConstants.STATUS_ONPHONE)
- return YahooStatusEnum.ON_THE_PHONE;
- else if(status == StatusConstants.STATUS_ONVACATION)
- return YahooStatusEnum.ON_VACATION;
- else if(status == StatusConstants.STATUS_OUTTOLUNCH)
- return YahooStatusEnum.OUT_TO_LUNCH;
- else if(status == StatusConstants.STATUS_STEPPEDOUT)
- return YahooStatusEnum.STEPPED_OUT;
- else if(status == StatusConstants.STATUS_INVISIBLE)
- return YahooStatusEnum.INVISIBLE;
- else if(status == StatusConstants.STATUS_IDLE)
- return YahooStatusEnum.IDLE;
- else if(status == StatusConstants.STATUS_OFFLINE)
- return YahooStatusEnum.OFFLINE;
- // Yahoo supports custom statuses so if such is set just return available
- else
- return YahooStatusEnum.AVAILABLE;
- }
-
- /**
- * Utility method throwing an exception if the stack is not properly
- * initialized.
- * @throws java.lang.IllegalStateException if the underlying stack is
- * not registered and initialized.
- */
- private void assertConnected() throws IllegalStateException
- {
- if (parentProvider == null)
- throw new IllegalStateException(
- "The provider must be non-null and signed on the yahoo "
- +"service before being able to communicate.");
- if (!parentProvider.isRegistered())
- throw new IllegalStateException(
- "The provider must be signed on the yahoo service before "
- +"being able to communicate.");
- }
-
- /**
- * Notify all provider presence listeners of the corresponding event change
- *
- * @param oldStatus
- * the status our stack had so far
- * @param newStatus
- * the status we have from now on
- */
- @Override
- protected void fireProviderStatusChangeEvent(
- PresenceStatus oldStatus,
- PresenceStatus newStatus)
- {
- if (!oldStatus.equals(newStatus))
- {
- currentStatus = newStatus;
-
- super.fireProviderStatusChangeEvent(oldStatus, newStatus);
- }
- }
-
- /**
- * Statuses have been received durring login process
- * so we will init them once we are logged in
- */
- private void initContactStatuses()
- {
- YahooGroup[] groups = parentProvider.getYahooSession().getGroups();
-
- for (YahooGroup item : groups)
- {
- @SuppressWarnings("unchecked")
- Iterable<YahooUser> members = item.getMembers();
-
- for (YahooUser user : members)
- {
- ContactYahooImpl sourceContact =
- ssContactList.findContactById(user.getId());
-
- if(sourceContact != null)
- handleContactStatusChange(sourceContact, user);
- }
- }
- }
-
- /**
- * Our listener that will tell us when we're registered to server
- * and is ready to accept us as a listener.
- */
- private class RegistrationStateListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenever
- * a change in the registration state of the corresponding provider had
- * occurred.
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
- if (logger.isDebugEnabled())
- logger.debug("The yahoo provider changed state from: "
- + evt.getOldState()
- + " to: " + evt.getNewState());
-
- if(evt.getNewState() == RegistrationState.REGISTERING)
- {
- // add new listener waiting for events during login process
- earlyEventListener
- = new EarlyEventListener(parentProvider.getYahooSession());
- }
- else if(evt.getNewState() == RegistrationState.REGISTERED)
- {
- parentProvider.getYahooSession().
- addSessionListener(new StatusChangedListener());
-
- ssContactList.setYahooSession(parentProvider.getYahooSession());
-
- initContactStatuses();
-
- addSubscriptionListener(statusUpdater);
-
- if(earlyEventListener != null)
- {
- earlyEventListener.dispose();
- earlyEventListener = null;
- }
- }
- else if(evt.getNewState() == RegistrationState.UNREGISTERED
- || evt.getNewState() == RegistrationState.AUTHENTICATION_FAILED
- || evt.getNewState() == RegistrationState.CONNECTION_FAILED)
- {
- //since we are disconnected, we won't receive any further status
- //updates so we need to change by ourselves our own status as
- //well as set to offline all contacts in our contact list that
- //were online
- PresenceStatus oldStatus = currentStatus;
- currentStatus = YahooStatusEnum.OFFLINE;
-
- fireProviderStatusChangeEvent(oldStatus, currentStatus);
-
- removeSubscriptionListener(statusUpdater);
-
- //send event notifications saying that all our buddies are
- //offline. The protocol does not implement top level buddies
- //nor subgroups for top level groups so a simple nested loop
- //would be enough.
- Iterator<ContactGroup> groupsIter =
- getServerStoredContactListRoot().subgroups();
- while(groupsIter.hasNext())
- {
- ContactGroup group = groupsIter.next();
- Iterator<Contact> contactsIter = group.contacts();
-
- while(contactsIter.hasNext())
- {
- ContactYahooImpl contact
- = (ContactYahooImpl)contactsIter.next();
-
- PresenceStatus oldContactStatus
- = contact.getPresenceStatus();
-
- if(!oldContactStatus.isOnline())
- continue;
-
- contact.updatePresenceStatus(YahooStatusEnum.OFFLINE);
-
- fireContactPresenceStatusChangeEvent(
- contact
- , contact.getParentContactGroup()
- , oldContactStatus, YahooStatusEnum.OFFLINE);
- }
- }
-
- // clear listener
- if(earlyEventListener != null)
- {
- earlyEventListener.dispose();
- earlyEventListener = null;
- }
- }
- }
- }
-
- private void handleContactStatusChange(YahooUser yFriend)
- {
- ContactYahooImpl sourceContact =
- ssContactList.findContactById(yFriend.getId());
-
- if(sourceContact == null)
- {
- if(parentProvider.getAccountID().getUserID().
- equals(yFriend.getId()))
- {
- // thats my own status
- if (logger.isTraceEnabled())
- logger.trace("Own status changed to " + yFriend.getStatus());
- PresenceStatus oldStatus = currentStatus;
- currentStatus =
- yahooStatusToPresenceStatus(yFriend.getStatus());
- fireProviderStatusChangeEvent(oldStatus, currentStatus);
-
- return;
- }
- // strange
- else
- return;
- }
-
- handleContactStatusChange(sourceContact, yFriend);
- }
-
- void handleContactStatusChange(ContactYahooImpl sourceContact, YahooUser yFriend)
- {
- PresenceStatus oldStatus
- = sourceContact.getPresenceStatus();
-
- PresenceStatus newStatus = yahooStatusToPresenceStatus(yFriend.getStatus());
-
- // statuses maybe the same and only change in status message
- sourceContact.setStatusMessage(yFriend.getCustomStatusMessage());
-
- // when old and new status are the same do nothing - no change
- if(oldStatus.equals(newStatus))
- {
- if (logger.isDebugEnabled())
- logger.debug("old(" + oldStatus + ") and new("+ newStatus + ") statuses are the same!");
- return;
- }
-
- sourceContact.updatePresenceStatus(newStatus);
-
- ContactGroup parent
- = ssContactList.findContactGroup(sourceContact);
-
- if (logger.isDebugEnabled())
- logger.debug("Will Dispatch the contact status event.");
- fireContactPresenceStatusChangeEvent(sourceContact, parent,
- oldStatus, newStatus);
- }
-
- private class StatusChangedListener
- extends SessionAdapter
- {
- @Override
- public void friendsUpdateReceived(SessionFriendEvent evt)
- {
- if (logger.isDebugEnabled())
- logger.debug("Received a status update for contact " + evt);
-
- if(evt.getFriend() != null)
- {
- handleContactStatusChange(evt.getFriend());
- }
- else if(evt.getFriends() != null)
- {
- YahooUser[] yfs = evt.getFriends();
- for (int i = 0; i < yfs.length; i++)
- handleContactStatusChange(yfs[i]);
- }
- }
- }
-
- /**
- * Updates the statuses of newly created persistent contacts
- */
- private class StatusUpdater
- extends SubscriptionAdapter
- {
- @Override
- public void subscriptionCreated(SubscriptionEvent evt)
- {
- ContactYahooImpl contact =
- (ContactYahooImpl)evt.getSourceContact();
-
- if(!contact.isPersistent() || !contact.isResolved())
- return;
-
- handleContactStatusChange(contact, contact.getSourceContact());
- }
- }
-
- private class EarlyEventListener
- extends SessionAdapter
- {
- private final List<SessionAuthorizationEvent> receivedAuthorizations
- = new Vector<SessionAuthorizationEvent>();
-
- /**
- * The <code>YahooSession</code> this instance is listening to because
- * the <code>YahooSession</code> isn't available in
- * <code>parentProvider</code> after
- * {@link RegistrationState#UNREGISTERED} and then this listener cannot
- * be removed.
- */
- private final YahooSession yahooSession;
-
- public EarlyEventListener(YahooSession yahooSession)
- {
- this.yahooSession = yahooSession;
- this.yahooSession.addSessionListener(this);
- }
-
- @Override
- public void authorizationReceived(SessionAuthorizationEvent ev)
- {
- if(ev.isAuthorizationRequest())
- {
- if (logger.isTraceEnabled())
- logger.trace("authorizationRequestReceived from " +
- ev.getFrom());
- receivedAuthorizations.add(ev);
- }
- }
-
- public void dispose()
- {
- yahooSession.removeSessionListener(this);
- }
-
- public void processEarlyAuthorizations()
- {
- for (SessionAuthorizationEvent e : receivedAuthorizations)
- {
- ssContactList.processAuthorizationRequest(e);
- }
- }
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetTypingNotificationsYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetTypingNotificationsYahooImpl.java
deleted file mode 100644
index 81e266a..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/OperationSetTypingNotificationsYahooImpl.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.event.*;
-
-/**
- * Maps SIP Communicator typing notifications to those going and coming from
- * smack lib.
- *
- * @author Damian Minkov
- */
-public class OperationSetTypingNotificationsYahooImpl
- extends AbstractOperationSetTypingNotifications<ProtocolProviderServiceYahooImpl>
-{
- private static final Logger logger =
- Logger.getLogger(OperationSetTypingNotificationsYahooImpl.class);
-
- /**
- * An active instance of the opSetPersPresence operation set. We're using
- * it to map incoming events to contacts in our contact list.
- */
- private OperationSetPersistentPresenceYahooImpl opSetPersPresence = null;
-
- /**
- * @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
- * that created us and that we'll use for retrieving the underlying aim
- * connection.
- */
- OperationSetTypingNotificationsYahooImpl(
- ProtocolProviderServiceYahooImpl provider)
- {
- super(provider);
-
- provider.addRegistrationStateChangeListener(new ProviderRegListener());
- }
-
- /**
- * Sends a notification to <tt>notifiedContatct</tt> that we have entered
- * <tt>typingState</tt>.
- *
- * @param notifiedContact the <tt>Contact</tt> to notify
- * @param typingState the typing state that we have entered.
- *
- * @throws java.lang.IllegalStateException if the underlying stack is
- * not registered and initialized.
- * @throws java.lang.IllegalArgumentException if <tt>notifiedContact</tt> is
- * not an instance belonging to the underlying implementation.
- */
- public void sendTypingNotification(Contact notifiedContact, int typingState)
- throws IllegalStateException, IllegalArgumentException
- {
- assertConnected();
-
- if( !(notifiedContact instanceof ContactYahooImpl) )
- throw new IllegalArgumentException(
- "The specified contact is not an yahoo contact."
- + notifiedContact);
-
- if(typingState == OperationSetTypingNotifications.STATE_TYPING)
- {
-
- parentProvider.getYahooSession().
- keyTyped(notifiedContact.getAddress(),
- parentProvider.getAccountID().getUserID());
- }
- else
- if(typingState == OperationSetTypingNotifications.STATE_STOPPED ||
- typingState == OperationSetTypingNotifications.STATE_PAUSED)
- {
- parentProvider.getYahooSession().
- stopTyping(notifiedContact.getAddress(),
- parentProvider.getAccountID().getUserID());
- }
- }
-
- private class TypingListener
- extends SessionAdapter
- {
- @Override
- public void notifyReceived(SessionNotifyEvent evt)
- {
- if(evt.isTyping())
- {
- String typingUserID = evt.getFrom();
-
- if(typingUserID != null)
- {
- Contact sourceContact =
- opSetPersPresence.findContactByID(typingUserID);
-
- if(sourceContact == null)
- return;
-
- // typing on
- fireTypingNotificationsEvent(
- sourceContact,
- (evt.getMode() == 1) ? STATE_TYPING : STATE_STOPPED);
- }
- }
- }
- }
-
- /**
- * Our listener that will tell us when we're registered and
- * ready to accept us as a listener.
- */
- private class ProviderRegListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenever
- * a change in the registration state of the corresponding provider had
- * occurred.
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
- if (logger.isDebugEnabled())
- logger.debug("The provider changed state from: "
- + evt.getOldState()
- + " to: " + evt.getNewState());
- if (evt.getNewState() == RegistrationState.REGISTERED)
- {
- opSetPersPresence =
- (OperationSetPersistentPresenceYahooImpl) parentProvider
- .getOperationSet(OperationSetPersistentPresence.class);
-
- parentProvider
- .getYahooSession().addSessionListener(new TypingListener());
- }
- }
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolIconYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolIconYahooImpl.java
deleted file mode 100644
index 34befc9..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolIconYahooImpl.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.resources.*;
-import org.osgi.framework.*;
-
-/**
- * Represents the Yahoo protocol icon. Implements the <tt>ProtocolIcon</tt>
- * interface in order to provide an Yahoo icon image in two different sizes.
- *
- * @author Yana Stamcheva
- */
-public class ProtocolIconYahooImpl
- implements ProtocolIcon
-{
- private static Logger logger = Logger.getLogger(ProtocolIconYahooImpl.class);
-
- private static ResourceManagementService resourcesService;
-
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String, byte[]> iconsTable
- = new Hashtable<String, byte[]>();
- static
- {
- iconsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- getImageInBytes("service.protocol.yahoo.YAHOO_16x16"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- getImageInBytes("service.protocol.yahoo.YAHOO_32x32"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- getImageInBytes("service.protocol.yahoo.YAHOO_48x48"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- getImageInBytes("service.protocol.yahoo.YAHOO_64x64"));
- }
-
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String, String> iconPathsTable
- = new Hashtable<String, String>();
- static
- {
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- getResources().getImagePath("service.protocol.yahoo.YAHOO_16x16"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- getResources().getImagePath("service.protocol.yahoo.YAHOO_32x32"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- getResources().getImagePath("service.protocol.yahoo.YAHOO_48x48"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- getResources().getImagePath("service.protocol.yahoo.YAHOO_64x64"));
- }
-
- /**
- * Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns
- * an iterator to a set containing the supported icon sizes.
- * @return an iterator to a set containing the supported icon sizes
- */
- public Iterator<String> getSupportedSizes()
- {
- return iconsTable.keySet().iterator();
- }
-
- /**
- * Returns TRUE if a icon with the given size is supported, FALSE-otherwise.
- */
- public boolean isSizeSupported(String iconSize)
- {
- return iconsTable.containsKey(iconSize);
- }
-
- /**
- * Returns the icon image in the given size.
- * @param iconSize the icon size; one of ICON_SIZE_XXX constants
- */
- public byte[] getIcon(String iconSize)
- {
- return iconsTable.get(iconSize);
- }
-
- /**
- * Returns a path to the icon with the given size.
- * @param iconSize the size of the icon we're looking for
- * @return the path to the icon with the given size
- */
- public String getIconPath(String iconSize)
- {
- return iconPathsTable.get(iconSize);
- }
-
- /**
- * Returns the icon image used to represent the protocol connecting state.
- * @return the icon image used to represent the protocol connecting state
- */
- public byte[] getConnectingIcon()
- {
- return getImageInBytes("yahooConnectingIcon");
- }
-
- /**
- * Returns the byte representation of the image corresponding to the given
- * identifier.
- *
- * @param imageID the identifier of the image
- * @return the byte representation of the image corresponding to the given
- * identifier.
- */
- public static byte[] getImageInBytes(String imageID)
- {
- InputStream in = getResources().getImageInputStream(imageID);
-
- if (in == null)
- return null;
- byte[] image = null;
- try
- {
- image = new byte[in.available()];
-
- in.read(image);
- }
- catch (IOException e)
- {
- logger.error("Failed to load image:" + imageID, e);
- }
-
- return image;
- }
-
- public static ResourceManagementService getResources()
- {
- if (resourcesService == null)
- {
- ServiceReference serviceReference = YahooActivator.getBundleContext()
- .getServiceReference(ResourceManagementService.class.getName());
-
- if(serviceReference == null)
- return null;
-
- resourcesService = (ResourceManagementService)
- YahooActivator.getBundleContext().getService(serviceReference);
- }
-
- return resourcesService;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderFactoryYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderFactoryYahooImpl.java
deleted file mode 100644
index 358286c..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderFactoryYahooImpl.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-import org.osgi.framework.*;
-
-/**
- * The Yahoo implementation of the ProtocolProviderFactory.
- * @author Damian Minkov
- */
-public class ProtocolProviderFactoryYahooImpl
- extends ProtocolProviderFactory
-{
-
- /**
- * Creates an instance of the ProtocolProviderFactoryYahooImpl.
- */
- protected ProtocolProviderFactoryYahooImpl()
- {
- super(YahooActivator.getBundleContext(), ProtocolNames.YAHOO);
- }
-
- /**
- * Initializes and creates an account corresponding to the specified
- * accountProperties and registers the resulting ProtocolProvider in the
- * <tt>context</tt> BundleContext parameter. This method has a persistent
- * effect. Once created the resulting account will remain installed until
- * removed through the uninstall account method.
- *
- * @param userIDStr the user identifier for the new account
- * @param accountProperties a set of protocol (or implementation)
- * specific properties defining the new account.
- * @return the AccountID of the newly created account
- */
- @Override
- public AccountID installAccount( String userIDStr,
- Map<String, String> accountProperties)
- {
- BundleContext context
- = YahooActivator.getBundleContext();
- if (context == null)
- throw new NullPointerException("The specified BundleContext was null");
-
- if (userIDStr == null)
- throw new NullPointerException("The specified AccountID was null");
-
- if (accountProperties == null)
- throw new NullPointerException("The specified property map was null");
-
- accountProperties.put(USER_ID, userIDStr);
-
- AccountID accountID = new YahooAccountID(userIDStr, accountProperties);
-
- //make sure we haven't seen this account id before.
- if( registeredAccounts.containsKey(accountID) )
- throw new IllegalStateException(
- "An account for id " + userIDStr + " was already installed!");
-
- //first store the account and only then load it as the load generates
- //an osgi event, the osgi event triggers (through the UI) a call to
- //the register() method and it needs to access the configuration service
- //and check for a password.
- this.storeAccount(accountID, false);
-
- accountID = loadAccount(accountProperties);
-
- return accountID;
- }
-
- @Override
- protected AccountID createAccountID(String userID, Map<String, String> accountProperties)
- {
- return new YahooAccountID(userID, accountProperties);
- }
-
- @Override
- protected ProtocolProviderService createService(String userID,
- AccountID accountID)
- {
- ProtocolProviderServiceYahooImpl service =
- new ProtocolProviderServiceYahooImpl();
-
- service.initialize(userID, accountID);
- return service;
- }
-
- @Override
- public void modifyAccount( ProtocolProviderService protocolProvider,
- Map<String, String> accountProperties)
- throws NullPointerException
- {
- BundleContext context
- = YahooActivator.getBundleContext();
-
- if (context == null)
- throw new NullPointerException(
- "The specified BundleContext was null");
-
- if (protocolProvider == null)
- throw new NullPointerException(
- "The specified Protocol Provider was null");
-
- YahooAccountID accountID
- = (YahooAccountID) protocolProvider.getAccountID();
-
- // If the given accountID doesn't correspond to an existing account
- // we return.
- if(!registeredAccounts.containsKey(accountID))
- return;
-
- ServiceRegistration registration = registeredAccounts.get(accountID);
-
- // kill the service
- if (registration != null)
- registration.unregister();
-
- if (accountProperties == null)
- throw new NullPointerException(
- "The specified property map was null");
-
- accountProperties.put(USER_ID, accountID.getUserID());
-
- if (!accountProperties.containsKey(PROTOCOL))
- accountProperties.put(PROTOCOL, ProtocolNames.YAHOO);
-
- accountID.setAccountProperties(accountProperties);
-
- // First store the account and only then load it as the load generates
- // an osgi event, the osgi event triggers (trhgough the UI) a call to
- // the register() method and it needs to acces the configuration service
- // and check for a password.
- this.storeAccount(accountID);
-
- Hashtable<String, String> properties = new Hashtable<String, String>();
- properties.put(PROTOCOL, ProtocolNames.YAHOO);
- properties.put(USER_ID, accountID.getUserID());
-
- ((ProtocolProviderServiceYahooImpl)protocolProvider)
- .initialize(accountID.getUserID(), accountID);
-
- // We store again the account in order to store all properties added
- // during the protocol provider initialization.
- this.storeAccount(accountID);
-
- registration
- = context.registerService(
- ProtocolProviderService.class.getName(),
- protocolProvider,
- properties);
-
- registeredAccounts.put(accountID, registration);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java
deleted file mode 100644
index 264aaab..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/ProtocolProviderServiceYahooImpl.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-
-import net.java.sip.communicator.service.dns.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.*;
-import ymsg.network.event.*;
-
-/**
- * An implementation of the protocol provider service over the Yahoo protocol
- *
- * @author Damian Minkov
- */
-public class ProtocolProviderServiceYahooImpl
- extends AbstractProtocolProviderService
-{
- /**
- * This class logger.
- */
- private static final Logger logger =
- Logger.getLogger(ProtocolProviderServiceYahooImpl.class);
-
- /**
- * The current yahoo session.
- */
- private YahooSession yahooSession = null;
-
- /**
- * indicates whether or not the provider is initialized and ready for use.
- */
- private boolean isInitialized = false;
-
- /**
- * We use this to lock access to initialization.
- */
- private final Object initializationLock = new Object();
-
- /**
- * The identifier of the account that this provider represents.
- */
- private AccountID accountID = null;
-
- /**
- * Used when we need to re-register
- */
- private SecurityAuthority authority = null;
-
- /**
- * The persistent presence operations set.
- */
- private OperationSetPersistentPresenceYahooImpl persistentPresence = null;
-
- /**
- * Typing notifications operations set.
- */
- private OperationSetTypingNotificationsYahooImpl typingNotifications = null;
-
- /**
- * The logo corresponding to the msn protocol.
- */
- private ProtocolIconYahooImpl yahooIcon
- = new ProtocolIconYahooImpl();
-
- /**
- * The connection listener.
- */
- private YahooConnectionListener connectionListener = null;
-
- /**
- * Returns the state of the registration of this protocol provider
- * @return the <tt>RegistrationState</tt> that this provider is
- * currently in or null in case it is in a unknown state.
- */
- public RegistrationState getRegistrationState()
- {
- if(yahooSession != null &&
- yahooSession.getSessionStatus() == StatusConstants.MESSAGING)
- return RegistrationState.REGISTERED;
- else
- return RegistrationState.UNREGISTERED;
- }
-
- /**
- * Starts the registration process. Connection details such as
- * registration server, user name/number are provided through the
- * configuration service through implementation specific properties.
- *
- * @param authority the security authority that will be used for resolving
- * any security challenges that may be returned during the
- * registration or at any moment while wer're registered.
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void register(final SecurityAuthority authority)
- throws OperationFailedException
- {
- if(authority == null)
- throw new IllegalArgumentException(
- "The register method needs a valid non-null authority impl "
- + " in order to be able and retrieve passwords.");
-
- this.authority = authority;
-
- connectAndLogin(authority, SecurityAuthority.AUTHENTICATION_REQUIRED);
- }
-
- /**
- * Connects and logins to the server
- * @param authority SecurityAuthority
- * @param authReasonCode the authentication reason code, which should
- * indicate why are making an authentication request
- * @throws OperationFailedException if login parameters
- * as server port are not correct
- */
- private void connectAndLogin( SecurityAuthority authority,
- int authReasonCode)
- throws OperationFailedException
- {
- synchronized(initializationLock)
- {
- //verify whether a password has already been stored for this account
- String password = YahooActivator.
- getProtocolProviderFactory().loadPassword(getAccountID());
-
- // If the password hasn't been saved or the reason is one of those
- // listed below we need to ask the user for credentials again.
- if (password == null
- || authReasonCode == SecurityAuthority.WRONG_PASSWORD
- || authReasonCode == SecurityAuthority.WRONG_USERNAME)
- {
- //create a default credentials object
- UserCredentials credentials = new UserCredentials();
- credentials.setUserName(getAccountID().getUserID());
-
- //request a password from the user
- credentials = authority.obtainCredentials(
- getAccountID().getDisplayName(),
- credentials,
- authReasonCode);
-
- // in case user has canceled the login window
- if(credentials == null)
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.UNREGISTERED,
- RegistrationStateChangeEvent.REASON_USER_REQUEST, "");
- return;
- }
-
- //extract the password the user passed us.
- char[] pass = credentials.getPassword();
-
- // the user didn't provide us a password (canceled the operation)
- if(pass == null)
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.UNREGISTERED,
- RegistrationStateChangeEvent.REASON_USER_REQUEST, "");
- return;
- }
- password = new String(pass);
-
- if (credentials.isPasswordPersistent())
- {
- YahooActivator.getProtocolProviderFactory()
- .storePassword(getAccountID(), password);
- }
- }
-
- yahooSession = new YahooSession();
- connectionListener = new YahooConnectionListener();
- yahooSession.addSessionListener(connectionListener);
-
- try
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.REGISTERING,
- RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
-
- yahooSession.login(getAccountID().getUserID(), password);
-
- if(yahooSession.getSessionStatus()==StatusConstants.MESSAGING)
- {
- persistentPresence.fireProviderStatusChangeEvent(
- persistentPresence.getPresenceStatus(),
- persistentPresence.yahooStatusToPresenceStatus(
- yahooSession.getStatus()));
-
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.REGISTERED,
- RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
- }
- else
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.UNREGISTERED,
- RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
- }
- }
- catch (LoginRefusedException ex)
- {
- if(ex.getStatus() == StatusConstants.STATUS_BADUSERNAME)
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.AUTHENTICATION_FAILED,
- RegistrationStateChangeEvent.REASON_NON_EXISTING_USER_ID,
- null);
-
- reregister(SecurityAuthority.WRONG_USERNAME);
- }
- else if(ex.getStatus() == StatusConstants.STATUS_BAD)
- {
- YahooActivator.getProtocolProviderFactory()
- .storePassword(getAccountID(), null);
-
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.AUTHENTICATION_FAILED,
- RegistrationStateChangeEvent.REASON_AUTHENTICATION_FAILED,
- null);
-
- // Try to re-register and ask the user to retype the password.
- reregister(SecurityAuthority.WRONG_PASSWORD);
- }
- else if(ex.getStatus() == StatusConstants.STATUS_LOCKED)
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.AUTHENTICATION_FAILED,
- RegistrationStateChangeEvent.REASON_RECONNECTION_RATE_LIMIT_EXCEEDED,
- null);
- }
- }
- catch (IOException ex)
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.CONNECTION_FAILED,
- RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
- }
- catch (DnssecRuntimeException ex)
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.UNREGISTERED,
- RegistrationStateChangeEvent.REASON_USER_REQUEST, null);
- }
- }
- }
-
- /**
- * Reconnects if fails fire connection failed.
- * @param reasonCode the appropriate <tt>SecurityAuthority</tt> reasonCode,
- * which would specify the reason for which we're re-calling the login.
- */
- void reregister(int reasonCode)
- {
- try
- {
- connectAndLogin(authority, reasonCode);
- }
- catch (OperationFailedException ex)
- {
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.CONNECTION_FAILED,
- RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
- }
- }
-
- /**
- * Ends the registration of this protocol provider with the service.
- */
- public void unregister()
- {
- unregisterInternal(true);
- }
-
- /**
- * Unregister and fire the event if requested
- * @param fireEvent boolean
- */
- void unregisterInternal(boolean fireEvent)
- {
- RegistrationState currRegState = getRegistrationState();
-
- if(fireEvent)
- fireRegistrationStateChanged(
- currRegState,
- RegistrationState.UNREGISTERING,
- RegistrationStateChangeEvent.REASON_USER_REQUEST,
- null);
-
- try
- {
- if(connectionListener != null && yahooSession != null)
- {
- yahooSession.removeSessionListener(connectionListener);
- connectionListener = null;
- }
-
- if((yahooSession != null)
- && (yahooSession.getSessionStatus() == StatusConstants.MESSAGING))
- yahooSession.logout();
- }
- catch(Exception ex)
- {
- logger.error("Cannot logout! ", ex);
- }
-
- yahooSession = null;
-
- if(fireEvent)
- fireRegistrationStateChanged(
- currRegState,
- RegistrationState.UNREGISTERED,
- RegistrationStateChangeEvent.REASON_USER_REQUEST,
- null);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see net.java.sip.communicator.service.protocol.ProtocolProviderService#
- * isSignallingTransportSecure()
- */
- public boolean isSignalingTransportSecure()
- {
- return false;
- }
-
- /**
- * Returns the "transport" protocol of this instance used to carry the
- * control channel for the current protocol service.
- *
- * @return The "transport" protocol of this instance: TCP.
- */
- public TransportProtocol getTransportProtocol()
- {
- return TransportProtocol.TCP;
- }
-
- /**
- * Returns the short name of the protocol that the implementation of this
- * provider is based upon (like SIP, Msn, ICQ/AIM, or others for
- * example).
- *
- * @return a String containing the short name of the protocol this
- * service is taking care of.
- */
- public String getProtocolName()
- {
- return ProtocolNames.YAHOO;
- }
-
- /**
- * Initialized the service implementation, and puts it in a sate where it
- * could interoperate with other services. It is strongly recomended that
- * properties in this Map be mapped to property names as specified by
- * <tt>AccountProperties</tt>.
- *
- * @param screenname the account id/uin/screenname of the account that
- * we're about to create
- * @param accountID the identifier of the account that this protocol
- * provider represents.
- *
- * @see net.java.sip.communicator.service.protocol.AccountID
- */
- protected void initialize(String screenname,
- AccountID accountID)
- {
- synchronized(initializationLock)
- {
- this.accountID = accountID;
-
- addSupportedOperationSet(
- OperationSetInstantMessageTransform.class,
- new OperationSetInstantMessageTransformImpl());
-
- //initialize the presence operationset
- persistentPresence
- = new OperationSetPersistentPresenceYahooImpl(this);
- addSupportedOperationSet(
- OperationSetPersistentPresence.class,
- persistentPresence);
- //register it once again for those that simply need presence
- addSupportedOperationSet(
- OperationSetPresence.class,
- persistentPresence);
-
- //initialize the IM operation set
- addSupportedOperationSet(
- OperationSetBasicInstantMessaging.class,
- new OperationSetBasicInstantMessagingYahooImpl(this));
-
- //initialize the multi user chat operation set
- addSupportedOperationSet(
- OperationSetAdHocMultiUserChat.class,
- new OperationSetAdHocMultiUserChatYahooImpl(this));
-
- //initialize the typing notifications operation set
- typingNotifications
- = new OperationSetTypingNotificationsYahooImpl(this);
- addSupportedOperationSet(
- OperationSetTypingNotifications.class,
- typingNotifications);
-
- addSupportedOperationSet(
- OperationSetFileTransfer.class,
- new OperationSetFileTransferYahooImpl(this));
-
- isInitialized = true;
- }
- }
-
- /**
- * Makes the service implementation close all open sockets and release
- * any resources that it might have taken and prepare for
- * shutdown/garbage collection.
- */
- public void shutdown()
- {
- synchronized(initializationLock){
- unregisterInternal(false);
- yahooSession = null;
- isInitialized = false;
- }
- }
-
- /**
- * Returns true if the provider service implementation is initialized and
- * ready for use by other services, and false otherwise.
- *
- * @return true if the provider is initialized and ready for use and false
- * otherwise
- */
- public boolean isInitialized()
- {
- return isInitialized;
- }
-
- /**
- * Returns the AccountID that uniquely identifies the account represented
- * by this instance of the ProtocolProviderService.
- * @return the id of the account represented by this provider.
- */
- public AccountID getAccountID()
- {
- return accountID;
- }
-
- /**
- * Returns the Yahoo<tt>Session</tt>opened by this provider
- * @return a reference to the <tt>Session</tt> last opened by this
- * provider.
- */
- YahooSession getYahooSession()
- {
- return yahooSession;
- }
-
- /**
- * Creates a RegistrationStateChange event corresponding to the specified
- * old and new states and notifies all currently registered listeners.
- *
- * @param oldState the state that the provider had before the change
- * occurred
- * @param newState the state that the provider is currently in.
- * @param reasonCode a value corresponding to one of the REASON_XXX fields
- * of the RegistrationStateChangeEvent class, indicating the reason for
- * this state transition.
- * @param reason a String further explaining the reason code or null if
- * no such explanation is necessary.
- */
- @Override
- public void fireRegistrationStateChanged( RegistrationState oldState,
- RegistrationState newState,
- int reasonCode,
- String reason)
- {
- if(newState.equals(RegistrationState.UNREGISTERED))
- {
- unregisterInternal(false);
- yahooSession = null;
- }
-
- super.fireRegistrationStateChanged(oldState, newState, reasonCode, reason);
- }
-
- /**
- * Listens when we are logged in the server
- * or incoming exception in the lib impl.
- */
- private class YahooConnectionListener
- extends SessionAdapter
- {
- /**
- * Yahoo has logged us off the system, or the connection was lost
- *
- * @param ev the event
- */
- @Override
- public void connectionClosed(SessionEvent ev)
- {
- if(isRegistered())
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.CONNECTION_FAILED,
- RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
- }
-
- /**
- * Some exception has occurred in stack.
- * @param ev
- */
- @Override
- public void inputExceptionThrown(SessionExceptionEvent ev)
- {
- if(ev.getException() instanceof YMSG9BadFormatException)
- {
- logger.error("Yahoo protocol exception occured exception",
- ev.getException());
- logger.error("Yahoo protocol exception occured exception cause",
- ev.getException().getCause());
- }
- else
- logger.error(
- "Yahoo protocol exception occured", ev.getException());
-
- unregisterInternal(false);
- if(isRegistered())
- fireRegistrationStateChanged(
- getRegistrationState(),
- RegistrationState.UNREGISTERED,
- RegistrationStateChangeEvent.REASON_INTERNAL_ERROR, null);
- }
- }
-
- /**
- * Returns the yahoo protocol icon.
- * @return the yahoo protocol icon
- */
- public ProtocolIcon getProtocolIcon()
- {
- return yahooIcon;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/RootContactGroupYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/RootContactGroupYahooImpl.java
deleted file mode 100644
index 856bb30..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/RootContactGroupYahooImpl.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * A dummy ContactGroup implementation representing the ContactList root for
- * Yahoo contact lists.
- * @author Damian Minkov
- */
-public class RootContactGroupYahooImpl
- extends AbstractContactGroupYahooImpl
-{
- private String ROOT_CONTACT_GROUP_NAME = "ContactListRoot";
- private List<ContactGroup> subGroups = new LinkedList<ContactGroup>();
- private boolean isResolved = false;
-
- /**
- * An empty list that we use when returning an iterator.
- */
- private List<Contact> dummyContacts = new LinkedList<Contact>();
-
- private final ProtocolProviderServiceYahooImpl protocolProvider;
-
- /**
- * Creates a ContactGroup instance.
- */
- RootContactGroupYahooImpl(ProtocolProviderServiceYahooImpl protocolProvider)
- {
- this.protocolProvider = protocolProvider;
- }
-
- /**
- * The ContactListRoot is the only group that can contain subgroups.
- *
- * @return true (always)
- */
- public boolean canContainSubgroups()
- {
- return true;
- }
-
- /**
- * Returns the name of this group which is always
- * <tt>ROOT_CONTACT_GROUP_NAME</tt>.
- *
- * @return a String containing the name of this group.
- */
- public String getGroupName()
- {
- return ROOT_CONTACT_GROUP_NAME;
- }
-
- /**
- * Adds the specified group to the end of the list of sub groups.
- * @param group the group to add.
- */
- void addSubGroup(ContactGroupYahooImpl group)
- {
- subGroups.add(group);
- }
-
- /**
- * Removes the specified from the list of sub groups
- * @param group the group to remove.
- */
- void removeSubGroup(ContactGroupYahooImpl group)
- {
- removeSubGroup(subGroups.indexOf(group));
- }
-
- /**
- * Removes the sub group with the specified index.
- * @param index the index of the group to remove
- */
- void removeSubGroup(int index)
- {
- subGroups.remove(index);
- }
-
- /**
- * Returns the number of subgroups contained by this
- * <tt>RootContactGroupImpl</tt>.
- *
- * @return an int indicating the number of subgroups that this
- * ContactGroup contains.
- */
- public int countSubgroups()
- {
- return subGroups.size();
- }
-
- /**
- * Returns null as this is the root contact group.
- * @return null as this is the root contact group.
- */
- public ContactGroup getParentContactGroup()
- {
- return null;
- }
-
- /**
- * Returns the subgroup with the specified index.
- *
- * @param index the index of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(int index)
- {
- return subGroups.get(index);
- }
-
- /**
- * Returns the subgroup with the specified name.
- * @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(String groupName)
- {
- Iterator<ContactGroup> subgroups = subgroups();
- while (subgroups.hasNext())
- {
- ContactGroup grp = subgroups.next();
-
- if (grp.getGroupName().equals(groupName))
- return grp;
- }
-
- return null;
- }
-
- /**
- * Returns an iterator over the sub groups that this
- * <tt>ContactGroup</tt> contains.
- *
- * @return a java.util.Iterator over the <tt>ContactGroup</tt>
- * children of this group (i.e. subgroups).
- */
- public Iterator<ContactGroup> subgroups()
- {
- return subGroups.iterator();
- }
-
- /**
- * Returns the number, which is always 0, of <tt>Contact</tt> members
- * of this <tt>ContactGroup</tt>
- * @return an int indicating the number of <tt>Contact</tt>s, members
- * of this <tt>ContactGroup</tt>.
- */
- public int countContacts()
- {
- return dummyContacts.size();
- }
-
- /**
- * Returns an Iterator over all contacts, member of this
- * <tt>ContactGroup</tt>.
- * @return a java.util.Iterator over all contacts inside this
- * <tt>ContactGroup</tt>
- */
- public Iterator<Contact> contacts()
- {
- return dummyContacts.iterator();
- }
-
- /**
- * Returns the <tt>Contact</tt> with the specified address or
- * identifier.
- * @param id the addres or identifier of the <tt>Contact</tt> we are
- * looking for.
- * @return the <tt>Contact</tt> with the specified id or address.
- */
- public Contact getContact(String id)
- {
- //no contacts in the root group for this yahoo impl.
- return null;
- }
-
-
- /**
- * Returns a string representation of the root contact group that contains
- * all subgroups and subcontacts of this group.
- *
- * @return a string representation of this root contact group.
- */
- @Override
- public String toString()
- {
- StringBuffer buff = new StringBuffer(getGroupName());
- buff.append(".subGroups=" + countSubgroups() + ":\n");
-
- Iterator<ContactGroup> subGroups = subgroups();
- while (subGroups.hasNext())
- {
- ContactGroup group = subGroups.next();
- buff.append(group.toString());
- if (subGroups.hasNext())
- buff.append("\n");
- }
- return buff.toString();
- }
-
- /**
- * Returns the protocol provider that this group belongs to.
- * @return a regerence to the ProtocolProviderService instance that this
- * ContactGroup belongs to.
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return protocolProvider;
- }
-
- /**
- * Determines whether or not this contact group is being stored by the
- * server. Non persistent contact groups exist for the sole purpose of
- * containing non persistent contacts.
- * @return true if the contact group is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return true;
- }
-
- /**
- * Returns null as no persistent data is required and the group name is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this group has been resolved against the
- * server. Unresolved groups are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped groups to their on-line buddies.
- * @return true if the group has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Returns a <tt>String</tt> that uniquely represnets the group. In this we
- * use the name of the group as an identifier. This may cause problems
- * though, in clase the name is changed by some other application between
- * consecutive runs of the sip-communicator.
- *
- * @return a String representing this group in a unique and persistent
- * way.
- */
- public String getUID()
- {
- return getGroupName();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/ServerStoredContactListYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/ServerStoredContactListYahooImpl.java
deleted file mode 100644
index e732b84..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/ServerStoredContactListYahooImpl.java
+++ /dev/null
@@ -1,1274 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import ymsg.network.*;
-import ymsg.network.event.*;
-
-/**
- * This class encapsulates the Roster class. Once created, it will
- * register itself as a listener to the encapsulated Roster and modify it's
- * local copy of Contacts and ContactGroups every time an event is generated
- * by the underlying framework. The class would also generate
- * corresponding sip-communicator events to all events coming from smack.
- *
- * @author Damian Minkov
- * @author Emil Ivov
- */
-public class ServerStoredContactListYahooImpl
-{
- private static final Logger logger =
- Logger.getLogger(ServerStoredContactListYahooImpl.class);
-
- /**
- * If there is no group and we add contact with no parent
- * a default group is created with name : DEFAULT_GROUP_NAME
- */
- private static final String DEFAULT_GROUP_NAME = "General";
-
- /**
- * The root contagroup. The container for all yahoo buddies and groups.
- */
- private final RootContactGroupYahooImpl rootGroup;
-
- /**
- * The operation set that created us and that we could use when dispatching
- * subscription events.
- */
- private final OperationSetPersistentPresenceYahooImpl parentOperationSet;
-
- /**
- * The provider that is on top of us.
- */
- private final ProtocolProviderServiceYahooImpl yahooProvider;
-
- private YahooSession yahooSession = null;
-
- /**
- * Listeners that would receive event notifications for changes in group
- * names or other properties, removal or creation of groups.
- */
- private Vector<ServerStoredGroupListener> serverStoredGroupListeners
- = new Vector<ServerStoredGroupListener>();
-
- private ContactListModListenerImpl contactListModListenerImpl
- = new ContactListModListenerImpl();
-
- /**
- * Handler for incoming authorization requests.
- */
- private AuthorizationHandler handler = null;
-
- private Hashtable<String, String> addedCustomYahooIds
- = new Hashtable<String, String>();
-
- /**
- * Creates a ServerStoredContactList wrapper for the specified BuddyList.
- *
- * @param parentOperationSet the operation set that created us and that
- * we could use for dispatching subscription events
- * @param provider the provider that has instantiated us.
- */
- ServerStoredContactListYahooImpl(
- OperationSetPersistentPresenceYahooImpl parentOperationSet,
- ProtocolProviderServiceYahooImpl provider)
- {
- //We need to init these as early as possible to ensure that the provider
- //and the operationsset would not be null in the incoming events.
- this.parentOperationSet = parentOperationSet;
-
- this.yahooProvider = provider;
- this.rootGroup = new RootContactGroupYahooImpl(this.yahooProvider);
- }
-
- /**
- * Handler for incoming authorization requests.
- *
- * @param handler an instance of an AuthorizationHandler for
- * authorization requests coming from other users requesting
- * permission add us to their contact list.
- */
- public void setAuthorizationHandler(AuthorizationHandler handler)
- {
- this.handler = handler;
- }
-
- /**
- * Returns the root group of the contact list.
- *
- * @return the root ContactGroup for the ContactList
- */
- public ContactGroup getRootGroup()
- {
- return rootGroup;
- }
-
- /**
- * Registers the specified group listener so that it would receive events
- * on group modification/creation/destruction.
- * @param listener the ServerStoredGroupListener to register for group
- * events
- */
- void addGroupListener(ServerStoredGroupListener listener)
- {
- synchronized(serverStoredGroupListeners)
- {
- if(!serverStoredGroupListeners.contains(listener))
- serverStoredGroupListeners.add(listener);
- }
- }
-
- /**
- * Removes the specified group listener so that it won't receive further
- * events on group modification/creation/destruction.
- * @param listener the ServerStoredGroupListener to unregister
- */
- void removeGroupListener(ServerStoredGroupListener listener)
- {
- synchronized(serverStoredGroupListeners)
- {
- this.serverStoredGroupListeners.remove(listener);
- }
- }
-
- /**
- * Creates the corresponding event and notifies all
- * <tt>ServerStoredGroupListener</tt>s that the source group has been
- * removed, changed, renamed or whatever happened to it.
- * @param group the ContactGroup that has been created/modified/removed
- * @param eventID the id of the event to generate.
- */
- private void fireGroupEvent(ContactGroupYahooImpl group, int eventID)
- {
- //bail out if no one's listening
- if(parentOperationSet == null){
- if (logger.isDebugEnabled())
- logger.debug("No presence op. set available. Bailing out.");
- return;
- }
-
- ServerStoredGroupEvent evt = new ServerStoredGroupEvent(
- group
- , eventID
- , parentOperationSet.getServerStoredContactListRoot()
- , yahooProvider
- , parentOperationSet);
-
- if (logger.isTraceEnabled())
- logger.trace("Will dispatch the following grp event: " + evt);
-
- Iterable<ServerStoredGroupListener> listeners;
- synchronized (serverStoredGroupListeners)
- {
- listeners
- = new ArrayList<ServerStoredGroupListener>(
- serverStoredGroupListeners);
- }
-
- for (ServerStoredGroupListener listener : listeners)
- {
- try{
- if (eventID == ServerStoredGroupEvent.GROUP_REMOVED_EVENT)
- listener.groupRemoved(evt);
- else if (eventID == ServerStoredGroupEvent.GROUP_RENAMED_EVENT)
- listener.groupNameChanged(evt);
- else if (eventID == ServerStoredGroupEvent.GROUP_CREATED_EVENT)
- listener.groupCreated(evt);
- else if (eventID == ServerStoredGroupEvent.GROUP_RESOLVED_EVENT)
- listener.groupResolved(evt);
- }catch(Exception ex){
- logger.warn("Unhandled Exception! ", ex);
- }
- }
- }
-
- /**
- * Make the parent persistent presence operation set dispatch a contact
- * removed event.
- * @param parentGroup the group where that the removed contact belonged to.
- * @param contact the contact that was removed.
- */
- private void fireContactRemoved( ContactGroup parentGroup,
- ContactYahooImpl contact)
- {
- //bail out if no one's listening
- if(parentOperationSet == null){
- if (logger.isDebugEnabled())
- logger.debug("No presence op. set available. Bailing out.");
- return;
- }
-
- //dispatch
- parentOperationSet.fireSubscriptionEvent(
- contact, parentGroup, SubscriptionEvent.SUBSCRIPTION_REMOVED);
- }
-
- /**
- * Make the parent persistent presence operation set dispatch a subscription
- * moved event.
- * @param oldParentGroup the group where the source contact was located
- * before being moved
- * @param newParentGroup the group that the source contact is currently in.
- * @param contact the contact that was added
- */
- private void fireContactMoved( ContactGroup oldParentGroup,
- ContactGroupYahooImpl newParentGroup,
- ContactYahooImpl contact)
- {
- //bail out if no one's listening
- if(parentOperationSet == null){
- if (logger.isDebugEnabled())
- logger.debug("No presence op. set available. Bailing out.");
- return;
- }
-
- //dispatch
- parentOperationSet.fireSubscriptionMovedEvent(
- contact, oldParentGroup, newParentGroup);
- }
-
- /**
- * Returns a reference to the provider that created us.
- * @return a reference to a ProtocolProviderServiceImpl instance.
- */
- ProtocolProviderServiceYahooImpl getParentProvider()
- {
- return yahooProvider;
- }
-
- /**
- * Returns the ConntactGroup with the specified name or null if no such
- * group was found.
- * <p>
- * @param name the name of the group we're looking for.
- * @return a reference to the ContactGroupYahooImpl instance we're looking
- * for or null if no such group was found.
- */
- public ContactGroupYahooImpl findContactGroup(String name)
- {
- String nameToLookFor = replaceIllegalChars(name);
- Iterator<ContactGroup> contactGroups = rootGroup.subgroups();
-
- while(contactGroups.hasNext())
- {
- ContactGroupYahooImpl contactGroup
- = (ContactGroupYahooImpl) contactGroups.next();
-
- if (contactGroup.getGroupName().equals(nameToLookFor))
- return contactGroup;
- }
-
- return null;
- }
-
- /**
- * Returns the Contact with the specified id or null if
- * no such id was found.
- *
- * @param id the id of the contact to find.
- * @return the <tt>Contact</tt> carrying the specified
- * <tt>screenName</tt> or <tt>null</tt> if no such contact exits.
- */
- public ContactYahooImpl findContactById(String id)
- {
- Iterator<ContactGroup> contactGroups = rootGroup.subgroups();
- ContactYahooImpl result = null;
-
- while(contactGroups.hasNext())
- {
- ContactGroupYahooImpl contactGroup
- = (ContactGroupYahooImpl) contactGroups.next();
-
- result = contactGroup.findContact(id);
-
- if (result != null)
- return result;
- }
-
- return null;
- }
-
- /**
- * Returns the Contact corresponding to the specified <tt>YahooUser</tt>
- * or null if no such id was found.
- *
- * @param yahooUser the YahooUser of the contact to find.
- * @return the <tt>Contact</tt> carrying the specified
- * <tt>screenName</tt> or <tt>null</tt> if no such contact exits.
- */
- public ContactYahooImpl findContactByYahooUser(YahooUser yahooUser)
- {
- return findContactById(yahooUser.getId().toLowerCase());
- }
-
- /**
- * Returns the ContactGroup containing the specified contact or null
- * if no such group or contact exist.
- *
- * @param child the contact whose parent group we're looking for.
- * @return the <tt>ContactGroup</tt> containing the specified
- * <tt>contact</tt> or <tt>null</tt> if no such groupo or contact
- * exist.
- */
- public ContactGroup findContactGroup(ContactYahooImpl child)
- {
- Iterator<ContactGroup> contactGroups = rootGroup.subgroups();
- String contactAddress = child.getAddress();
-
- while(contactGroups.hasNext())
- {
- ContactGroupYahooImpl contactGroup
- = (ContactGroupYahooImpl) contactGroups.next();
-
- if( contactGroup.findContact(contactAddress)!= null)
- return contactGroup;
- }
-
- return null;
- }
-
- /**
- * Adds a new contact with the specified screenname to the list under a
- * default location.
- * @param id the id of the contact to add.
- * @throws OperationFailedException
- */
- public void addContact(String id)
- throws OperationFailedException
- {
- ContactGroupYahooImpl parent = getFirstPersistentGroup();
-
- if(parent == null)
- {
- // if there is no group create it
- parent = createUnresolvedContactGroup(DEFAULT_GROUP_NAME);
- }
-
- addContact(parent, id);
- }
-
- /**
- * Adds a new contact with the specified screenname to the list under the
- * specified group.
- * @param id the id of the contact to add.
- * @param parent the group under which we want the new contact placed.
- * @throws OperationFailedException if the contact already exist
- */
- public void addContact(final ContactGroupYahooImpl parent, String id)
- throws OperationFailedException
- {
- if (logger.isTraceEnabled())
- logger.trace("Adding contact " + id + " to parent=" + parent);
-
- //if the contact is already in the contact list and is not volatile,
- //then only broadcast an event
- ContactYahooImpl existingContact = findContactById(id);
-
- if( existingContact != null
- && existingContact.isPersistent() )
- {
- if (logger.isDebugEnabled())
- logger.debug("Contact " + id + " already exists.");
- throw new OperationFailedException(
- "Contact " + id + " already exists.",
- OperationFailedException.SUBSCRIPTION_ALREADY_EXISTS);
- }
-
- if(id.indexOf("@") > -1 )
- addedCustomYahooIds.put(YahooSession.getYahooUserID(id), id);
-
- try
- {
- yahooSession.addFriend(YahooSession.getYahooUserID(id),
- parent.getGroupName());
- }
- catch(IOException ex)
- {
- throw new OperationFailedException(
- "Contact cannot be added " + id,
- OperationFailedException.NETWORK_FAILURE);
- }
- }
-
- /**
- * Creates a non persistent contact for the specified address. This would
- * also create (if necessary) a group for volatile contacts that would not
- * be added to the server stored contact list. This method would have no
- * effect on the server stored contact list.
- * @param id the address of the contact to create.
- * @return the newly created volatile <tt>ContactImpl</tt>
- */
- ContactYahooImpl createVolatileContact(String id)
- {
- if (logger.isTraceEnabled())
- logger.trace("Creating volatile contact " + id);
- ContactYahooImpl newVolatileContact =
- new ContactYahooImpl(id, this, false, false, true);
-
- //Check whether a volatile group already exists and if not create one
- ContactGroupYahooImpl theVolatileGroup = getNonPersistentGroup();
-
- //if the parent group is null then create it
- if (theVolatileGroup == null)
- {
- theVolatileGroup = new VolatileContactGroupYahooImpl(
- YahooActivator.getResources().getI18NString(
- "service.gui.NOT_IN_CONTACT_LIST_GROUP_NAME"),
- this);
-
- theVolatileGroup.addContact(newVolatileContact);
-
- this.rootGroup.addSubGroup(theVolatileGroup);
-
- fireGroupEvent(theVolatileGroup
- , ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
- else
- {
- theVolatileGroup.addContact(newVolatileContact);
-
- fireContactAdded(theVolatileGroup, newVolatileContact);
- }
-
- return newVolatileContact;
- }
-
-
- /**
- * Creates a non resolved contact for the specified address and inside the
- * specified group. The newly created contact would be added to the local
- * contact list as a standard contact but when an event is received from the
- * server concerning this contact, then it will be reused and only its
- * isResolved field would be updated instead of creating the whole contact
- * again.
- *
- * @param parentGroup the group where the unersolved contact is to be
- * created
- * @param id the Address of the contact to create.
- * @return the newly created unresolved <tt>ContactImpl</tt>
- */
- ContactYahooImpl createUnresolvedContact(ContactGroup parentGroup,
- String id)
- {
- if (logger.isTraceEnabled())
- logger.trace("Creating unresolved contact " + id
- + " to parent=" + parentGroup);
-
- ContactYahooImpl existingContact = findContactById(id);
-
- if( existingContact != null)
- {
- return existingContact;
- }
-
- ContactYahooImpl newUnresolvedContact
- = new ContactYahooImpl(id, this, false, true, false);
-
- if(parentGroup instanceof ContactGroupYahooImpl)
- ((ContactGroupYahooImpl)parentGroup).
- addContact(newUnresolvedContact);
-
- fireContactAdded(parentGroup, newUnresolvedContact);
-
- return newUnresolvedContact;
- }
-
- /**
- * Creates a non resolved contact group for the specified name. The newly
- * created group would be added to the local contact list as any other group
- * but when an event is received from the server concerning this group, then
- * it will be reused and only its isResolved field would be updated instead
- * of creating the whole group again.
- * <p>
- * @param groupName the name of the group to create.
- * @return the newly created unresolved <tt>ContactGroupImpl</tt>
- */
- ContactGroupYahooImpl createUnresolvedContactGroup(String groupName)
- {
- ContactGroupYahooImpl existingGroup = findContactGroup(groupName);
-
- if( existingGroup != null )
- {
- if (logger.isDebugEnabled())
- logger.debug("ContactGroup " + groupName + " already exists.");
- return existingGroup;
- }
-
- ContactGroupYahooImpl newUnresolvedGroup =
- new ContactGroupYahooImpl(groupName, this);
-
- this.rootGroup.addSubGroup(newUnresolvedGroup);
-
- fireGroupEvent(newUnresolvedGroup
- , ServerStoredGroupEvent.GROUP_CREATED_EVENT);
-
- return newUnresolvedGroup;
- }
-
- /**
- * Creates the specified group on the server stored contact list.
- * @param groupName a String containing the name of the new group.
- * @throws OperationFailedException with code CONTACT_GROUP_ALREADY_EXISTS
- * if the group we're trying to create is already in our contact list.
- */
- public void createGroup(String groupName)
- throws OperationFailedException
- {
- if (logger.isTraceEnabled())
- logger.trace("Creating group: " + groupName);
-
- ContactGroupYahooImpl existingGroup = findContactGroup(groupName);
-
- if( existingGroup != null && existingGroup.isPersistent() )
- {
- if (logger.isDebugEnabled())
- logger.debug("ContactGroup " + groupName + " already exists.");
- throw new OperationFailedException(
- "ContactGroup " + groupName + " already exists.",
- OperationFailedException.CONTACT_GROUP_ALREADY_EXISTS);
- }
-
- // create unresolved group if friend is added - group will be resolved
- createUnresolvedContactGroup(groupName);
- }
-
- /**
- * Removes the specified group from the buddy list.
- * @param groupToRemove the group that we'd like removed.
- */
- @SuppressWarnings("unchecked") //jymsg legacy code
- public void removeGroup(ContactGroupYahooImpl groupToRemove)
- {
- // to remove group just remove all the contacts in it
-
- if (logger.isTraceEnabled())
- logger.trace("removing group " + groupToRemove);
-
- // if its not persistent group just remove it
- if(!groupToRemove.isPersistent() || !groupToRemove.isResolved())
- {
- rootGroup.removeSubGroup(groupToRemove);
- fireGroupEvent(groupToRemove,
- ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
- return;
- }
-
- Vector<YahooUser> contacts
- = groupToRemove.getSourceGroup().getMembers();
-
- if(contacts.size() == 0)
- {
- // the group is empty just remove it
- rootGroup.removeSubGroup(groupToRemove);
- fireGroupEvent(groupToRemove,
- ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
- return;
- }
-
- /*
- * ContactGroupYahooImpl#getGroupName() isn't a plain getter so
- * performance-wise we're better off not calling it multiple times in
- * the following loop.
- */
- String groupToRemoveName = groupToRemove.getGroupName();
-
- for (YahooUser item : contacts)
- {
- try
- {
- yahooSession.removeFriend(item.getId(), groupToRemoveName);
- }
- catch(IOException ex)
- {
- if (logger.isInfoEnabled())
- logger.info("Cannot Remove contact " + item.getId());
- }
- }
- }
-
- /**
- * Removes a contact from the serverside list
- * Event will come for successful operation
- * @param contactToRemove ContactYahooImpl
- */
- void removeContact(ContactYahooImpl contactToRemove)
- {
- if (logger.isTraceEnabled())
- logger.trace("Removing yahoo contact "
- + contactToRemove.getSourceContact());
-
- if(contactToRemove.isVolatile())
- {
- ContactGroupYahooImpl parent =
- (ContactGroupYahooImpl)contactToRemove.getParentContactGroup();
-
- parent.removeContact(contactToRemove);
- fireContactRemoved(parent, contactToRemove);
- return;
- }
-
- try
- {
- yahooSession.removeFriend(
- contactToRemove.getSourceContact().getId(),
- contactToRemove.getParentContactGroup().getGroupName());
- }
- catch(IOException ex)
- {
- if (logger.isInfoEnabled())
- logger.info("Cannot Remove contact " + contactToRemove);
- }
- }
-
- /**
- * Renames the specified group according to the specified new name..
- * @param groupToRename the group that we'd like removed.
- * @param newName the new name of the group
- */
- public void renameGroup(ContactGroupYahooImpl groupToRename, String newName)
- {
- // not working
- /*
- try
- {
- yahooSession.renameGroup(groupToRename.getGroupName(), newName);
- }
- catch(IOException ex)
- {
- if (logger.isInfoEnabled())
- logger.info("Cannot rename group " + groupToRename);
- }
-
- fireGroupEvent(groupToRename,
- ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
- */
- }
-
- /**
- * Moves the specified <tt>contact</tt> to the group indicated by
- * <tt>newParent</tt>.
- * @param contact the contact that we'd like moved under the new group.
- * @param newParent the group where we'd like the parent placed.
- */
- public void moveContact(ContactYahooImpl contact,
- ContactGroupYahooImpl newParent)
- {
- String userID = contact.getID();
- try
- {
- contactListModListenerImpl.
- waitForMove(userID,
- contact.getParentContactGroup().getGroupName());
-
- yahooSession.addFriend(
- userID,
- newParent.getGroupName());
- }
- catch(IOException ex)
- {
- contactListModListenerImpl.removeWaitForMove(userID);
- logger.error("Contact cannot be added " + ex.getMessage());
- }
- }
-
- /**
- * Returns the volatile group
- *
- * @return ContactGroupYahooImpl
- */
- private ContactGroupYahooImpl getNonPersistentGroup()
- {
- for (int i = 0; i < getRootGroup().countSubgroups(); i++)
- {
- ContactGroupYahooImpl gr =
- (ContactGroupYahooImpl)getRootGroup().getGroup(i);
-
- if(!gr.isPersistent())
- return gr;
- }
-
- return null;
- }
-
- /**
- * Returns the first persistent group
- *
- * @return ContactGroupIcqImpl
- */
- private ContactGroupYahooImpl getFirstPersistentGroup()
- {
- for (int i = 0; i < getRootGroup().countSubgroups(); i++)
- {
- ContactGroupYahooImpl gr =
- (ContactGroupYahooImpl)getRootGroup().getGroup(i);
-
- if(gr.isPersistent())
- return gr;
- }
-
- return null;
- }
-
- /**
- * Make the parent persistent presence operation set dispatch a contact
- * added event.
- * @param parentGroup the group where the new contact was added
- * @param contact the contact that was added
- */
- void fireContactAdded( ContactGroup parentGroup,
- ContactYahooImpl contact)
- {
- //bail out if no one's listening
- if(parentOperationSet == null){
- if (logger.isDebugEnabled())
- logger.debug("No presence op. set available. Bailing out.");
- return;
- }
-
- //dispatch
- parentOperationSet.fireSubscriptionEvent(
- contact, parentGroup, SubscriptionEvent.SUBSCRIPTION_CREATED);
- }
-
- /**
- * Make the parent persistent presence operation set dispatch a contact
- * resolved event.
- * @param parentGroup the group that the resolved contact belongs to.
- * @param contact the contact that was resolved
- */
- void fireContactResolved( ContactGroup parentGroup,
- ContactYahooImpl contact)
- {
- //bail out if no one's listening
- if(parentOperationSet == null){
- if (logger.isDebugEnabled())
- logger.debug("No presence op. set available. Bailing out.");
- return;
- }
-
- //dispatch
- parentOperationSet.fireSubscriptionEvent(
- contact, parentGroup, SubscriptionEvent.SUBSCRIPTION_RESOLVED);
- }
-
- /**
- * When the protocol is online this method is used to fill or resolve
- * the current contact list
- */
- @SuppressWarnings("unchecked") //jymsg legacy code
- private void initList()
- {
- if (logger.isTraceEnabled())
- logger.trace("Start init list of "
- + yahooProvider.getAccountID().getUserID());
-
- for (YahooGroup item : yahooSession.getGroups())
- {
- ContactGroupYahooImpl group = findContactGroup(item.getName());
-
- if(group == null)
- {
- // create the group as it doesn't exist
- group = new ContactGroupYahooImpl(
- item, item.getMembers(), this, true);
-
- rootGroup.addSubGroup(group);
-
- //tell listeners about the added group
- fireGroupEvent(group,
- ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
- else
- {
- // the group exist so just resolved. The group will check and
- // create or resolve its entries
- group.setResolved(item);
-
- //fire an event saying that the group has been resolved
- fireGroupEvent(group
- , ServerStoredGroupEvent.GROUP_RESOLVED_EVENT);
-
- /** @todo if something to delete . delete it */
- }
-
- if (logger.isTraceEnabled())
- logger.trace("Init of group done! : " + group);
- }
- }
-
- /**
- * @param name Name of the group to search
- * @return The yahoo group with given name
- */
- private YahooGroup findGroup(String name)
- {
- for (YahooGroup elem : yahooSession.getGroups())
- {
- if(elem.getName().equals(name))
- return elem;
- }
- return null;
- }
-
- /**
- * Process incoming authorization requests.
- * @param ev the event to process.
- */
- void processAuthorizationRequest(SessionAuthorizationEvent ev)
- {
- if(handler == null)
- return;
-
- Contact srcContact = findContactById(ev.getFrom());
-
- // if there is no such contact we create it as
- // volatile so we can fire notification
- // and then if accepted add it in the protocol
- // so we can receive its states
- boolean isCurrentlyCreated = false;
- if(srcContact == null)
- {
- srcContact = createVolatileContact(ev.getFrom());
- isCurrentlyCreated = true;
- }
-
- AuthorizationRequest authRequest = new AuthorizationRequest();
- authRequest.setReason(ev.getMessage());
-
- AuthorizationResponse authResponse =
- handler.processAuthorisationRequest(
- authRequest, srcContact);
-
- if (authResponse.getResponseCode() == AuthorizationResponse.IGNORE)
- {
- return;
- }
- else if (authResponse.getResponseCode() == AuthorizationResponse.REJECT)
- {
- removeContact((ContactYahooImpl)srcContact);
- try
- {
- yahooSession.rejectFriendAuthorization(
- ev, ev.getFrom(), authResponse.getReason());
- }
- catch(IOException ex)
- {
- logger.error("cannot send auth deny", ex);
- }
-
- return;
- }
-
- // else we accepted it
- try
- {
- yahooSession.acceptFriendAuthorization(ev, ev.getFrom());
- }
- catch(IOException ex)
- {
- logger.error("cannot send auth deny", ex);
- }
-
- if(isCurrentlyCreated)
- try
- {
- addContact(ev.getFrom());
- }
- catch (OperationFailedException ex)
- {
- logger.error("Cannot add friend", ex);
- }
- }
-
- /**
- * Imulates firing adding contact in group and moving contact to group.
- * When moving contact it is first adding to the new group then
- * it is removed from the old one.
- */
- private class ContactListModListenerImpl
- extends SessionAdapter
- {
- private final Hashtable<String, Object> waitMove
- = new Hashtable<String, Object>();
-
- public void waitForMove(String id, String oldParent)
- {
- waitMove.put(id, oldParent);
- }
-
- public void removeWaitForMove(String id)
- {
- waitMove.remove(id);
- }
-
- /**
- * Successfully added a friend
- * friend - YahooUser of friend
- * group - name of group added to
- * @param ev fired event
- */
- @Override
- public void friendAddedReceived(SessionFriendEvent ev)
- {
- if (logger.isTraceEnabled())
- logger.trace("Receive event for adding a friend : " + ev);
-
- ContactGroupYahooImpl group =
- findContactGroup(ev.getGroup());
-
- if(group == null){
- if (logger.isTraceEnabled())
- logger.trace("Group not found!" + ev.getGroup());
- return;
- }
-
- String contactID = ev.getFriend().getId();
- ContactYahooImpl contactToAdd = findContactById(contactID);
-
- // if group is note resolved resolve it
- // this means newly created group
- if(!group.isResolved())
- {
- // if the contact is volatile me must remove it
- // as new one will be created
- if(contactToAdd != null && contactToAdd.isVolatile())
- {
- ContactGroupYahooImpl parent
- = (ContactGroupYahooImpl)contactToAdd
- .getParentContactGroup();
-
- parent.removeContact(contactToAdd);
- fireContactRemoved(parent, contactToAdd);
- }
-
- YahooGroup gr = findGroup(ev.getGroup());
-
- if(gr != null)
- group.setResolved(gr);
-
- // contact will be added when resolving the group
-
- return;
- }
-
-
- boolean isVolatile = false;
-
- if(contactToAdd == null)
- {
- if(addedCustomYahooIds.containsKey(contactID))
- {
- String expectedContactID =
- addedCustomYahooIds.remove(contactID);
-
- contactToAdd =
- new ContactYahooImpl(expectedContactID, ev.getFriend(),
- ServerStoredContactListYahooImpl.this, true, true);
- }
- else
- {
- contactToAdd =
- new ContactYahooImpl(ev.getFriend(),
- ServerStoredContactListYahooImpl.this, true, true);
- }
- }
- else
- {
- isVolatile = contactToAdd.isVolatile();
- }
-
- //first check is contact is moving from a group
- Object isWaitingForMove = waitMove.get(contactID);
-
- if(isWaitingForMove != null && isWaitingForMove instanceof String)
- {
- // waits for move into group
- // will remove it from old group and will wait for event remove
- // from group, then will fire moved to group event
- String oldParent = (String)isWaitingForMove;
-
- group.addContact(contactToAdd);
- waitMove.put(contactID, group.getSourceGroup());
- try
- {
- yahooSession.removeFriend(contactID, oldParent);
- }
- catch(IOException ex)
- {
- if (logger.isInfoEnabled())
- logger.info("Cannot Remove(till moving) contact :" +
- contactToAdd + " from group " + oldParent);
- }
- return;
- }
-
- if(isVolatile)
- {
- // we must remove the volatile buddy as we will add
- // the persistent one.
- // Volatile buddy is moving from the volatile group
- // to the new one
- ContactGroupYahooImpl parent =
- (ContactGroupYahooImpl)contactToAdd.getParentContactGroup();
-
- parent.removeContact(contactToAdd);
- fireContactRemoved(parent, contactToAdd);
-
- contactToAdd.setPersistent(true);
- contactToAdd.setResolved(ev.getFriend());
-
- group.addContact(contactToAdd);
-
- fireContactAdded(group, contactToAdd);
- waitMove.remove(contactID);
-
- return;
- }
-
- group.addContact(contactToAdd);
- fireContactAdded(group, contactToAdd);
- }
-
- /**
- * Successfully removed a friend
- * friend - YahooUser of friend
- * group - name of group removed from
- * @param ev fired event
- */
- @Override
- public void friendRemovedReceived(SessionFriendEvent ev)
- {
- if (logger.isTraceEnabled())
- logger.trace("Receive event for removing a friend : " + ev);
-
- String contactID = ev.getFriend().getId();
-
- // first check is this part of move action
- Object waitForMoveObj = waitMove.get(contactID);
- if(waitForMoveObj != null && waitForMoveObj instanceof YahooGroup)
- {
- // first get the group - oldParent
- ContactGroupYahooImpl oldParent
- = findContactGroup(ev.getGroup());
- ContactYahooImpl contactToRemove
- = oldParent.findContact(contactID);
-
- oldParent.removeContact(contactToRemove);
- waitMove.remove(contactID);
-
- ContactGroupYahooImpl newParent =
- findContactGroup(((YahooGroup)waitForMoveObj).getName());
-
- fireContactMoved(oldParent, newParent, contactToRemove);
- return;
- }
-
- ContactYahooImpl contactToRemove = findContactById(contactID);
-
- // strange we cannot find the contact to be removed
- if(contactToRemove == null)
- return;
-
- ContactGroupYahooImpl parentGroup =
- (ContactGroupYahooImpl)contactToRemove.
- getParentContactGroup();
- parentGroup.removeContact(contactToRemove);
- fireContactRemoved(parentGroup, contactToRemove);
-
- // check if the group is deleted. If the contact is the last one in
- // the group. The group is also deleted
- if(findGroup(ev.getGroup()) == null)
- {
- rootGroup.removeSubGroup(parentGroup);
- fireGroupEvent(parentGroup,
- ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
- }
- }
-
- /**
- * Someone wants to add us to their friends list
- * to - the target (us!)
- * from - the user who wants to add us
- * message - the request message text
- * @param ev fired event
- */
- @Override
- public void contactRequestReceived(SessionEvent ev)
- {
- if (logger.isInfoEnabled())
- logger.info("contactRequestReceived : " + ev);
-
- if(handler == null || ev.getFrom() == null)
- return;
-
- ContactYahooImpl contact = findContactById(ev.getFrom());
-
- if(contact == null)
- contact = createVolatileContact(ev.getFrom());
-
- AuthorizationRequest request = new AuthorizationRequest();
- request.setReason(ev.getMessage());
-
- AuthorizationResponse resp =
- handler.processAuthorisationRequest(request, contact);
-
- if (resp.getResponseCode() == AuthorizationResponse.REJECT)
- {
- try{
- yahooSession.rejectContact(ev, resp.getReason());
- }catch(IOException ex){
- logger.error("Cannot send reject : " + ex.getMessage());
- }
- }
- }
-
- /**
- * Someone has rejected our attempts to add them to our friends list
- * from - the user who rejected us
- * message - rejection message text
- * @param ev fired event
- */
- @Override
- public void contactRejectionReceived(SessionEvent ev)
- {
- if (logger.isInfoEnabled())
- logger.info("contactRejectionReceived : " + ev);
-
- if(handler == null)
- return;
-
- ContactYahooImpl contact = findContactById(ev.getFrom());
-
- AuthorizationResponse resp =
- new AuthorizationResponse(AuthorizationResponse.REJECT,
- ev.getMessage());
- handler.processAuthorizationResponse(resp, contact);
- }
-
- /**
- * Invoked on picture received.
- * @param ev fired event
- */
- @Override
- public void pictureReceived(SessionPictureEvent ev)
- {
- ContactYahooImpl contact = findContactById(ev.getFrom());
-
- if(contact == null)
- return;
-
- contact.setImage(ev.getPictureData());
-
- parentOperationSet.fireContactPropertyChangeEvent(
- ContactPropertyChangeEvent.PROPERTY_IMAGE,
- contact, null, ev.getPictureData());
- }
-
- /**
- * Process Authorization responses
- * @param ev the event to process
- */
- @Override
- public void authorizationReceived(SessionAuthorizationEvent ev)
- {
- if(ev.isAuthorizationAccepted())
- {
- if (logger.isTraceEnabled())
- logger.trace("authorizationAccepted from " + ev.getFrom());
- Contact srcContact = findContactById(ev.getFrom());
-
- if(srcContact == null)
- if (logger.isTraceEnabled())
- logger.trace("No contact found");
- else
- handler.processAuthorizationResponse(
- new AuthorizationResponse(
- AuthorizationResponse.ACCEPT,
- ev.getMessage()),
- srcContact);
- }
- else if(ev.isAuthorizationDenied())
- {
- if (logger.isTraceEnabled())
- logger.trace("authorizationDenied from " + ev.getFrom());
- Contact srcContact = findContactById(ev.getFrom());
-
- if(srcContact == null)
- if (logger.isTraceEnabled())
- logger.trace("No contact found");
- else
- {
- handler.processAuthorizationResponse(
- new AuthorizationResponse(
- AuthorizationResponse.REJECT,
- ev.getMessage()),
- srcContact);
- try
- {
- removeContact((ContactYahooImpl)srcContact);
- } catch (Exception ex)
- {
- logger.error("cannot remove denied contact : " +
- srcContact, ex);
- }
- }
- }
- else if(ev.isAuthorizationRequest())
- {
- if (logger.isTraceEnabled())
- logger.trace("authorizationRequestReceived from "
- + ev.getFrom());
- processAuthorizationRequest(ev);
- }
- }
- }
-
- /**
- * Sets the yahoo session instance of the lib
- * which comunicates with the server
- * @param session YahooSession
- */
- void setYahooSession(YahooSession session)
- {
- this.yahooSession = session;
- session.addSessionListener(contactListModListenerImpl);
- initList();
- }
-
- /**
- * It seems that ymsg (or the Yahoo! service itself as the problem also
- * appears with libpurple) would return illegal chars for names that were
- * entered in cyrillic. We use this method to translate their names into
- * something that we could actually display and store here.
- *
- * @param ymsgString the <tt>String</tt> containing illegal chars.
- *
- * @return a String where all illegal chars are converted into human
- * readable ones
- */
- static String replaceIllegalChars(String ymsgString)
- {
- return ymsgString.replace((char)26, '?');
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/VolatileContactGroupYahooImpl.java b/src/net/java/sip/communicator/impl/protocol/yahoo/VolatileContactGroupYahooImpl.java
deleted file mode 100644
index e2c589a..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/VolatileContactGroupYahooImpl.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The Yahoo implementation of the Volatile ContactGroup interface.
- *
- * @author Damian Minkov
- */
-public class VolatileContactGroupYahooImpl
- extends ContactGroupYahooImpl
-{
- /**
- * This contact group name
- */
- private String contactGroupName = null;
-
- /**
- * Creates an Yahoo group using the specified group name
- * @param groupName String groupname
- * @param ssclCallback a callback to the server stored contact list
- * we're creating.
- */
- VolatileContactGroupYahooImpl(
- String groupName,
- ServerStoredContactListYahooImpl ssclCallback)
- {
- super(groupName, ssclCallback);
- this.contactGroupName = groupName;
- }
-
- /**
- * Returns the name of this group.
- * @return a String containing the name of this group.
- */
- @Override
- public String getGroupName()
- {
- return contactGroupName;
- }
-
- /**
- * Returns a string representation of this group, in the form
- * YahooGroup.GroupName[size]{ buddy1.toString(), buddy2.toString(), ...}.
- * @return a String representation of the object.
- */
- @Override
- public String toString()
- {
- StringBuffer buff = new StringBuffer("VolatileYahooGroup.");
- buff.append(getGroupName());
- buff.append(", childContacts="+countContacts()+":[");
-
- Iterator<Contact> contacts = contacts();
-
- while (contacts.hasNext())
- {
- Contact contact = contacts.next();
-
- buff.append(contact.toString());
- if(contacts.hasNext())
- buff.append(", ");
- }
- return buff.append("]").toString();
- }
-
- /**
- * Determines whether or not this contact group is being stored by the
- * server. Non persistent contact groups exist for the sole purpose of
- * containing non persistent contacts.
- * @return true if the contact group is persistent and false otherwise.
- */
- @Override
- public boolean isPersistent()
- {
- return false;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/YahooAccountID.java b/src/net/java/sip/communicator/impl/protocol/yahoo/YahooAccountID.java
deleted file mode 100644
index 0eb0e86..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/YahooAccountID.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The Yahoo implementation of a sip-communicator AccountID
- *
- * @author Damian Minkov
- */
-public class YahooAccountID
- extends AccountID
-{
- /**
- * Creates an account id from the specified id and account properties.
- * @param id the id identifying this account
- * @param accountProperties any other properties necessary for the account.
- */
- YahooAccountID(String id, Map<String, String> accountProperties )
- {
- super(YahooSession.getYahooUserID(id),
- accountProperties, ProtocolNames.YAHOO, "yahoo.com");
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/YahooActivator.java b/src/net/java/sip/communicator/impl/protocol/yahoo/YahooActivator.java
deleted file mode 100644
index 1e7ca01..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/YahooActivator.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-import org.jitsi.service.configuration.*;
-import org.jitsi.service.resources.*;
-import org.osgi.framework.*;
-
-/**
- * Loads the Yahoo provider factory and registers it with service in the OSGI
- * bundle context.
- *
- * @author Damian Minkov
- */
-public class YahooActivator
- implements BundleActivator
-{
- private ServiceRegistration yahooPpFactoryServReg = null;
- private static BundleContext bundleContext = null;
- private static ConfigurationService configurationService = null;
-
- private static ProtocolProviderFactoryYahooImpl yahooProviderFactory = null;
-
- private static ResourceManagementService resourcesService;
-
- /**
- * Called when this bundle is started so the Framework can perform the
- * bundle-specific activities necessary to start this bundle.
- *
- * @param context The execution context of the bundle being started.
- * @throws Exception If this method throws an exception, this bundle is
- * marked as stopped and the Framework will remove this bundle's
- * listeners, unregister all services registered by this bundle, and
- * release all services used by this bundle.
- */
- public void start(BundleContext context) throws Exception
- {
- bundleContext = context;
-
- Hashtable<String, String> hashtable = new Hashtable<String, String>();
- hashtable.put(ProtocolProviderFactory.PROTOCOL, ProtocolNames.YAHOO);
-
- yahooProviderFactory = new ProtocolProviderFactoryYahooImpl();
-
- //reg the yahoo account man.
- yahooPpFactoryServReg = context.registerService(
- ProtocolProviderFactory.class.getName(),
- yahooProviderFactory,
- hashtable);
- }
-
- /**
- * Returns a reference to a ConfigurationService implementation currently
- * registered in the bundle context or null if no such implementation was
- * found.
- *
- * @return ConfigurationService a currently valid implementation of the
- * configuration service.
- */
- public static ConfigurationService getConfigurationService()
- {
- if(configurationService == null)
- {
- ServiceReference confReference
- = bundleContext.getServiceReference(
- ConfigurationService.class.getName());
- configurationService
- = (ConfigurationService) bundleContext.getService(confReference);
- }
- return configurationService;
- }
-
- /**
- * Returns a reference to the bundle context that we were started with.
- * @return a reference to the BundleContext instance that we were started
- * witn.
- */
- public static BundleContext getBundleContext()
- {
- return bundleContext;
- }
-
- /**
- * Retrurns a reference to the protocol provider factory that we have
- * registered.
- * @return a reference to the <tt>ProtocolProviderFactoryYahooImpl</tt>
- * instance that we have registered from this package.
- */
- static ProtocolProviderFactoryYahooImpl getProtocolProviderFactory()
- {
- return yahooProviderFactory;
- }
-
- /**
- * Called when this bundle is stopped so the Framework can perform the
- * bundle-specific activities necessary to stop the bundle.
- *
- * @param context The execution context of the bundle being stopped.
- * @throws Exception If this method throws an exception, the bundle is
- * still marked as stopped, and the Framework will remove the bundle's
- * listeners, unregister all services registered by the bundle, and
- * release all services used by the bundle.
- */
- public void stop(BundleContext context) throws Exception
- {
- yahooProviderFactory.stop();
- yahooPpFactoryServReg.unregister();
- }
-
- public static ResourceManagementService getResources()
- {
- if (resourcesService == null)
- {
- ServiceReference serviceReference = bundleContext
- .getServiceReference(ResourceManagementService.class.getName());
-
- if(serviceReference == null)
- return null;
-
- resourcesService = (ResourceManagementService) bundleContext
- .getService(serviceReference);
- }
-
- return resourcesService;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/YahooSession.java b/src/net/java/sip/communicator/impl/protocol/yahoo/YahooSession.java
deleted file mode 100644
index f24e50c..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/YahooSession.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.yahoo;
-
-import java.io.*;
-
-import ymsg.network.*;
-
-/**
- * Extends The Yahoo session to have access to some
- * protected functionality
- * Not working for now.
- *
- * @author Damian Minkov
- */
-public class YahooSession
- extends Session
-{
- /**
- * Renames a group. Not working for now
- */
- public void renameGroup(String oldName, String newName)
- throws IOException
- {
- transmitGroupRename(oldName, newName);
- }
-
- /**
- * Removes the server part from the given id
- */
- public static String getYahooUserID(String id)
- {
- return (id.indexOf("@") > -1 )
- ? id.substring(0, id.indexOf("@"))
- : id;
- }
-
- /**
- * Sending typing notifications
- * @param to user we are notifing
- * @param from our user id
- */
- void keyTyped(String to, String from)
- {
- try {
- transmitNotify(to, from, true, " ", NOTIFY_TYPING);
- }catch(IOException e){}
- }
-
- /**
- * Sending stop typing notifications
- * @param to user we are notifing
- * @param from our user id
- */
- void stopTyping(String to, String from)
- {
- try {
- transmitNotify(to, from, false, " ", NOTIFY_TYPING);
- }catch(IOException e){}
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/yahoo/yahoo.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/yahoo/yahoo.provider.manifest.mf
deleted file mode 100644
index 39e23bf..0000000
--- a/src/net/java/sip/communicator/impl/protocol/yahoo/yahoo.provider.manifest.mf
+++ /dev/null
@@ -1,22 +0,0 @@
-Bundle-Activator: net.java.sip.communicator.impl.protocol.yahoo.YahooActivator
-Bundle-Name: Yahoo Protocol Provider Implementation
-Bundle-Description: An Yahoo implementation of the Protocol Provider Service.
-Bundle-Vendor: jitsi.org
-Bundle-Version: 0.0.1
-Bundle-SymbolicName: net.java.sip.communicator.protocol.yahoo
-Import-Package: org.osgi.framework,
- javax.net.ssl,
- javax.swing,
- javax.swing.text,
- javax.xml.parsers,
- javax.naming,
- javax.naming.directory,
- org.xml.sax,
- sun.security.action,
- org.jitsi.service.configuration,
- org.jitsi.service.resources, net.java.sip.communicator.service.resources,
- net.java.sip.communicator.util,
- net.java.sip.communicator.service.dns,
- net.java.sip.communicator.service.protocol,
- net.java.sip.communicator.service.protocol.yahooconstants,
- net.java.sip.communicator.service.protocol.event
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/BonjourService.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/BonjourService.java
deleted file mode 100644
index 8258da7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/BonjourService.java
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.impl.protocol.zeroconf.jmdns.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Class dealing with JmDNS and treating all the
- * incoming connections on the bonjour port
- * @author Christian Vincenot
- */
-public class BonjourService extends Thread
- implements ServiceListener,
- DNSListener
-{
- private static final Logger logger =
- Logger.getLogger(BonjourService.class);
-
- private int port = 5298;
- private ServerSocket sock = null;
- private String id = null;
- private JmDNS jmdns=null;
- private final Map<String, Object> props = new Hashtable<String, Object>();
- private ServiceInfo service = null;
- private boolean dead = false;
-
- private final List<ContactZeroconfImpl> contacts
- = new Vector<ContactZeroconfImpl>();
-
- private ProtocolProviderServiceZeroconfImpl pps;
- OperationSetPersistentPresenceZeroconfImpl opSetPersPresence;
-
- private ZeroconfAccountID acc;
-
- /* Should maybe better get the status directly from OperationSetPresence */
- private PresenceStatus status = ZeroconfStatusEnum.OFFLINE;
-
- /**
- * Returns the corresponding ProtocolProviderService
- * @return corresponding ProtocolProviderService
- */
- public ProtocolProviderServiceZeroconfImpl getPPS()
- {
- return pps;
- }
-
- /**
- * Returns the id of this service.
- * @return returns the id of this service.
- */
- String getID()
- {
- return id;
- }
-
- /**
- * Creates a new instance of the Bonjour service thread
- * @param port TCP Port number on which to try to start the Bonjour service
- * @param pps ProtocolProviderService instance
- * which is creating this BonjourService
- */
- public BonjourService(int port,
- ProtocolProviderServiceZeroconfImpl pps)
- {
- this.acc = (ZeroconfAccountID) pps.getAccountID();
- this.port = port;
- this.id = acc.getUserID();
- this.pps = pps;
-
- opSetPersPresence =
- (OperationSetPersistentPresenceZeroconfImpl) pps
- .getOperationSet(OperationSetPersistentPresence.class);
-
- // Gaim
- props.put("1st", (acc.getFirst() == null)? "":acc.getFirst());
- props.put("email", (acc.getMail() == null)? "":acc.getMail());
- props.put("jid", this.id);
- props.put("last", (acc.getLast() == null)?"":acc.getLast());
- props.put("msg", opSetPersPresence.getCurrentStatusMessage());
- props.put("status", "avail");
-
- //iChat
- props.put("phsh","000");
- //props.put("status","avail");
- //props.put("port.p2pj", "5298");
- props.put("vc", "C!");
- //props.put("1st", "John");
- props.put("txtvers","1");
-
- //XEP-0174 (Final paper)
- props.put("ext","");
- props.put("nick", (acc.getFirst() == null)? this.id:acc.getFirst());
- props.put("ver", "1");
- props.put("node", "SIP Communicator");
-
- //Ours
- props.put("client", "SIP Communicator");
-
- changeStatus(opSetPersPresence.getPresenceStatus());
-
- sock = createSocket(port);
- if (sock == null)
- return;
-
- port = sock.getLocalPort();
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: ServerSocket bound to port "+port);
-
- props.put("port.p2pj", Integer.toString(port));
- this.setDaemon(true);
- this.start();
- }
-
- /* TODO: Better exception checking to avoid sudden exit and bonjour
- * service shutdown */
-
- /**
- * Walk?
- */
- @Override
- public void run()
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Bonjour Service Thread up and running!");
-
- /* Put jmDNS in DEBUD Mode :
- * Following verbosity levels can be chosen :
- * "INFO" , "WARNING", "SEVERE", "ALL", "FINE", "FINER", "FINEST", etc
- */
- //System.setProperty("jmdns.debug", "0");
-
- while (dead == false)
- {
- if (sock == null || sock.isClosed())
- {
- sock = createSocket(port);
- /* What should we do now? TEMPORARY: shutdown()*/
- if (sock == null) shutdown();
- port = sock.getLocalPort();
- props.put("port.p2pj", Integer.toString(port));
- //TODO: update JmDNS in case the port had to be changed!
- }
- try
- {
- Socket connection = sock.accept();
- ContactZeroconfImpl contact = getContact(null,
- connection.getInetAddress());
- /*if (status.equals(ZeroconfStatusEnum.OFFLINE)
- || status.equals(ZeroconfStatusEnum.INVISIBLE) */
- if (dead == true) break;
-
- if ((contact == null)
- || (contact.getClientThread() != null))
- {
- if (contact == null)
- logger.error("ZEROCONF: Connexion from "
- + "unknown contact ["
- + connection.getInetAddress()
- +"]. REJECTING!");
- else if (contact.getClientThread() == null)
- logger.error("ZEROCONF: Redundant chat "
- + "channel ["
- + contact
- +"]. REJECTING!");
- connection.close();
- }
- else new ClientThread(connection, this);
- }
- catch(Exception e)
- {
- logger.error(e);
- }
- }
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Going Offline - "
- +"BonjourService Thread exiting!");
- }
-
- /**
- * Might be used for shutdown...
- */
- public void shutdown()
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Shutdown!");
-
- dead = true;
- try
- { sock.close(); }
- catch (Exception ex)
- { logger.error(ex); }
-
- changeStatus(ZeroconfStatusEnum.OFFLINE);
- if(jmdns != null)
- jmdns.close();
- }
-
- private ServerSocket createSocket(int port)
- {
- ServerSocket sock=null;
- try
- {
- sock = new ServerSocket(port);
- }
- catch(Exception e)
- {
- logger.error("ZEROCONF: Couldn't bind socket to port "
- +port+"! Switching to an other port...");
- try
- {
- sock = new ServerSocket(0);
- }
- catch (IOException ex)
- {
- logger.error("ZEROCONF: FATAL ERROR => "
- +"Couldn't bind to a port!!", ex);
- }
- }
-
- return sock;
- }
-
- /**
- * Changes the status of the local user.
- * @param stat New presence status
- */
- public void changeStatus(PresenceStatus stat)
- {
- /* [old_status == new_status ?] => NOP */
- if (stat.equals(status))
- return;
-
- /* [new_status == OFFLINE ?] => clean up everything */
- if (stat.equals(ZeroconfStatusEnum.OFFLINE))
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Going OFFLINE");
- //jmdns.unregisterAllServices();
- jmdns.removeServiceListener("_presence._tcp.local.", this);
- jmdns.close();
- jmdns=null;
- //dead = true;
-
- // Erase all contacts by putting them OFFLINE
- opSetPersPresence.changePresenceStatusForAllContacts(
- opSetPersPresence.getServerStoredContactListRoot(), stat);
-
- try
- {
- sleep(1000);
- } catch (InterruptedException ex)
- {
- logger.error(ex);
- }
- }
-
- /* [old_status == OFFLINE ?] => register service */
- else if (status.equals(ZeroconfStatusEnum.OFFLINE))
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Getting out of OFFLINE state");
- props.put("status", stat.getStatusName());
- service = new ServiceInfo("_presence._tcp.local.", id,
- port, 0, 0, props);
-
- try
- {
- jmdns = new JmDNS();
- jmdns.registerServiceType("_presence._tcp.local.");
- jmdns.addServiceListener("_presence._tcp.local.", this);
- jmdns.registerService(service);
-
- /* In case the ID had to be changed */
- id = service.getName();
- }
- catch (Exception ex)
- { logger.error(ex); }
-
- //dead = false;
-
- /* Normal status change */
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF : Changing status");
-
- props.put("status", stat.getStatusName());
-
- /* FIXME: Not totally race condition free since the 3 calls aren't
- * atomic, but that's not really critical since there's little
- * change chance of concurrent local contact change, and this
- * wouldn't have big consequences.
- */
- ServiceInfo info =
- jmdns.getLocalService(id.toLowerCase()+"._presence._tcp.local.");
- if (info == null)
- logger.error("ZEROCONF/JMDNS: PROBLEM GETTING "
- +"LOCAL SERVICEINFO !!");
-
- byte[] old = info.getTextBytes();
- info.setProps(props);
- jmdns.updateInfos(info, old);
- }
-
- status = stat;
- }
-
- private class AddThread extends Thread
- {
- private String type, name;
- public AddThread(String type, String name)
- {
- this.setDaemon(true);
- this.type = type;
- this.name = name;
- this.start();
- }
-
- @Override
- public void run()
- {
- ServiceInfo service = null;
- while ((service == null) && (dead == false)
- && !status.equals(ZeroconfStatusEnum.OFFLINE))
- {
- service = jmdns.getServiceInfo(type, name, 10000);
- if (service == null)
- logger.error("BONJOUR: ERROR - Service Info of "
- + name +" not found in cache!!");
- try
- {
- sleep(2);
- }
- catch (InterruptedException ex)
- {
- logger.error(ex);
- }
- }
- if ((dead == false) && !status.equals(ZeroconfStatusEnum.OFFLINE))
- jmdns.requestServiceInfo(type, name);
- //} else handleResolvedService(name, type, service);
- }
- }
-
- /* Service Listener Implementation */
-
- /**
- * A service has been added.
- *
- * @param event The ServiceEvent providing the name and fully qualified type
- * of the service.
- */
- public void serviceAdded(ServiceEvent event)
- {
- /* WARNING: DONT PUT ANY BLOCKING CALLS OR FLAWED LOOPS IN THIS METHOD.
- * JmDNS calls this method without creating a new thread, so if this
- * method doesn't return, jmDNS will hang !!
- */
-
- String name = event.getName();
- String type = event.getType();
-
- if (name.equals(id))
- return;
-
- if (logger.isDebugEnabled())
- logger.debug("BONJOUR: "+name
- +"["+type+"] detected! Trying to get information...");
- try
- {
- sleep(2);
- }
- catch (InterruptedException ex)
- {
- logger.error(ex);
- }
-
- jmdns.printServices();
-
- new AddThread(type, name);
- }
-
-
-
- /**
- * A service has been removed.
- *
- * @param event The ServiceEvent providing the name and fully qualified type
- * of the service.
- */
- public void serviceRemoved(ServiceEvent event)
- {
- String name = event.getName();
- if (name.equals(id))
- return;
-
- ContactZeroconfImpl contact = getContact(name, null);
-
- if(contact == null)
- return;
-
- opSetPersPresence.changePresenceStatusForContact(contact,
- ZeroconfStatusEnum.OFFLINE);
- if (logger.isDebugEnabled())
- logger.debug("BONJOUR: Received announcement that "
- +name+" went offline!");
-
- }
-
- /**
- * A service has been resolved. Its details are now available in the
- * ServiceInfo record.
- *
- * @param event The ServiceEvent providing the name, the fully qualified
- * type of the service, and the service info record,
- * or null if the service could not be resolved.
- */
- public void serviceResolved(ServiceEvent event)
- {
- String contactID = event.getName();
- String type = event.getType();
- ServiceInfo info = event.getInfo();
-
- if (logger.isDebugEnabled())
- logger.debug("BONJOUR: Information about "
- +contactID+" discovered");
-
- handleResolvedService(contactID, type, info);
- }
-
- private void handleResolvedService(String contactID,
- String type,
- ServiceInfo info)
- {
- if (contactID.equals(id))
- return;
-
- if (info.getAddress().toString().length() > 15)
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Temporarily ignoring IPv6 addresses!");
- return;
- }
-
- ContactZeroconfImpl newFriend;
-
- synchronized(this)
- {
- if (getContact(contactID, info.getAddress()) != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Contact "
- +contactID+" already in contact list! Skipping.");
- return;
- };
- if (logger.isDebugEnabled())
- logger.debug("ZEROCNF: ContactID " + contactID +
- " Address " + info.getAddress());
-
- if (logger.isDebugEnabled())
- logger.debug(" Address=>"+info.getAddress()
- +":"+info.getPort());
-
- for (Iterator<String> names = info.getPropertyNames();
- names.hasNext();)
- {
- String prop = names.next();
- if (logger.isDebugEnabled())
- logger.debug(" "+prop+"=>"
- +info.getPropertyString(prop));
- }
-
- /* Creating the contact */
- String name = info.getPropertyString("1st");
- if (info.getPropertyString("last") != null)
- name += " "+ info.getPropertyString("last");
-
- int port = Integer.valueOf(
- info.getPropertyString("port.p2pj")).intValue();
-
- if (port < 1)
- {
- logger.error("ZEROCONF: Flawed contact announced himself"
- +"without necessary parameters : "+contactID);
- return;
- }
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Detected client "+name);
-
- newFriend =
- opSetPersPresence.createVolatileContact(
- contactID, this, name,
- info.getAddress(), port);
- }
- /* Try to detect which client type it is */
- int clientType = ContactZeroconfImpl.XMPP;
- if (info.getPropertyString("client") != null
- && info.getPropertyString("client").
- compareToIgnoreCase("SIP Communicator") == 0)
- clientType = ContactZeroconfImpl.SIPCOM;
-
- else if ((info.getPropertyString("jid") != null)
- && (info.getPropertyString("node") == null))
- clientType = ContactZeroconfImpl.GAIM;
-
- else if (info.getPropertyString("jid") == null)
- clientType = ContactZeroconfImpl.ICHAT;
-
- newFriend.setClientType(clientType);
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: CLIENT TYPE "+clientType);
-
- ZeroconfStatusEnum status =
- ZeroconfStatusEnum.statusOf(info.getPropertyString("status"));
- opSetPersPresence.
- changePresenceStatusForContact(newFriend,
- status == null?ZeroconfStatusEnum.ONLINE:status);
-
- // Listening for changes
- jmdns.addListener(this, new DNSQuestion(info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_UNIQUE));
- }
-
- /**
- * Callback called by JmDNS to inform the
- * BonjourService of a potential status change of some contacts.
- * @param jmdns JmDNS instance responsible for this
- * @param now Timestamp
- * @param record DNSRecord which changed
- */
- public synchronized void updateRecord( JmDNS jmdns,
- long now,
- DNSRecord record)
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF/JMDNS: Received record update for "+record);
-
- int clazz = record.getClazz();
- int type = record.getType();
-
- /* Check the info returned by JmDNS since we can't really trust its
- * filtering. */
- if (!(((type & DNSConstants.TYPE_TXT) != 0) &&
- ((clazz & DNSConstants.CLASS_IN) != 0) &&
- record.isUnique() &&
- record.getName().endsWith("_presence._tcp.local.")))
- return;
-
- String name = record.getName().replaceAll("._presence._tcp.local.","");
- ContactZeroconfImpl contact;
-
- synchronized(this)
- {
- contact = getContact(name, null);
-
- if (contact == null) { //return;
- logger.error("ZEROCONF: BUG in jmDNS => Received update without "
- +"previous contact annoucement. Trying to add contact");
- new AddThread("_presence._tcp.local.", name);
- return;
- }
- }
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: "+ name
- + " changed status. Requesting fresh data!");
-
- /* Since a record was updated, we can be sure that we can do a blocking
- * getServiceInfo without risk. (Still, we use the method with timeout
- * to avoid bad surprises). If some problems of status change refresh
- * appear, we'll have to fall back on the method with callback as we've
- * done for "ServiceAdded".
- */
-
- ServiceInfo info = jmdns.getServiceInfo("_presence._tcp.local.", name,
- 1000);
- if (info == null)
- {
- logger.error("ZEROCONF/JMDNS: Problem!! The service "
- +"information was not in cache. See comment in "
- +"BonjourService.java:updateRecord !!");
- return;
- }
-
- /* Let's change what we can : status, message, etc */
- ZeroconfStatusEnum status =
- ZeroconfStatusEnum.statusOf(info.getPropertyString("status"));
-
- opSetPersPresence.
- changePresenceStatusForContact(contact,
- status == null ? ZeroconfStatusEnum.ONLINE:status);
-
- }
-
- /**
- * Returns an Iterator over all contacts.
- *
- * @return a java.util.Iterator over all contacts
- */
- public Iterator<ContactZeroconfImpl> contacts()
- {
- return contacts.iterator();
- }
-
- /**
- * Adds a contact to the locally stored list of contacts
- * @param contact Zeroconf Contact to add to the local list
- */
- public void addContact(ContactZeroconfImpl contact)
- {
- if (contact == null)
- throw new IllegalArgumentException("contact");
-
- synchronized(contacts)
- {
- contacts.add(contact);
- }
- }
- /**
- * Returns the <tt>Contact</tt> with the specified identifier or IP address.
- *
- * @param id the identifier of the <tt>Contact</tt> we are
- * looking for.
- * @param ip the IP address of the <tt>Contact</tt> we are looking for.
- * @return the <tt>Contact</tt> with the specified id or address.
- */
- public ContactZeroconfImpl getContact(String id, InetAddress ip)
- {
- if (id == null && ip == null) return null;
-
- synchronized(contacts)
- {
- Iterator<ContactZeroconfImpl> contactsIter = contacts();
-
- while (contactsIter.hasNext())
- {
- ContactZeroconfImpl contact = contactsIter.next();
- //System.out.println("ZEROCNF: Comparing "+id+ " "+ip+
- //" with "+ contact.getAddress()+ " " + contact.getIpAddress());
- if (((contact.getAddress().equals(id)) || (id == null))
- && ((contact.getIpAddress().equals(ip)) || (ip == null)))
- return contact;
-
- }
- }
- //System.out.println("ZEROCNF: ERROR - " +
- //"Couldn't find contact to get ["+id+" / "+ip+"]");
- return null;
- }
-
- /**
- * Removes the <tt>Contact</tt> with the specified identifier or IP address.
- *
- *
- * @param id the identifier of the <tt>Contact</tt> we are
- * looking for.
- * @param ip the IP address of the <tt>Contact</tt> we are looking for.
- */
- public void removeContact(String id, InetAddress ip)
- {
- synchronized(contacts)
- {
- Iterator<ContactZeroconfImpl> contactsIter = contacts();
- while (contactsIter.hasNext())
- {
- ContactZeroconfImpl contact = contactsIter.next();
- if (((contact.getAddress().equals(id)) || (id == null))
- &&((contact.getIpAddress().equals(ip)) || (ip == null)))
- {
- if (contact.getClientThread() != null)
- contact.getClientThread().cleanThread();
- contacts.remove(contact);
- return;
- }
- };
- }
- logger.error(
- "ZEROCONF: ERROR - Couldn't find contact to delete ["+id+" / "+ip+"]");
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java
deleted file mode 100644
index 4367eed..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.io.*;
-import java.net.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Class creating a thread responsible for handling the chat
- * with the remote user on the other end of the socket
- *
- * @author Christian Vincenot
- */
-public class ClientThread
- extends Thread
-{
- private static final Logger logger = Logger.getLogger(ClientThread.class);
-
- private OperationSetBasicInstantMessagingZeroconfImpl opSetBasicIM;
- private OperationSetTypingNotificationsZeroconfImpl opSetTyping;
- private Socket sock;
- private InetAddress remoteIPAddress;
- private OutputStream out;
- private DataInputStream in;
- private BonjourService bonjourService;
- private ContactZeroconfImpl contact=null;
- private boolean streamState = false;
-
- private String messagesQueue=null;
-
- /**
- * Sets the contact with which we're chatting in this ClientThread
- * @param contact Zeroconf contact with which we're chatting
- */
- protected void setContact(ContactZeroconfImpl contact)
- {
- this.contact = contact;
- }
-
- /**
- * Set the stream as opened. This means that the
- * conversation with the client is really opened
- * from now on (the XML greetings are over)
- */
- protected void setStreamOpen()
- {
- synchronized(this)
- {
- this.streamState = true;
- }
- }
-
- /**
- * Says if the stream between the local user and the remote user
- * is in an opened state (greetings are over and we can chat)
- * @return Returns true if the stream is "opened" (ie, ready for chat)
- */
- protected boolean isStreamOpened()
- {
- synchronized(this)
- {
- return this.streamState;
- }
- }
-
- /**
- * Creates a new instance of ClientThread reponsible
- * for handling the conversation with the remote user.
- * @param sock Socket created for chatting
- * @param bonjourService BonjourService which spawned this ClientThread
- */
- public ClientThread(Socket sock, BonjourService bonjourService)
- {
- this.sock = sock;
- this.remoteIPAddress = sock.getInetAddress();
- this.bonjourService = bonjourService;
- this.opSetBasicIM =
- (OperationSetBasicInstantMessagingZeroconfImpl) bonjourService
- .getPPS().getOperationSet(
- OperationSetBasicInstantMessaging.class);
-
- this.opSetTyping =
- (OperationSetTypingNotificationsZeroconfImpl) bonjourService
- .getPPS()
- .getOperationSet(OperationSetTypingNotifications.class);
- this.setDaemon(true);
-
- try
- {
- out = sock.getOutputStream();
- in = new DataInputStream(sock.getInputStream());
- }
- catch (IOException e)
- {
- logger.error("Creating ClientThread: Couldn't get I/O for "
- +"the connection", e);
- //System.exit(1);
- return;
- }
-
- this.start();
- }
-
- /*
- * Read a message from the socket.
- * TODO: clean the code a bit and optimize it.
- */
- private String readMessage()
- {
- String line;
- byte[] bytes = new byte[10];
-
- try
- {
- int i=0;
-
- while (i < 9)
- {
- i += in.read(bytes,0,9-i);
- }
-
- line = new String(bytes);
- bytes = new byte[1];
- if ((line.getBytes())[0] == '\n')
- line = line.substring(1);
-
- if (line.startsWith("<message"))
- {
- while (true)
- {
- bytes[0] = in.readByte();
- line += new String(bytes);
-
- if ((line.endsWith("</message>"))
- || (line.endsWith("stream>")))
- return line;
- }
- }
- else
- {
- while (true)
- {
- bytes[0] = in.readByte();
- line += new String(bytes);
- if ( ">".compareTo(new String(bytes)) == 0 )
- return line;
- }
- }
- }
- catch (IOException e)
- {
- logger.error("Couldn't get I/O for the connection", e);
- //System.exit(1);
- }
-
- return null;
- }
-
- /*
- * Parse the payload and extract the information.
- * TODO: If needed, fill in the remaining fields of MessageZeroconfImpl
- * like the baloon icon color, color/size/font of the text.
- */
- private MessageZeroconfImpl parseMessage(String str)
- {
- if (str.startsWith("<?xml") || str.startsWith("<stream"))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.STREAM_OPEN);
-
- if (str.endsWith("stream>"))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.STREAM_CLOSE);
-
- if ((str.indexOf("<delivered/>") > 0) && (str.indexOf("<body>") < 0))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.DELIVERED);
-
- if (!str.startsWith("<message"))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.UNDEF);
-
- /* TODO: Parse Enconding (& contact id to be able to double-check
- * the source of a message)
- *
- * TODO: Check that the fields are outside of <body>..</body>
- */
-
- if ((str.indexOf("<body>") < 0) || (str.indexOf("</body>") < 0))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.UNDEF);
-
- String temp =
- str.substring(str.indexOf("<body>")+6, str.indexOf("</body>"));
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: received message ["+temp+"]");
-
- int messageType = MessageZeroconfImpl.MESSAGE;
-
- if ((str.indexOf("<id>") >= 0) && (str.indexOf("</id>") >= 0))
- messageType = MessageZeroconfImpl.TYPING;
-
- MessageZeroconfImpl msg =
- new MessageZeroconfImpl(
- temp,
- null,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE,
- messageType);
-
- return msg;
- }
-
- private int handleMessage(MessageZeroconfImpl msg)
- {
-
- switch(msg.getType())
- {
- /* STREAM INIT */
- case MessageZeroconfImpl.STREAM_OPEN:
- if (contact == null)
- contact = bonjourService.getContact(null, remoteIPAddress);
- if (!isStreamOpened())
- {
- sendHello();
- setStreamOpen();
- }
- if (messagesQueue != null)
- {
- write(messagesQueue);
- messagesQueue = null;
- }
- break;
-
- /* ACK */
- case MessageZeroconfImpl.DELIVERED : break;
-
- /* NORMAL MESSAGE */
- case MessageZeroconfImpl.MESSAGE:
- if (!isStreamOpened())
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: client on the other side "
- +"isn't polite (sending messages without "
- +"saying hello :P");
- if (contact == null)
- //TODO: Parse contact id to double-check
- contact = bonjourService.getContact(null, remoteIPAddress);
-
- /* TODO: If we want to implement invisible status, we'll have to
- * make this test less restrictive to handle messages from
- * unannounced clients.
- */
- if (contact == null)
- {
- logger.error("ZEROCONF: ERROR - Couldn't identify "
- +"contact. Closing socket.");
- return -1;
- }
- else if (contact.getClientThread() == null)
- contact.setClientThread(this);
-
- opSetBasicIM.fireMessageReceived(msg, contact);
-
- opSetTyping.fireTypingNotificationsEvent(contact,
- OperationSetTypingNotificationsZeroconfImpl.STATE_STOPPED);
- break;
-
- case MessageZeroconfImpl.TYPING:
- if (!isStreamOpened())
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: client on the other side "
- +"isn't polite (sending messages without "
- +"saying hello :P");
- if (contact == null)
- //TODO: Parse contact id to double-check
- contact = bonjourService.getContact(null, remoteIPAddress);
- opSetTyping.fireTypingNotificationsEvent(contact,
- OperationSetTypingNotificationsZeroconfImpl.STATE_TYPING);
-
- /* TODO: code a private runnable class to be used as timeout
- * to set the typing state to STATE_PAUSED when a few seconds
- * without news have passed.
- */
-
- break;
-
- case MessageZeroconfImpl.STREAM_CLOSE:
- sendBye();
- contact.setClientThread(null);
- return 1;
-
- case MessageZeroconfImpl.UNDEF:
- logger.error("ZEROCONF: received strange message. SKIPPING!");
- break;
- }
-
- //System.out.println("RECEIVED MESSAGE "+ msg.getContent()+
- //" from "+contact.getAddress() + "!!!!!!!!!!!!!!");
- return 0;
- }
-
-
- private void write(String string)
- {
- //System.out.println("Writing " + string + "!!!!!!!!!");
- byte[] bytes = string.getBytes();
- try
- {
- out.write(bytes);
- out.flush();
- }
- catch (IOException e)
- {
- logger.error("Couldn't get I/O for the connection");
- if (contact != null)
- {
- contact.setClientThread(null);
- }
-
- try
- {
- sock.close();
- }
- catch (IOException ex)
- {
- logger.error(ex);
- }
-
- }
- }
-
- /**
- * Say hello :)
- */
- protected void sendHello()
- {
- switch(contact.getClientType())
- {
- case ContactZeroconfImpl.GAIM:
- case ContactZeroconfImpl.ICHAT:
- case ContactZeroconfImpl.SIPCOM:
- write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
- write("<stream:stream xmlns=\"jabber:client\" "
- +"xmlns:stream=\"http://etherx.jabber.org/streams\">");
- break;
- case ContactZeroconfImpl.XMPP:
- write("<stream:stream"
- +"xmlns='jabber:client'"
- +"xmlns:stream='http://etherx.jabber.org/streams'"
- +"from='"+bonjourService.getID()+"'"
- +"to='"+contact.getAddress()+"'"
- +"version='1.0'>\n");
- break;
- }
-
- /* Legacy: OLD XMPP (XEP-0174 Draft) */
- //write("<stream:stream to='"+sock.getInetAddress().getHostAddress()
- //+"' xmlns='jabber:client' stream='http://etherx.jabber.org/streams'>");
- }
-
- private void sendBye()
- {
- write("</stream:stream>\n");
- }
-
- private String toXHTML(MessageZeroconfImpl msg)
- {
- switch(contact.getClientType())
- {
- case ContactZeroconfImpl.XMPP:
- return new String("<message to='"
- +contact.getAddress()+"' from='"
- +bonjourService.getID()+"'>"
- + "<body>"+msg.getContent()+"</body>"
- + "</message>\n");
-
- case ContactZeroconfImpl.SIPCOM:
-
- case ContactZeroconfImpl.ICHAT:
- return new String(
- "<message to='"+sock.getInetAddress().getHostAddress()
- +"' type='chat' id='"+bonjourService.getID()+"'>"
- + "<body>"+msg.getContent()+"</body>"
- + "<html xmlns='http://www.w3.org/1999/xhtml'>"
- + "<body ichatballooncolor='#7BB5EE' "
- + "ichattextcolor='#000000'>"
- + "<font face='Helvetica' ABSZ='12' color='#000000'>"
- + msg.getContent()
- + "</font>"
- + "</body>"
- + "</html>"
- + "<x xmlns='jabber:x:event'>"
- + "<offline/>"
- + "<delivered/>"
- + "<composing/>"
- + (msg.getType()==MessageZeroconfImpl.TYPING?"<id></id>":"")
- + "</x>"
- + "</message>");
-
- case ContactZeroconfImpl.GAIM:
- default:
- return new String(
- "<message to='"+contact.getAddress()
- +"' from='"+bonjourService.getID()
- + "' type='chat'><body>"+msg.getContent()+"</body>"
- + "<html xmlns='http://www.w3.org/1999/xhtml'><body><font>"
- + msg.getContent()
- + "</font></body></html><x xmlns='jabber:x:event'><composing/>"
- + (msg.getType()==MessageZeroconfImpl.TYPING?"<id></id>":"")
- + "</x></message>\n");
- }
- }
-
-
- /**
- * Send a message to the remote user
- * @param msg Message to send
- */
- public void sendMessage(MessageZeroconfImpl msg)
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Sending messag ["
- +msg.getContent()+"] to "
- + contact.getDisplayName());
- if (!isStreamOpened())
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Stream not opened... "
- +"will send the message later");
- messagesQueue += toXHTML(msg);
- }
- else write(toXHTML(msg));
- }
-
- /**
- * Walk?
- */
- @Override
- public void run()
- {
- if (logger.isDebugEnabled())
- logger.debug("Bonjour: NEW CONNEXION from "
- + sock.getInetAddress().getCanonicalHostName()
- +" / "+sock.getInetAddress().getHostAddress());
- String input;
- MessageZeroconfImpl msg=null;
-
-
- input = readMessage();
- msg = parseMessage(input);
-
- while (handleMessage(msg) == 0 && !sock.isClosed())
- {
- input = readMessage();
- msg = parseMessage(input);
- }
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF : OUT OF LOOP !! Closed chat.");
- cleanThread();
- }
-
- /**
- * Clean-up the thread to exit
- */
- public void cleanThread()
- {
- /* I wonder if that's ok... */
- if (sock != null && sock.isClosed() == false)
- {
- sendBye();
- try
- {
- sock.close();
- }
- catch (IOException ex)
- {
- logger.error(ex);
- }
- }
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactGroupZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactGroupZeroconfImpl.java
deleted file mode 100644
index 568e087..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactGroupZeroconfImpl.java
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * A simple, straightforward implementation of a zeroconf ContactGroup. Since
- * the Zeroconf protocol, we simply store all group details
- * in class fields. You should know that when implementing a real protocol,
- * the contact group implementation would rather encapsulate group objects from
- * the protocol stack and group property values should be returned by consulting
- * the encapsulated object.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- */
-public class ContactGroupZeroconfImpl
- implements ContactGroup
-{
-
- /**
- * The name of this Zeroconf contact group.
- */
- private String groupName = null;
-
- /**
- * The list of this group's members.
- */
- private Vector<Contact> contacts = new Vector<Contact>();
-
- /**
- * The list of sub groups belonging to this group.
- */
- private Vector<ContactGroup> subGroups = new Vector<ContactGroup>();
-
- /**
- * The group that this group belongs to (or null if this is the root group).
- */
- private ContactGroupZeroconfImpl parentGroup = null;
-
- /**
- * Determines whether this group is really in the contact list or whether
- * it is here only temporarily and will be gone next time we restart.
- */
- private boolean isPersistent = false;
-
- /**
- * The protocol provider that created us.
- */
- private ProtocolProviderServiceZeroconfImpl parentProvider = null;
-
- /**
- * Determines whether this group has been resolved on the server.
- * Unresolved groups are groups that were available on previous runs and
- * that the meta contact list has stored. During all next runs, when
- * bootstrapping, the meta contact list would create these groups as
- * unresolved. Once a protocol provider implementation confirms that the
- * groups are still on the server, it would issue an event indicating that
- * the groups are now resolved.
- */
- private boolean isResolved = true;
-
- /**
- * An id uniquely identifying the group. For many protocols this could be
- * the group name itself.
- */
- private String uid = null;
- private static final String UID_SUFFIX = ".uid";
-
- /**
- * Creates a ContactGroupZeroconfImpl with the specified name.
- *
- * @param groupName the name of the group.
- * @param parentProvider the protocol provider that created this group.
- */
- public ContactGroupZeroconfImpl(
- String groupName,
- ProtocolProviderServiceZeroconfImpl parentProvider)
- {
- this.groupName = groupName;
- this.uid = groupName + UID_SUFFIX;
- this.parentProvider = parentProvider;
- }
-
- /**
- * Determines whether the group may contain subgroups or not.
- *
- * @return always true in this implementation.
- */
- public boolean canContainSubgroups()
- {
- return true;
- }
-
- /**
- * Returns the protocol provider that this group belongs to.
- * @return a regerence to the ProtocolProviderService instance that this
- * ContactGroup belongs to.
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return parentProvider;
- }
-
- /**
- * Returns an Iterator over all contacts, member of this
- * <tt>ContactGroup</tt>.
- *
- * @return a java.util.Iterator over all contacts inside this
- * <tt>ContactGroup</tt>
- */
- public Iterator<Contact> contacts()
- {
- return contacts.iterator();
- }
-
- /**
- * Adds the specified contact to this group.
- * @param contactToAdd the ContactZeroconfImpl to add to this group.
- */
- public void addContact(ContactZeroconfImpl contactToAdd)
- {
- this.contacts.add(contactToAdd);
- contactToAdd.setParentGroup(this);
- }
-
- /**
- * Returns the number of <tt>Contact</tt> members of this
- * <tt>ContactGroup</tt>
- *
- * @return an int indicating the number of <tt>Contact</tt>s, members of
- * this <tt>ContactGroup</tt>.
- */
- public int countContacts()
- {
- return contacts.size();
- }
-
- /**
- * Returns the number of subgroups contained by this
- * <tt>ContactGroup</tt>.
- *
- * @return the number of subGroups currently added to this group.
- */
- public int countSubgroups()
- {
- return subGroups.size();
- }
-
- /**
- * Adds the specified contact group to the contained by this group.
- * @param subgroup the ContactGroupZeroconfImpl to add as a
- * subgroup to this group.
- */
- public void addSubgroup(ContactGroupZeroconfImpl subgroup)
- {
- this.subGroups.add(subgroup);
- subgroup.setParentGroup(this);
- }
-
- /**
- * Sets the group that is the new parent of this group
- * @param parent ContactGroupZeroconfImpl
- */
- void setParentGroup(ContactGroupZeroconfImpl parent)
- {
- this.parentGroup = parent;
- }
-
- /**
- * Returns the contact group that currently contains this group or null if
- * this is the root contact group.
- * @return the contact group that currently contains this group or null if
- * this is the root contact group.
- */
- public ContactGroup getParentContactGroup()
- {
- return this.parentGroup;
- }
-
- /**
- * Removes the specified contact group from the this group's subgroups.
- * @param subgroup the ContactGroupZeroconfImpl subgroup to remove.
- */
- public void removeSubGroup(ContactGroupZeroconfImpl subgroup)
- {
- this.subGroups.remove(subgroup);
- subgroup.setParentGroup(null);
- }
-
- /**
- * Returns the group that is parent of the specified zeroconfGroup or null
- * if no parent was found.
- * @param zeroconfGroup the group whose parent we're looking for.
- * @return the ContactGroupZeroconfImpl instance that zeroconfGroup
- * belongs to or null if no parent was found.
- */
- public ContactGroupZeroconfImpl findGroupParent(
- ContactGroupZeroconfImpl zeroconfGroup)
- {
- if ( subGroups.contains(zeroconfGroup) )
- return this;
-
- Iterator<ContactGroup> subGroupsIter = subgroups();
- while (subGroupsIter.hasNext())
- {
- ContactGroupZeroconfImpl subgroup
- = (ContactGroupZeroconfImpl) subGroupsIter.next();
-
- ContactGroupZeroconfImpl parent
- = subgroup.findGroupParent(zeroconfGroup);
-
- if(parent != null)
- return parent;
- }
- return null;
- }
-
- /**
- * Returns the group that is parent of the specified zeroconfContact or
- * null if no parent was found.
- *
- * @param zeroconfContact the contact whose parent we're looking for.
- * @return the ContactGroupZeroconfImpl instance that zeroconfContact
- * belongs to or <tt>null</tt> if no parent was found.
- */
- public ContactGroupZeroconfImpl findContactParent(
- ContactZeroconfImpl zeroconfContact)
- {
- if ( contacts.contains(zeroconfContact) )
- return this;
-
- Iterator<ContactGroup> subGroupsIter = subgroups();
- while (subGroupsIter.hasNext())
- {
- ContactGroupZeroconfImpl subgroup
- = (ContactGroupZeroconfImpl) subGroupsIter.next();
-
- ContactGroupZeroconfImpl parent
- = subgroup.findContactParent(zeroconfContact);
-
- if(parent != null)
- return parent;
- }
- return null;
- }
-
-
-
- /**
- * Returns the <tt>Contact</tt> with the specified address or identifier.
- *
- * @param id the addres or identifier of the <tt>Contact</tt> we are
- * looking for.
- * @return the <tt>Contact</tt> with the specified id or address.
- */
- public Contact getContact(String id)
- {
- Iterator<Contact> contactsIter = contacts();
- while (contactsIter.hasNext())
- {
- ContactZeroconfImpl contact =
- (ContactZeroconfImpl)contactsIter.next();
-
- if (contact.getAddress().equals(id))
- return contact;
-
- }
- return null;
- }
-
- /**
- * Returns the subgroup with the specified index.
- *
- * @param index the index of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(int index)
- {
- return subGroups.get(index);
- }
-
- /**
- * Returns the subgroup with the specified name.
- *
- * @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(String groupName)
- {
- Iterator<ContactGroup> groupsIter = subgroups();
- while (groupsIter.hasNext())
- {
- ContactGroupZeroconfImpl contactGroup
- = (ContactGroupZeroconfImpl) groupsIter.next();
- if (contactGroup.getGroupName().equals(groupName))
- return contactGroup;
-
- }
- return null;
-
- }
-
- /**
- * Returns the name of this group.
- *
- * @return a String containing the name of this group.
- */
- public String getGroupName()
- {
- return this.groupName;
- }
-
- /**
- * Sets this group a new name.
- * @param newGrpName a String containing the new name of this group.
- */
- public void setGroupName(String newGrpName)
- {
- this.groupName = newGrpName;
- }
-
- /**
- * Returns an iterator over the sub groups that this
- * <tt>ContactGroup</tt> contains.
- *
- * @return a java.util.Iterator over the <tt>ContactGroup</tt> children
- * of this group (i.e. subgroups).
- */
- public Iterator<ContactGroup> subgroups()
- {
- return subGroups.iterator();
- }
-
- /**
- * Removes the specified contact from this group.
- * @param contact the ContactZeroconfImpl to remove from this group
- */
- public void removeContact(ContactZeroconfImpl contact)
- {
- this.contacts.remove(contact);
- }
-
- /**
- * Returns the contact with the specified id or null if no such contact
- * exists.
- * @param id the id of the contact we're looking for.
- * @return ContactZeroconfImpl
- */
- public ContactZeroconfImpl findContactByID(String id)
- {
- //first go through the contacts that are direct children.
- Iterator<Contact> contactsIter = contacts();
-
- while(contactsIter.hasNext())
- {
- ContactZeroconfImpl mContact =
- (ContactZeroconfImpl)contactsIter.next();
-
- if( mContact.getAddress().equals(id) )
- return mContact;
- }
-
- //if we didn't find it here, let's try in the subougroups
- Iterator<ContactGroup> groupsIter = subgroups();
-
- while( groupsIter.hasNext() )
- {
- ContactGroupZeroconfImpl mGroup =
- (ContactGroupZeroconfImpl)groupsIter.next();
-
- ContactZeroconfImpl mContact = mGroup.findContactByID(id);
-
- if (mContact != null)
- return mContact;
- }
-
- return null;
- }
-
-
- /**
- * Returns a String representation of this group and the contacts it
- * contains (may turn out to be a relatively long string).
- * @return a String representing this group and its child contacts.
- */
- @Override
- public String toString()
- {
-
- StringBuffer buff = new StringBuffer(getGroupName());
- buff.append(".subGroups=" + countSubgroups() + ":\n");
-
- Iterator<ContactGroup> subGroups = subgroups();
- while (subGroups.hasNext())
- {
- ContactGroupZeroconfImpl group =
- (ContactGroupZeroconfImpl)subGroups.next();
- buff.append(group.toString());
- if (subGroups.hasNext())
- buff.append("\n");
- }
-
- buff.append("\nChildContacts="+countContacts()+":[");
-
- Iterator<Contact> contacts = contacts();
- while (contacts.hasNext())
- {
- ContactZeroconfImpl contact = (ContactZeroconfImpl) contacts.next();
- buff.append(contact.toString());
- if(contacts.hasNext())
- buff.append(", ");
- }
- return buff.append("]").toString();
- }
-
- /**
- * Specifies whether or not this contact group is being stored by the server.
- * Non persistent contact groups are common in the case of simple,
- * non-persistent presence operation sets. They could however also be seen
- * in persistent presence operation sets when for example we have received
- * an event from someone not on our contact list and the contact that we
- * associated with that user is placed in a non persistent group. Non
- * persistent contact groups are volatile even when coming from a persistent
- * presence op. set. They would only exist until the application is closed
- * and will not be there next time it is loaded.
- *
- * @param isPersistent true if the contact group is to be persistent and
- * false otherwise.
- */
- public void setPersistent(boolean isPersistent)
- {
- this.isPersistent = isPersistent;
- }
-
- /**
- * Determines whether or not this contact group is being stored by the
- * server. Non persistent contact groups exist for the sole purpose of
- * containing non persistent contacts.
- * @return true if the contact group is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Returns null as no persistent data is required and the contact address is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Makes the group resolved or unresolved.
- *
- * @param resolved true to make the group resolved; false to
- * make it unresolved
- */
- public void setResolved(boolean resolved)
- {
- this.isResolved = resolved;
- }
-
- /**
- * Returns a <tt>String</tt> that uniquely represnets the group inside
- * the current protocol. The string MUST be persistent (it must not change
- * across connections or runs of the application). In many cases (Jabber,
- * ICQ) the string may match the name of the group as these protocols
- * only allow a single level of contact groups and there is no danger of
- * having the same name twice in the same contact list. Other protocols
- * (no examples come to mind but that doesn't bother me ;) ) may be
- * supporting mutilple levels of grooups so it might be possible for group
- * A and group B to both contain groups named C. In such cases the
- * implementation must find a way to return a unique identifier in this
- * method and this UID should never change for a given group.
- *
- * @return a String representing this group in a unique and persistent
- * way.
- */
- public String getUID()
- {
- return uid;
- }
-
- /**
- * Ugly but tricky conversion method.
- * @param uid the uid we'd like to get a name from
- * @return the name of the group with the specified <tt>uid</tt>.
- */
- static String createNameFromUID(String uid)
- {
- return uid.substring(0, uid.length() - (UID_SUFFIX.length()));
- }
-
- /**
- * Indicates whether some other object is "equal to" this one which in terms
- * of contact groups translates to having the equal names and matching
- * subgroups and child contacts. The resolved status of contactgroups and
- * contacts is deliberately ignored so that groups and/or contacts would
- * be assumed equal even if it differs.
- * <p>
- * @param obj the reference object with which to compare.
- * @return <code>true</code> if this contact group has the equal child
- * contacts and subgroups to those of the <code>obj</code> argument.
- */
- @Override
- public boolean equals(Object obj)
- {
- if(obj == null
- || !(obj instanceof ContactGroupZeroconfImpl))
- return false;
-
- ContactGroupZeroconfImpl zeroconfGroup
- = (ContactGroupZeroconfImpl)obj;
-
- if(!zeroconfGroup.getGroupName().equals(getGroupName()) ||
- !zeroconfGroup.getUID().equals(getUID()) ||
- zeroconfGroup.countContacts() != countContacts() ||
- zeroconfGroup.countSubgroups() != countSubgroups())
- return false;
-
- //traverse child contacts
- Iterator<Contact> theirContacts = zeroconfGroup.contacts();
-
- while(theirContacts.hasNext())
- {
- ContactZeroconfImpl theirContact
- = (ContactZeroconfImpl)theirContacts.next();
-
- ContactZeroconfImpl ourContact
- = (ContactZeroconfImpl)getContact(theirContact.getAddress());
-
- if(ourContact == null
- || !ourContact.equals(theirContact))
- return false;
- }
-
- //traverse subgroups
- Iterator<ContactGroup> theirSubgroups = zeroconfGroup.subgroups();
-
- while(theirSubgroups.hasNext())
- {
- ContactGroupZeroconfImpl theirSubgroup
- = (ContactGroupZeroconfImpl)theirSubgroups.next();
-
- ContactGroupZeroconfImpl ourSubgroup
- = (ContactGroupZeroconfImpl)getGroup(
- theirSubgroup.getGroupName());
-
- if(ourSubgroup == null
- || !ourSubgroup.equals(theirSubgroup))
- return false;
- }
-
- return true;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactZeroconfImpl.java
deleted file mode 100644
index c22cf29..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactZeroconfImpl.java
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.net.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * A simple, straightforward implementation of a zeroconf Contact. Since
- * the Zeroconf protocol is not a real one, we simply store all contact details
- * in class fields. You should know that when implementing a real protocol,
- * the contact implementation would rather encapsulate contact objects from
- * the protocol stack and group property values should be returned after
- * consulting the encapsulated object.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- */
-public class ContactZeroconfImpl
- extends AbstractContact
-{
- private static final Logger logger
- = Logger.getLogger(ContactZeroconfImpl.class);
-
-
- /**
- * The id of the contact.
- */
- private String contactID = null;
-
- /**
- * The ClientThread attached to this contact if we're already chatting
- * with him.
- */
- private ClientThread thread = null;
-
- /*
- * Type of Client.
- */
- /**
- * Gaim/Pidgin client type
- */
- public static final int GAIM = 1;
- /**
- * iChat client type
- */
- public static final int ICHAT = 2;
- /**
- * XMPP - XEP-0174 client type
- */
- public static final int XMPP = 3;
- /**
- * Another SIP Communicator client
- */
- public static final int SIPCOM = 4;
- private int clientType = XMPP;
-
-
- /**
- * The provider that created us.
- */
- private ProtocolProviderServiceZeroconfImpl parentProvider = null;
-
-
- /*
- * The Bonjour Service who discovered this contact.
- * TODO: This could probably be avoided using only the
- * Protocol Provider.
- */
- private BonjourService bonjourService;
-
- /**
- * The group that belong to.
- */
- private ContactGroupZeroconfImpl parentGroup = null;
-
- /**
- * The presence status of the contact.
- */
- private PresenceStatus presenceStatus = ZeroconfStatusEnum.OFFLINE;
-
- /**
- * Determines whether this contact is persistent,
- * i.e. member of the contact list or whether it is here only temporarily.
- * Chris: should be set to false here
- */
- private boolean isPersistent = false;
-
- /**
- * Determines whether the contact has been resolved (i.e. we have a
- * confirmation that it is still on the server contact list).
- */
- private boolean isResolved = true;
-
- /**
- * IP Address
- */
- private InetAddress ipAddress;
-
- /**
- * Port on which Bonjour is listening.
- */
- private int port;
-
- /**
- * Name announced by Bonjour.
- */
- private String name;
-
- /**
- * Contact personal message
- */
- private String message;
-
-
- /**
- * Creates an instance of a meta contact with the specified string used
- * as a name and identifier.
- * @param bonjourId ID of the contact
- * @param bonjourService BonjourService responsible for handling chat with
- * this contact
- * @param name Display name of this contact
- * @param ipAddress IP address of this contact
- * @param port Port declared by this contact for direct point-to-point chat
- * @param parentProvider the provider that created us.
- */
- public ContactZeroconfImpl(
- String bonjourId,
- ProtocolProviderServiceZeroconfImpl parentProvider,
- BonjourService bonjourService,
- String name,
- InetAddress ipAddress,
- int port)
- {
- this.contactID = bonjourId;
- this.parentProvider = parentProvider;
- this.bonjourService = bonjourService;
- this.name = name;
- this.ipAddress = ipAddress;
- this.port = port;
- bonjourService.addContact(this);
- }
-
- /**
- * This method is only called when the contact is added to a new
- * <tt>ContactGroupZeroconfImpl</tt> by the
- * <tt>ContactGroupZeroconfImpl</tt> itself.
- *
- * @param newParentGroup the <tt>ContactGroupZeroconfImpl</tt> that is now
- * parent of this <tt>ContactZeroconfImpl</tt>
- */
- void setParentGroup(ContactGroupZeroconfImpl newParentGroup)
- {
- this.parentGroup = newParentGroup;
- }
-
- /**
- * Return the BonjourService
- * @return BonjourService
- */
- public BonjourService getBonjourService()
- {
- return bonjourService;
- }
-
- /**
- * Return the ClientThread responsible for handling with this contact
- * @return ClientThread corresponding to the chat with this contact or null
- * if no chat was started
- */
- protected ClientThread getClientThread()
- {
- return thread;
- }
-
- /**
- * Set the ClientThread responsible for handling with this contact
- * @param thread ClientThread corresponding to the chat with this contact
- * or null if the chat is over
- */
- protected void setClientThread(ClientThread thread)
- {
- this.thread = thread;
- }
-
- /**
- * Return the type of client
- * @return Type of client used by this contact
- */
- public int getClientType()
- {
- return clientType;
- }
-
- /**
- * Sets the type of client
- * @param clientType Type of client used by this contact
- */
- public void setClientType(int clientType)
- {
- this.clientType = clientType;
- }
-
- /**
- * Returns a String that can be used for identifying the contact.
- *
- * @return a String id representing and uniquely identifying the contact.
- */
- public String getAddress()
- {
- return contactID;
- }
-
- /**
- * Returns a String that could be used by any user interacting modules
- * for referring to this contact.
- *
- * @return a String that can be used for referring to this contact when
- * interacting with the user.
- */
- public String getDisplayName()
- {
- return name;
- }
-
- /**
- * Returns the IP address declared by this Contact
- * @return IP address declared by this Contact
- */
- public InetAddress getIpAddress()
- {
- return ipAddress;
- }
-
- /**
- * Returns the TCP port declared by this Contact for direct chat
- * @return the TCP port declared by this Contact for direct chat
- */
- public int getPort()
- {
- return port;
- }
-
-
- /**
- * Returns the status/private message displayed by this contact
- * @return the status/private message displayed by this contact
- */
- public String getMessage()
- {
- return message;
- }
-
- /**
- * Sets the status/private message displayed by this contact
- * @param message the status/private message displayed by this contact
- */
- public void setMessage(String message)
- {
- this.message = message;
- }
-
-
- /**
- * Returns a byte array containing an image (most often a photo or an
- * avatar) that the contact uses as a representation.
- *
- * @return byte[] an image representing the contact.
- */
- public byte[] getImage()
- {
- return null;
- }
-
- /**
- * Returns the status of the contact.
- *
- * @return always ZeroconfStatusEnum.
- */
- public PresenceStatus getPresenceStatus()
- {
- return this.presenceStatus;
- }
-
- /**
- * Sets <tt>zeroconfPresenceStatus</tt> as the PresenceStatus that this
- * contact is currently in.
- * @param zeroconfPresenceStatus the <tt>ZeroconfPresenceStatus</tt>
- * currently valid for this contact.
- */
- public void setPresenceStatus(PresenceStatus zeroconfPresenceStatus)
- {
- this.presenceStatus = zeroconfPresenceStatus;
-
- if (zeroconfPresenceStatus == ZeroconfStatusEnum.OFFLINE) {
- try
- {
- bonjourService.opSetPersPresence.unsubscribe(this);
- }
- catch (Exception ex)
- {
- logger.error(ex);
- }
- }
- }
-
- /**
- * Returns a reference to the protocol provider that created the contact.
- *
- * @return a refererence to an instance of the ProtocolProviderService
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return parentProvider;
- }
-
- /**
- * Determines whether or not this contact represents our own identity.
- *
- * @return true in case this is a contact that represents ourselves and
- * false otherwise.
- */
- public boolean isLocal()
- {
- return false;
- }
-
- /**
- * Returns the group that contains this contact.
- * @return a reference to the <tt>ContactGroupZeroconfImpl</tt> that
- * contains this contact.
- */
- public ContactGroup getParentContactGroup()
- {
- return this.parentGroup;
- }
-
- /**
- * Returns a string representation of this contact, containing most of its
- * representative details.
- *
- * @return a string representation of this contact.
- */
- @Override
- public String toString()
- {
- StringBuffer buff
- = new StringBuffer("ContactZeroconfImpl[ DisplayName=")
- .append(getDisplayName()).append("]");
-
- return buff.toString();
- }
-
- /**
- * Determines whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @return true if the contact is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Specifies whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @param isPersistent true if the contact is persistent and false
- * otherwise.
- */
- public void setPersistent(boolean isPersistent)
- {
- this.isPersistent = isPersistent;
- }
-
-
- /**
- * Returns null as no persistent data is required and the contact address is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- *
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Makes the contact resolved or unresolved.
- *
- * @param resolved true to make the contact resolved; false to
- * make it unresolved
- */
- public void setResolved(boolean resolved)
- {
- this.isResolved = resolved;
- }
-
- /**
- * Returns the persistent presence operation set that this contact belongs
- * to.
- *
- * @return the <tt>OperationSetPersistentPresenceZeroconfImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetPersistentPresenceZeroconfImpl
- getParentPresenceOperationSet()
- {
- return (OperationSetPersistentPresenceZeroconfImpl)parentProvider
- .getOperationSet(OperationSetPersistentPresence.class);
- }
-
- /**
- * Return the current status message of this contact.
- *
- * @return null as the protocol has currently no support of status messages
- */
- public String getStatusMessage()
- {
- return null;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/MessageZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/MessageZeroconfImpl.java
deleted file mode 100644
index 3621edc..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/MessageZeroconfImpl.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Very simple message implementation for the Zeroconf protocol.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- * @author Lubomir Marinov
- */
-public class MessageZeroconfImpl
- extends AbstractMessage
-{
-
- /**
- * Message Type.
- */
- private int type;
-
- /**
- * Message type indicating that a stream is being created
- */
- public static final int STREAM_OPEN = 0x1;
-
- /**
- * Normal chat message
- */
- public static final int MESSAGE = 0x2;
-
- /**
- * Typing notification
- */
- public static final int TYPING = 0x3;
-
- /**
- * Message indicating that the stream is being closed
- */
- public static final int STREAM_CLOSE = 0x4;
-
- /**
- * Message indicating that the previsous message was delivered successfully
- */
- public static final int DELIVERED = 0x5;
-
- /**
- * Undefined message
- */
- public static final int UNDEF = 0x6;
-
- /*
- * The Baloon Icon color. (we probably won't ever use it)
- */
- private int baloonColor = 0x7BB5EE;
-
- /*
- * The Text Color.
- */
- private int textColor = 0x000000;
-
- /*
- * The font of the message.
- */
- private String textFont = "Helvetica";
-
- /*
- * The size of the caracters composing the message.
- */
- private int textSize = 12;
-
- /*
- * The source contact id announced in the message. TODO: Could be set &
- * checked to identify more precisely the contact in case several users
- * would be sharing the same IP.
- */
- private String contactID;
-
- /**
- * Creates a message instance according to the specified parameters.
- *
- * @param content the message body
- * @param contentEncoding message encoding or null for UTF8
- * @param contentType of the message
- * @param type Type of message
- */
- public MessageZeroconfImpl(String content, String contentEncoding,
- String contentType, int type)
- {
- super(content, contentType, contentEncoding, null);
-
- this.type = type;
- }
-
- /**
- * Creates a message instance according to the specified parameters.
- *
- * @param type Type of message
- * @param content the message body
- * @param contentEncoding message encoding or null for UTF8
- */
- public MessageZeroconfImpl(String content, String contentEncoding, int type)
- {
- this(content, contentEncoding,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE, type);
- }
-
- /**
- * Returns the type of message. Always text/plain for Zeroconf, so null.
- *
- * @return null
- */
- public int getType()
- {
- return type;
- }
-
- /**
- * Gets the baloon color declared in messages sent by iChat-like clients
- *
- * @return baloon color
- */
- public int getBaloonColor()
- {
- return baloonColor;
- }
-
- /**
- * Sets the baloon color declared in messages sent by iChat-like clients
- *
- * @param baloonColor baloon color
- */
- public void setBaloonColor(int baloonColor)
- {
- this.baloonColor = baloonColor;
- }
-
- /**
- * Returns the text color
- *
- * @return Text color
- */
- public int getTextColor()
- {
- return textColor;
- }
-
- /**
- * Sets the text color
- *
- * @param textColor Text color
- */
- public void setTextColor(int textColor)
- {
- this.textColor = textColor;
- }
-
- /**
- * Returns the text font
- *
- * @return Text font
- */
- public String getTextFont()
- {
- return textFont;
- }
-
- /**
- * Sets the text color
- *
- * @param textFont Text font
- */
- public void setTextFont(String textFont)
- {
- this.textFont = textFont;
- }
-
- /**
- * Returns the text size
- *
- * @return Text size
- */
- public int getTextSize()
- {
- return textSize;
- }
-
- /**
- * Sets the text size
- *
- * @param textSize Text size
- */
- public void setTextSize(int textSize)
- {
- this.textSize = textSize;
- }
-
- /**
- * Returns the contact's ID
- *
- * @return String representing the contact's ID
- */
- public String getContactID()
- {
- return contactID;
- }
-
- /**
- * Sets the contact's ID
- *
- * @param contactID String representing the contact's ID
- */
- public void setContactID(String contactID)
- {
- this.contactID = contactID;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetBasicInstantMessagingZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetBasicInstantMessagingZeroconfImpl.java
deleted file mode 100644
index d49118b..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetBasicInstantMessagingZeroconfImpl.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.io.*;
-import java.net.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Instant messaging functionalities for the Zeroconf protocol.
- *
- * @author Christian Vincenot
- *
- */
-public class OperationSetBasicInstantMessagingZeroconfImpl
- extends AbstractOperationSetBasicInstantMessaging
-{
- private static final Logger logger
- = Logger.getLogger(OperationSetBasicInstantMessagingZeroconfImpl.class);
-
- /**
- * The currently valid persistent presence operation set..
- */
- private final OperationSetPersistentPresenceZeroconfImpl opSetPersPresence;
-
- /**
- * The protocol provider that created us.
- */
- private final ProtocolProviderServiceZeroconfImpl parentProvider;
-
- /**
- * Creates an instance of this operation set keeping a reference to the
- * parent protocol provider and presence operation set.
- *
- * @param provider The provider instance that creates us.
- * @param opSetPersPresence the currently valid
- * <tt>OperationSetPersistentPresenceZeroconfImpl</tt> instance.
- */
- public OperationSetBasicInstantMessagingZeroconfImpl(
- ProtocolProviderServiceZeroconfImpl provider,
- OperationSetPersistentPresenceZeroconfImpl opSetPersPresence)
- {
- this.opSetPersPresence = opSetPersPresence;
- this.parentProvider = provider;
- }
-
- @Override
- public Message createMessage(String content, String contentType,
- String encoding, String subject)
- {
- return new MessageZeroconfImpl(content, encoding, contentType,
- MessageZeroconfImpl.MESSAGE);
- }
-
- /**
- * Sends the <tt>message</tt> to the destination indicated by the
- * <tt>to</tt> contact.
- *
- * @param to the <tt>Contact</tt> to send <tt>message</tt> to
- * @param message the <tt>Message</tt> to send.
- * @throws IllegalStateException if the underlying Zeroconf stack is not
- * registered and initialized.
- * @throws IllegalArgumentException if <tt>to</tt> is not an instance
- * belonging to the underlying implementation.
- */
- public void sendInstantMessage(Contact to, Message message) throws
- IllegalStateException, IllegalArgumentException
- {
- if( !(to instanceof ContactZeroconfImpl) )
- throw new IllegalArgumentException(
- "The specified contact is not a Zeroconf contact."
- + to);
-
- MessageZeroconfImpl msg =
- (MessageZeroconfImpl)createMessage(message.getContent());
-
- deliverMessage(msg, (ContactZeroconfImpl)to);
- }
-
- /**
- * In case the to the <tt>to</tt> Contact corresponds to another zeroconf
- * protocol provider registered with SIP Communicator, we deliver
- * the message to them, in case the <tt>to</tt> Contact represents us, we
- * fire a <tt>MessageReceivedEvent</tt>, and if <tt>to</tt> is simply
- * a contact in our contact list, then we simply echo the message.
- *
- * @param message the <tt>Message</tt> the message to deliver.
- * @param to the <tt>Contact</tt> that we should deliver the message to.
- */
- private void deliverMessage(Message message, ContactZeroconfImpl to)
- {
- ClientThread thread = to.getClientThread();
- try
- {
- if (thread == null)
- {
- Socket sock;
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Creating a chat connexion to "
- +to.getIpAddress()+":"+to.getPort());
- sock = new Socket(to.getIpAddress(), to.getPort());
- thread = new ClientThread(sock, to.getBonjourService());
- thread.setStreamOpen();
- thread.setContact(to);
- to.setClientThread(thread);
- thread.sendHello();
- if (to.getClientType() == ContactZeroconfImpl.GAIM)
- {
- try
- {
- Thread.sleep(300);
- }
- catch (InterruptedException ex)
- {
- logger.error(ex);
- }
- }
- }
-
- //System.out.println("ZEROCONF: Message content => "+
- //message.getContent());
- thread.sendMessage((MessageZeroconfImpl) message);
-
- fireMessageDelivered(message, to);
- }
- catch (IOException ex)
- {
- logger.error(ex);
- }
- }
-
- /**
- * Notifies all registered message listeners that a message has been
- * received.
- *
- * @param message the <tt>Message</tt> that has been received.
- * @param from the <tt>Contact</tt> that <tt>message</tt> was received from.
- */
- @Override
- public void fireMessageReceived(Message message, Contact from)
- {
- super.fireMessageReceived(message, from);
- }
-
- /**
- * Determines whether the protocol provider (or the protocol itself) support
- * sending and receiving offline messages. Most often this method would
- * return true for protocols that support offline messages and false for
- * those that don't. It is however possible for a protocol to support these
- * messages and yet have a particular account that does not (i.e. feature
- * not enabled on the protocol server). In cases like this it is possible
- * for this method to return true even when offline messaging is not
- * supported, and then have the sendMessage method throw an
- * OperationFailedException with code - OFFLINE_MESSAGES_NOT_SUPPORTED.
- *
- * @return <tt>true</tt> if the protocol supports offline messages and
- * <tt>false</tt> otherwise.
- */
- public boolean isOfflineMessagingSupported()
- {
- return true;
- }
-
- /**
- * Determines whether the protocol supports the supplied content type
- *
- * @param contentType the type we want to check
- * @return <tt>true</tt> if the protocol supports it and
- * <tt>false</tt> otherwise.
- */
- public boolean isContentTypeSupported(String contentType)
- {
- return contentType.equals(DEFAULT_MIME_TYPE);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetPersistentPresenceZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetPersistentPresenceZeroconfImpl.java
deleted file mode 100644
index 412512e..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetPersistentPresenceZeroconfImpl.java
+++ /dev/null
@@ -1,852 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-import org.osgi.framework.*;
-
-/**
- * A Zeroconf implementation of a persistent presence operation set. In order
- * to simulate server persistence, this operation set would simply accept all
- * unresolved contacts and resolve them immediately. A real world protocol
- * implementation would save it on a server using methods provided by the
- * protocol stack.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- */
-public class OperationSetPersistentPresenceZeroconfImpl
- extends AbstractOperationSetPersistentPresence<ProtocolProviderServiceZeroconfImpl>
-{
- private static final Logger logger =
- Logger.getLogger(OperationSetPersistentPresenceZeroconfImpl.class);
-
- /**
- * The root of the zeroconf contact list.
- */
- private ContactGroupZeroconfImpl contactListRoot = null;
-
- /**
- * The currently active status message.
- */
- private String statusMessage = "The truth is out there...";
-
- /**
- * Our default presence status.
- */
- private PresenceStatus presenceStatus = ZeroconfStatusEnum.OFFLINE;
-
- /**
- * The <tt>AuthorizationHandler</tt> instance that we'd have to transmit
- * authorization requests to for approval.
- */
- private AuthorizationHandler authorizationHandler = null;
-
- /**
- * Creates an instance of this operation set keeping a reference to the
- * specified parent <tt>provider</tt>.
- * @param provider the ProtocolProviderServiceZeroconfImpl instance that
- * created us.
- */
- public OperationSetPersistentPresenceZeroconfImpl(
- ProtocolProviderServiceZeroconfImpl provider)
- {
- super(provider);
-
- contactListRoot = new ContactGroupZeroconfImpl("RootGroup", provider);
-
- //add our unregistration listener
- parentProvider.addRegistrationStateChangeListener(
- new UnregistrationListener());
- }
-
- /**
- * Creates a group with the specified name and parent in the server
- * stored contact list.
- *
- * @param parent the group where the new group should be created
- * @param groupName the name of the new group to create.
- */
- public void createServerStoredContactGroup(ContactGroup parent,
- String groupName)
- {
- ContactGroupZeroconfImpl newGroup
- = new ContactGroupZeroconfImpl(groupName, parentProvider);
-
- ((ContactGroupZeroconfImpl)parent).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
- /**
- * A Zeroconf Provider method to use for fast filling of a contact list.
- *
- * @param contactGroup the group to add
- */
- public void addZeroconfGroup(ContactGroupZeroconfImpl contactGroup)
- {
- contactListRoot.addSubgroup(contactGroup);
- }
-
- /**
- * A Zeroconf Provider method to use for fast filling of a contact list.
- * This method would add both the group and fire an event.
- *
- * @param parent the group where <tt>contactGroup</tt> should be added.
- * @param contactGroup the group to add
- */
- public void addZeroconfGroupAndFireEvent(
- ContactGroupZeroconfImpl parent
- , ContactGroupZeroconfImpl contactGroup)
- {
- parent.addSubgroup(contactGroup);
-
- this.fireServerStoredGroupEvent(
- contactGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
-
- /**
- * Returns a reference to the contact with the specified ID in case we
- * have a subscription for it and null otherwise/
- *
- * @param contactID a String identifier of the contact which we're
- * seeking a reference of.
- * @return a reference to the Contact with the specified
- * <tt>contactID</tt> or null if we don't have a subscription for the
- * that identifier.
- */
- public Contact findContactByID(String contactID)
- {
- return contactListRoot.findContactByID(contactID);
- }
-
- /**
- * Sets the specified status message.
- * @param statusMessage a String containing the new status message.
- */
- public void setStatusMessage(String statusMessage)
- {
- this.statusMessage = statusMessage;
- }
-
- /**
- * Returns the status message that was last set through
- * setCurrentStatusMessage.
- *
- * @return the last status message that we have requested and the aim
- * server has confirmed.
- */
- public String getCurrentStatusMessage()
- {
- return statusMessage;
- }
-
- /**
- * Returns a PresenceStatus instance representing the state this provider
- * is currently in.
- *
- * @return the PresenceStatus last published by this provider.
- */
- public PresenceStatus getPresenceStatus()
- {
- return presenceStatus;
- }
-
- /**
- * Returns the root group of the server stored contact list.
- *
- * @return the root ContactGroup for the ContactList stored by this
- * service.
- */
- public ContactGroup getServerStoredContactListRoot()
- {
- return contactListRoot;
- }
-
- /**
- * Returns the set of PresenceStatus objects that a user of this service
- * may request the provider to enter.
- *
- * @return Iterator a PresenceStatus array containing "enterable" status
- * instances.
- */
- public Iterator<PresenceStatus> getSupportedStatusSet()
- {
- return ZeroconfStatusEnum.supportedStatusSet();
- }
-
- /**
- * Removes the specified contact from its current parent and places it
- * under <tt>newParent</tt>.
- *
- * @param contactToMove the <tt>Contact</tt> to move
- * @param newParent the <tt>ContactGroup</tt> where <tt>Contact</tt>
- * would be placed.
- */
- public void moveContactToGroup(Contact contactToMove,
- ContactGroup newParent)
- {
- ContactZeroconfImpl zeroconfContact
- = (ContactZeroconfImpl)contactToMove;
-
- ContactGroupZeroconfImpl parentZeroconfGroup
- = findContactParent(zeroconfContact);
-
- parentZeroconfGroup.removeContact(zeroconfContact);
-
- //if this is a volatile contact then we haven't really subscribed to
- //them so we'd need to do so here
- if(!zeroconfContact.isPersistent())
- {
- //first tell everyone that the volatile contact was removed
- fireSubscriptionEvent(zeroconfContact
- , parentZeroconfGroup
- , SubscriptionEvent.SUBSCRIPTION_REMOVED);
-
- try
- {
- //now subscribe
- this.subscribe(newParent, contactToMove.getAddress());
-
- //now tell everyone that we've added the contact
- fireSubscriptionEvent(zeroconfContact
- , newParent
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
- }
- catch (Exception ex)
- {
- logger.error("Failed to move contact "
- + zeroconfContact.getAddress()
- , ex);
- }
- }
- else
- {
- ( (ContactGroupZeroconfImpl) newParent)
- .addContact(zeroconfContact);
-
- fireSubscriptionMovedEvent(contactToMove
- , parentZeroconfGroup
- , newParent);
- }
- }
-
- /**
- * Requests the provider to enter into a status corresponding to the
- * specified paramters.
- *
- * @param status the PresenceStatus as returned by
- * getRequestableStatusSet
- * @param statusMessage the message that should be set as the reason to
- * enter that status
- * @throws IllegalArgumentException if the status requested is not a
- * valid PresenceStatus supported by this provider.
- * @throws IllegalStateException if the provider is not currently
- * registered.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * publishing the status fails due to a network error.
- */
- public void publishPresenceStatus(PresenceStatus status,
- String statusMessage)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- PresenceStatus oldPresenceStatus = this.presenceStatus;
- this.presenceStatus = status;
- this.statusMessage = statusMessage;
-
- //ICI: changer le statut du plugin Zeroconf!!
- parentProvider.getBonjourService().changeStatus(status);
-
- this.fireProviderStatusChangeEvent(oldPresenceStatus);
-
- }
-
- /**
- * Get the PresenceStatus for a particular contact.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * we're interested in.
- * @return PresenceStatus the <tt>PresenceStatus</tt> of the specified
- * <tt>contact</tt>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * retrieving the status fails due to errors experienced during
- * network communication
- */
- public PresenceStatus queryContactStatus(String contactIdentifier)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- return findContactByID(contactIdentifier).getPresenceStatus();
- }
-
- /**
- * Sets the presence status of <tt>contact</tt> to <tt>newStatus</tt>.
- *
- * @param contact the <tt>ContactZeroconfImpl</tt> whose status we'd like
- * to set.
- * @param newStatus the new status we'd like to set to <tt>contact</tt>.
- */
- public void changePresenceStatusForContact(ContactZeroconfImpl contact,
- PresenceStatus newStatus)
- {
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(newStatus);
-
- fireContactPresenceStatusChangeEvent(
- contact, findContactParent(contact), oldStatus);
- }
-
- /**
- * Sets the presence status of all <tt>contact</tt>s in our contact list
- * (except those that correspond to another provider registered with SC)
- * to <tt>newStatus</tt>.
- *
- * @param newStatus the new status we'd like to set to <tt>contact</tt>.
- * @param parent the group in which we'd have to update the status of all
- * direct and indirect child contacts.
- */
- protected void changePresenceStatusForAllContacts(ContactGroup parent,
- PresenceStatus newStatus)
- {
- //first set the status for contacts in this group
- Iterator<Contact> childContacts = parent.contacts();
-
- while(childContacts.hasNext())
- {
- ContactZeroconfImpl contact
- = (ContactZeroconfImpl)childContacts.next();
-
- if(findProviderForZeroconfUserID(contact.getAddress()) != null)
- {
- //this is a contact corresponding to another SIP Communicator
- //provider so we won't change it's status here.
- continue;
- }
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(newStatus);
-
- fireContactPresenceStatusChangeEvent(
- contact, parent, oldStatus);
- }
-
- //now call this method recursively for all subgroups
- Iterator<ContactGroup> subgroups = parent.subgroups();
-
- while(subgroups.hasNext())
- {
- ContactGroup subgroup = subgroups.next();
- changePresenceStatusForAllContacts(subgroup, newStatus);
- }
- }
-
- /**
- * Returns the group that is parent of the specified zeroconfGroup or null
- * if no parent was found.
- * @param zeroconfGroup the group whose parent we're looking for.
- * @return the ContactGroupZeroconfImpl instance that zeroconfGroup
- * belongs to or null if no parent was found.
- */
- public ContactGroupZeroconfImpl findGroupParent(
- ContactGroupZeroconfImpl zeroconfGroup)
- {
- return contactListRoot.findGroupParent(zeroconfGroup);
- }
-
- /**
- * Returns the group that is parent of the specified zeroconfContact or
- * null if no parent was found.
- * @param zeroconfContact the contact whose parent we're looking for.
- * @return the ContactGroupZeroconfImpl instance that zeroconfContact
- * belongs to or null if no parent was found.
- */
- public ContactGroupZeroconfImpl findContactParent(
- ContactZeroconfImpl zeroconfContact)
- {
- return (ContactGroupZeroconfImpl)zeroconfContact
- .getParentContactGroup();
- }
-
-
- /**
- * Removes the specified group from the server stored contact list.
- *
- * @param group the group to remove.
- *
- * @throws IllegalArgumentException if <tt>group</tt> was not found in this
- * protocol's contact list.
- */
- public void removeServerStoredContactGroup(ContactGroup group)
- throws IllegalArgumentException
- {
- ContactGroupZeroconfImpl zeroconfGroup
- = (ContactGroupZeroconfImpl)group;
-
- ContactGroupZeroconfImpl parent = findGroupParent(zeroconfGroup);
-
- if(parent == null){
- throw new IllegalArgumentException(
- "group " + group
- + " does not seem to belong to this protocol's contact list.");
- }
-
- parent.removeSubGroup(zeroconfGroup);
-
- this.fireServerStoredGroupEvent(
- zeroconfGroup, ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
- }
-
- /**
- * Renames the specified group from the server stored contact list.
- *
- * @param group the group to rename.
- * @param newName the new name of the group.
- */
- public void renameServerStoredContactGroup(ContactGroup group,
- String newName)
- {
- ((ContactGroupZeroconfImpl)group).setGroupName(newName);
-
- this.fireServerStoredGroupEvent(
- group,
- ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
- }
-
- /**
- * Handler for incoming authorization requests.
- *
- * @param handler an instance of an AuthorizationHandler for
- * authorization requests coming from other users requesting
- * permission add us to their contact list.
- */
- public void setAuthorizationHandler(AuthorizationHandler handler)
- {
- this.authorizationHandler = handler;
- }
-
- /**
- * Persistently adds a subscription for the presence status of the
- * contact corresponding to the specified contactIdentifier and indicates
- * that it should be added to the specified group of the server stored
- * contact list.
- *
- * @param parent the parent group of the server stored contact list
- * where the contact should be added. <p>
- * @param contactIdentifier the contact whose status updates we are
- * subscribing for.
- * @throws IllegalArgumentException if <tt>contact</tt> or
- * <tt>parent</tt> are not a contact known to the underlying protocol
- * provider.
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(ContactGroup parent, String contactIdentifier)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- /* ContactZeroconfImpl contact = new ContactZeroconfImpl(
- contactIdentifier,
- parentProvider,
- null, null, null, 0);
-
- ((ContactGroupZeroconfImpl)parent).addContact(contact);
-
- fireSubscriptionEvent(contact,
- parent,
- SubscriptionEvent.SUBSCRIPTION_CREATED);
- //if the newly added contact corresponds to another provider - set their
- //status accordingly
- ProtocolProviderServiceZeroconfImpl gibProvider
- = findProviderForZeroconfUserID(contactIdentifier);
- if(gibProvider != null)
- {
- OperationSetPersistentPresence opSetPresence
- = (OperationSetPersistentPresence)gibProvider.getOperationSet(
- OperationSetPersistentPresence.class);
-
- changePresenceStatusForContact(
- contact
- , (ZeroconfStatusEnum)opSetPresence.getPresenceStatus());
- }
- else
- {
- //otherwise - since we are not a real protocol, we set the contact
- //presence status ourselves
- changePresenceStatusForContact(contact, getPresenceStatus());
- }
-
- //notify presence listeners for the status change.
- fireContactPresenceStatusChangeEvent(contact
- , parent
- , ZeroconfStatusEnum.OFFLINE);
- */}
-
-
-
- /**
- * Adds a subscription for the presence status of the contact
- * corresponding to the specified contactIdentifier.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * updates we are subscribing for. <p>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(String contactIdentifier)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- subscribe(contactListRoot, contactIdentifier);
- }
-
- /**
- * Removes a subscription for the presence status of the specified
- * contact.
- *
- * @param contact the contact whose status updates we are unsubscribing
- * from.
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * unsubscribing fails due to errors experienced during network
- * communication
- */
- public void unsubscribe(Contact contact)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- String name = contact.getAddress();
-
- ContactGroupZeroconfImpl parentGroup
- = (ContactGroupZeroconfImpl)((ContactZeroconfImpl)contact)
- .getParentContactGroup();
-
- //parentGroup.removeContact((ContactZeroconfImpl)contact);
-
- BonjourService service =
- ((ProtocolProviderServiceZeroconfImpl)contact.getProtocolProvider())
- .getBonjourService();
- //TODO: better check with IP
- service.removeContact(name,null);
-
- fireSubscriptionEvent(contact,
- ((ContactZeroconfImpl)contact).getParentContactGroup()
- , SubscriptionEvent.SUBSCRIPTION_REMOVED);
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created Contact
- * against the server. The protocol provider may will later try and resolve
- * the contact. When this happens the corresponding event would notify
- * interested subscription listeners.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(String address,
- String persistentData)
- {
- return createUnresolvedContact(address
- , persistentData
- , getServerStoredContactListRoot());
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created Contact
- * against the server. The protocol provider may will later try and resolve
- * the contact. When this happens the corresponding event would notify
- * interested subscription listeners.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @param parent the group where the unresolved contact is
- * supposed to belong to.
- *
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(String address,
- String persistentData,
- ContactGroup parent)
- {
- return null;
- }
-
- /**
- * Looks for a zeroconf protocol provider registered for a user id matching
- * <tt>zeroconfUserID</tt>.
- *
- * @param zeroconfUserID the ID of the Zeroconf user whose corresponding
- * protocol provider we'd like to find.
- * @return ProtocolProviderServiceZeroconfImpl a zeroconf protocol
- * provider registered for a user with id <tt>zeroconfUserID</tt> or null
- * if there is no such protocol provider.
- */
- public ProtocolProviderServiceZeroconfImpl
- findProviderForZeroconfUserID(String zeroconfUserID)
- {
- BundleContext bc = ZeroconfActivator.getBundleContext();
-
- String osgiQuery = "(&" +
- "(" + ProtocolProviderFactory.PROTOCOL +
- "=" + ProtocolNames.ZEROCONF + ")" +
- "(" + ProtocolProviderFactory.USER_ID +
- "=" + zeroconfUserID + "))";
-
- ServiceReference[] refs = null;
- try
- {
- refs = bc.getServiceReferences(
- ProtocolProviderService.class.getName(),
- osgiQuery);
- }
- catch (InvalidSyntaxException ex)
- {
- logger.error("Failed to execute the following osgi query: "
- + osgiQuery
- , ex);
- }
-
- if(refs != null && refs.length > 0)
- {
- return (ProtocolProviderServiceZeroconfImpl)bc.getService(refs[0]);
- }
-
- return null;
- }
-
- /**
- * Creates and returns a unresolved contact group from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created
- * <tt>ContactGroup</tt> against the server or the contact itself. The
- * protocol provider will later resolve the contact group. When this happens
- * the corresponding event would notify interested subscription listeners.
- *
- * @param groupUID an identifier, returned by ContactGroup's getGroupUID,
- * that the protocol provider may use in order to create the group.
- * @param persistentData a String returned ContactGroups's
- * getPersistentData() method during a previous run and that has been
- * persistently stored locally.
- * @param parentGroup the group under which the new group is to be created
- * or null if this is group directly underneath the root.
- * @return the unresolved <tt>ContactGroup</tt> created from the specified
- * <tt>uid</tt> and <tt>persistentData</tt>
- */
- public ContactGroup createUnresolvedContactGroup(String groupUID,
- String persistentData, ContactGroup parentGroup)
- {
- ContactGroupZeroconfImpl newGroup
- = new ContactGroupZeroconfImpl(
- ContactGroupZeroconfImpl.createNameFromUID(groupUID)
- , parentProvider);
- newGroup.setResolved(false);
-
- //if parent is null then we're adding under root.
- if(parentGroup == null)
- parentGroup = getServerStoredContactListRoot();
-
- ((ContactGroupZeroconfImpl)parentGroup).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
-
- return newGroup;
- }
-
- private class UnregistrationListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenver
- * a change in the registration state of the corresponding provider had
- * occurred. The method is particularly interested in events stating
- * that the zeroconf provider has unregistered so that it would fire
- * status change events for all contacts in our buddy list.
- *
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF : The Zeroconf provider changed state from: "
- + evt.getOldState()
- + " to: " + evt.getNewState());
-
- //send event notifications saying that all our buddies are
- //offline. The Zeroconf protocol does not implement top level buddies
- //nor subgroups for top level groups so a simple nested loop
- //would be enough.
- Iterator<ContactGroup> groupsIter
- = getServerStoredContactListRoot().subgroups();
- while (groupsIter.hasNext())
- {
- ContactGroup group = groupsIter.next();
- Iterator<Contact> contactsIter = group.contacts();
-
- while (contactsIter.hasNext())
- {
- ContactZeroconfImpl contact
- = (ContactZeroconfImpl) contactsIter.next();
-
- PresenceStatus oldContactStatus
- = contact.getPresenceStatus();
-
- /* We set contacts to OFFLINE and send an event so that external listeners
- * can be aware that the contacts are reachable anymore. Dunno if that's
- * a good idea. Can be erased if not. Contacts clean is directly done by the
- * contact status change handler.
- */
- if (!oldContactStatus.isOnline())
- {
- //contact.setPresenceStatus(ZeroconfStatusEnum.OFFLINE);
- fireContactPresenceStatusChangeEvent(
- contact
- , contact.getParentContactGroup()
- , oldContactStatus);
- }
- }
- }
- }
- }
-
- /**
- * Returns the volatile group or null if this group has not yet been
- * created.
- *
- * @return a volatile group existing in our contact list or <tt>null</tt>
- * if such a group has not yet been created.
- */
- public ContactGroupZeroconfImpl getNonPersistentGroup()
- {
- for (int i = 0;
- i < getServerStoredContactListRoot().countSubgroups();
- i++)
- {
- ContactGroupZeroconfImpl gr =
- (ContactGroupZeroconfImpl)getServerStoredContactListRoot()
- .getGroup(i);
-
- if(!gr.isPersistent())
- return gr;
- }
-
- return null;
- }
-
-
- /**
- * Creates a non persistent contact for the specified address. This would
- * also create (if necessary) a group for volatile contacts that would not
- * be added to the server stored contact list. This method would have no
- * effect on the server stored contact list.
- * @return the newly created volatile contact.
- * @param bonjourService BonjourService responsible for the chat with this contact
- * @param name Display name of the contact
- * @param ip IP address of the contact
- * @param port Port declared by the contact for direct chat
- * @param contactAddress the address of the volatile contact we'd like to
- * create.
- */
- public ContactZeroconfImpl createVolatileContact(String contactAddress,
- BonjourService bonjourService,
- String name,
- InetAddress ip,
- int port)
- {
- //First create the new volatile contact;
- ContactZeroconfImpl newVolatileContact
- = new ContactZeroconfImpl(contactAddress,
- this.parentProvider, bonjourService, name, ip, port);
- newVolatileContact.setPersistent(false);
-
-
- //Check whether a volatile group already exists and if not create
- //one
- ContactGroupZeroconfImpl theVolatileGroup = getNonPersistentGroup();
-
-
- //if the parent volatile group is null then we create it
- if (theVolatileGroup == null)
- {
- theVolatileGroup = new ContactGroupZeroconfImpl(
- "Bonjour"
- , parentProvider);
- theVolatileGroup.setResolved(false);
- theVolatileGroup.setPersistent(false);
-
- this.contactListRoot.addSubgroup(theVolatileGroup);
-
- fireServerStoredGroupEvent(theVolatileGroup
- , ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
- //now add the volatile contact instide it
- theVolatileGroup.addContact(newVolatileContact);
- fireSubscriptionEvent(newVolatileContact
- , theVolatileGroup
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- return newVolatileContact;
- }
-
- public Contact getLocalContact()
- {
- return null;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetTypingNotificationsZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetTypingNotificationsZeroconfImpl.java
deleted file mode 100644
index db397b8..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetTypingNotificationsZeroconfImpl.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Implements typing notifications for the Zeroconf protocol. The operation
- * set would simply mirror all outgoing typing notifications and make them
- * appear as incoming events generated by the contact that we are currently
- * writing a message to.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- */
-public class OperationSetTypingNotificationsZeroconfImpl
- extends AbstractOperationSetTypingNotifications<ProtocolProviderServiceZeroconfImpl>
-{
-
- /**
- * Creates a new instance of this operation set and keeps the parent
- * provider as a reference.
- *
- * @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
- * that created us and that we'll use for retrieving the underlying aim
- * connection.
- */
- OperationSetTypingNotificationsZeroconfImpl(
- ProtocolProviderServiceZeroconfImpl provider)
- {
- super(provider);
- }
-
- /**
- * Sends a notification to <tt>notifiedContatct</tt> that we have entered
- * <tt>typingState</tt>.
- *
- * @param notifiedContact the <tt>Contact</tt> to notify
- * @param typingState the typing state that we have entered.
- *
- * @throws java.lang.IllegalStateException if the underlying stack is
- * not registered and initialized.
- * @throws java.lang.IllegalArgumentException if <tt>notifiedContact</tt> is
- * not an instance belonging to the underlying implementation.
- */
- public void sendTypingNotification(Contact notifiedContact, int typingState)
- throws IllegalStateException, IllegalArgumentException
- {
- if( !(notifiedContact instanceof ContactZeroconfImpl) )
- throw new IllegalArgumentException(
- "The specified contact is not a Zeroconf contact."
- + notifiedContact);
-
- ContactZeroconfImpl to = (ContactZeroconfImpl)notifiedContact;
-
- ClientThread thread = to.getClientThread();
- if (thread == null) return;/*throw new IllegalStateException(
- "No communication channel opened to chat with this contact");*/
-
- if (typingState != STATE_TYPING)
- return;
-
- MessageZeroconfImpl message =
- new MessageZeroconfImpl("",null, MessageZeroconfImpl.TYPING);
- thread.sendMessage(message);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolIconZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolIconZeroconfImpl.java
deleted file mode 100644
index 4c6ce07..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolIconZeroconfImpl.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.resources.*;
-import org.osgi.framework.*;
-
-/**
- * Represents the Zeroconf protocol icon. Implements the <tt>ProtocolIcon</tt>
- * interface in order to provide a Zeroconf logo image in two different sizes.
- *
- * @author Christian Vincenot
- * @author Jonathan Martin
- */
-public class ProtocolIconZeroconfImpl
- implements ProtocolIcon
-{
- private static Logger logger
- = Logger.getLogger(ProtocolIconZeroconfImpl.class);
-
- private static ResourceManagementService resourcesService;
-
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String, byte[]> iconsTable
- = new Hashtable<String, byte[]>();
- static
- {
- iconsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- getImageInBytes("service.protocol.zeroconf.ZEROCONF_16x16"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- getImageInBytes("service.protocol.zeroconf.ZEROCONF_32x32"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- getImageInBytes("service.protocol.zeroconf.ZEROCONF_48x48"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- getImageInBytes("service.protocol.zeroconf.ZEROCONF_64x64"));
- }
-
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String, String> iconPathsTable
- = new Hashtable<String, String>();
- static
- {
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- getResources().getImagePath(
- "service.protocol.zeroconf.ZEROCONF_16x16"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- getResources().getImagePath(
- "service.protocol.zeroconf.ZEROCONF_32x32"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- getResources().getImagePath(
- "service.protocol.zeroconf.ZEROCONF_48x48"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- getResources().getImagePath(
- "service.protocol.zeroconf.ZEROCONF_64x64"));
- }
-
- /**
- * Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns
- * an iterator to a set containing the supported icon sizes.
- * @return an iterator to a set containing the supported icon sizes
- */
- public Iterator<String> getSupportedSizes()
- {
- return iconsTable.keySet().iterator();
- }
-
- /**
- * Returns TRUE if a icon with the given size is supported, FALSE-otherwise.
- * @param iconSize Icon size
- * @return True if this size is supported, false otherwise
- */
- public boolean isSizeSupported(String iconSize)
- {
- return iconsTable.containsKey(iconSize);
- }
-
- /**
- * Returns the icon image in the given size.
- * @param iconSize the icon size; one of ICON_SIZE_XXX constants
- * @return Icon image
- */
- public byte[] getIcon(String iconSize)
- {
- return iconsTable.get(iconSize);
- }
-
- /**
- * Returns a path to the icon with the given size.
- * @param iconSize the size of the icon we're looking for
- * @return the path to the icon with the given size
- */
- public String getIconPath(String iconSize)
- {
- return iconPathsTable.get(iconSize);
- }
-
- /**
- * Returns the icon image used to represent the protocol connecting state.
- * @return the icon image used to represent the protocol connecting state
- */
- public byte[] getConnectingIcon()
- {
- return getImageInBytes("zeroconfOnlineIcon");
- }
-
- /**
- * Returns the byte representation of the image corresponding to the given
- * identifier.
- *
- * @param imageID the identifier of the image
- * @return the byte representation of the image corresponding to the given
- * identifier.
- */
- public static byte[] getImageInBytes(String imageID)
- {
- InputStream in = getResources().
- getImageInputStream(imageID);
-
- if (in == null)
- return null;
- byte[] image = null;
- try
- {
- image = new byte[in.available()];
-
- in.read(image);
- }
- catch (IOException e)
- {
- logger.error("Failed to load image:" + imageID, e);
- }
-
- return image;
- }
-
- /**
- * Returns the <tt>ResourceManagementService</tt>.
- *
- * @return the <tt>ResourceManagementService</tt>
- */
- public static ResourceManagementService getResources()
- {
- if (resourcesService == null)
- {
- ServiceReference serviceReference = ZeroconfActivator.bundleContext
- .getServiceReference(ResourceManagementService.class.getName());
-
- if(serviceReference == null)
- return null;
-
- resourcesService
- = (ResourceManagementService)ZeroconfActivator.bundleContext
- .getService(serviceReference);
- }
-
- return resourcesService;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderFactoryZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderFactoryZeroconfImpl.java
deleted file mode 100644
index e68033f..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderFactoryZeroconfImpl.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-import org.osgi.framework.*;
-
-/**
- * The Zeroconf protocol provider factory creates instances of the Zeroconf
- * protocol provider service. One Service instance corresponds to one account.
- *
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- */
-public class ProtocolProviderFactoryZeroconfImpl
- extends ProtocolProviderFactory
-{
-
- /**
- * Creates an instance of the ProtocolProviderFactoryZeroconfImpl.
- */
- public ProtocolProviderFactoryZeroconfImpl()
- {
- super(ZeroconfActivator.getBundleContext(), ProtocolNames.ZEROCONF);
- }
-
- /**
- * Initializaed and creates an account corresponding to the specified
- * accountProperties and registers the resulting ProtocolProvider in the
- * <tt>context</tt> BundleContext parameter.
- *
- * @param userIDStr tha/a user identifier uniquely representing the newly
- * created account within the protocol namespace.
- * @param accountProperties a set of protocol (or implementation)
- * specific properties defining the new account.
- * @return the AccountID of the newly created account.
- */
- @Override
- public AccountID installAccount( String userIDStr,
- Map<String, String> accountProperties)
- {
- BundleContext context
- = ZeroconfActivator.getBundleContext();
- if (context == null)
- throw new NullPointerException(
- "The specified BundleContext was null");
-
- if (userIDStr == null)
- throw new NullPointerException(
- "The specified AccountID was null");
-
- if (accountProperties == null)
- throw new NullPointerException(
- "The specified property map was null");
-
- accountProperties.put(USER_ID, userIDStr);
-
- AccountID accountID =
- new ZeroconfAccountID(userIDStr, accountProperties);
-
- //make sure we haven't seen this account id before.
- if (registeredAccounts.containsKey(accountID))
- throw new IllegalStateException(
- "An account for id " + userIDStr + " was already installed!");
-
- //first store the account and only then load it as the load generates
- //an osgi event, the osgi event triggers (through the UI) a call to the
- //ProtocolProviderService.register() method and it needs to access
- //the configuration service and check for a stored password.
- this.storeAccount(accountID, false);
-
- accountID = loadAccount(accountProperties);
-
- return accountID;
- }
-
- @Override
- protected AccountID createAccountID(String userID, Map<String, String> accountProperties)
- {
- return new ZeroconfAccountID(userID, accountProperties);
- }
-
- @Override
- protected ProtocolProviderService createService(String userID,
- AccountID accountID)
- {
- ProtocolProviderServiceZeroconfImpl service =
- new ProtocolProviderServiceZeroconfImpl();
-
- service.initialize(userID, accountID);
- return service;
- }
-
- @Override
- public void modifyAccount( ProtocolProviderService protocolProvider,
- Map<String, String> accountProperties)
- throws NullPointerException
- {
- // TODO Auto-generated method stub
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderServiceZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderServiceZeroconfImpl.java
deleted file mode 100644
index 7fe916f..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderServiceZeroconfImpl.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * An implementation of the protocol provider service over the Zeroconf protocol
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- */
-public class ProtocolProviderServiceZeroconfImpl
- extends AbstractProtocolProviderService
-{
- /**
- * The logger for this class.
- */
- private static final Logger logger =
- Logger.getLogger(ProtocolProviderServiceZeroconfImpl.class);
-
- /**
- * We use this to lock access to initialization.
- */
- private final Object initializationLock = new Object();
-
- /**
- * The id of the account that this protocol provider represents.
- */
- private AccountID accountID = null;
-
- /**
- * Indicates whether or not the provider is initialized and ready for use.
- */
- private boolean isInitialized = false;
-
- /**
- * The logo corresponding to the zeroconf protocol.
- */
- private final ProtocolIconZeroconfImpl zeroconfIcon
- = new ProtocolIconZeroconfImpl();
-
- /**
- * The registration state that we are currently in. Note that in a real
- * world protocol implementation this field won't exist and the registration
- * state would be retrieved from the protocol stack.
- */
- private RegistrationState currentRegistrationState
- = RegistrationState.UNREGISTERED;
-
- /**
- * The BonjourService corresponding to this ProtocolProviderService
- */
-
- private BonjourService bonjourService;
-
- /**
- * The default constructor for the Zeroconf protocol provider.
- */
- public ProtocolProviderServiceZeroconfImpl()
- {
- if (logger.isTraceEnabled())
- logger.trace("Creating a zeroconf provider.");
- }
-
- /**
- * Returns the AccountID that uniquely identifies the account represented
- * by this instance of the ProtocolProviderService.
- *
- * @return the id of the account represented by this provider.
- */
- public AccountID getAccountID()
- {
- return accountID;
- }
-
- /**
- * Returns the Bonjour Service that handles the Bonjour protocol stack.
- *
- *@return the Bonjour Service linked with this Protocol Provider
- */
- public BonjourService getBonjourService()
- {
- return bonjourService;
- }
-
- /**
- * Initializes the service implementation, and puts it in a sate where it
- * could interoperate with other services. It is strongly recomended that
- * properties in this Map be mapped to property names as specified by
- * <tt>AccountProperties</tt>.
- *
- * @param userID the user id of the zeroconf account we're currently
- * initializing
- * @param accountID the identifier of the account that this protocol
- * provider represents.
- *
- * @see net.java.sip.communicator.service.protocol.AccountID
- */
- protected void initialize(String userID,
- AccountID accountID)
- {
- synchronized(initializationLock)
- {
- this.accountID = accountID;
-
-
- //initialize the presence operationset
- OperationSetPersistentPresenceZeroconfImpl persistentPresence =
- new OperationSetPersistentPresenceZeroconfImpl(this);
-
- addSupportedOperationSet(
- OperationSetPersistentPresence.class,
- persistentPresence);
- //register it once again for those that simply need presence and
- //won't be smart enough to check for a persistent presence
- //alternative
- addSupportedOperationSet(
- OperationSetPresence.class,
- persistentPresence);
-
- //initialize the IM operation set
- addSupportedOperationSet(
- OperationSetBasicInstantMessaging.class,
- new OperationSetBasicInstantMessagingZeroconfImpl(
- this,
- persistentPresence));
-
- //initialize the typing notifications operation set
- addSupportedOperationSet(
- OperationSetTypingNotifications.class,
- new OperationSetTypingNotificationsZeroconfImpl(this));
-
- isInitialized = true;
- }
- }
-
- /**
- * Returns the short name of the protocol that the implementation of this
- * provider is based upon (like SIP, Jabber, ICQ/AIM, or others for
- * example).
- *
- * @return a String containing the short name of the protocol this
- * service is implementing (most often that would be a name in
- * ProtocolNames).
- */
- public String getProtocolName()
- {
- return ProtocolNames.ZEROCONF;
- }
-
- /**
- * Returns the state of the registration of this protocol provider with
- * the corresponding registration service.
- *
- * @return ProviderRegistrationState
- */
- public RegistrationState getRegistrationState()
- {
- return currentRegistrationState;
- }
-
- /**
- * Starts the registration process.
- *
- * @param authority the security authority that will be used for
- * resolving any security challenges that may be returned during the
- * registration or at any moment while wer're registered.
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void register(SecurityAuthority authority)
- throws OperationFailedException
- {
- //we don't need a password here since there's no server in
- //zeroconf.
-
- RegistrationState oldState = currentRegistrationState;
- currentRegistrationState = RegistrationState.REGISTERED;
-
-
- //ICI : creer le service Zeroconf !!
- if (logger.isInfoEnabled())
- logger.info("ZEROCONF: Starting the service");
- this.bonjourService = new BonjourService(5298, this);
-
- //bonjourService.changeStatus(ZeroconfStatusEnum.ONLINE);
-
- fireRegistrationStateChanged(
- oldState
- , currentRegistrationState
- , RegistrationStateChangeEvent.REASON_USER_REQUEST
- , null);
- }
-
- /**
- * Makes the service implementation close all open sockets and release
- * any resources that it might have taken and prepare for
- * shutdown/garbage collection.
- */
- public void shutdown()
- {
- if(!isInitialized)
- {
- return;
- }
- if (logger.isTraceEnabled())
- logger.trace("Killing the Zeroconf Protocol Provider.");
-
- if(isRegistered())
- {
- try
- {
- //do the unregistration
- unregister();
- }
- catch (OperationFailedException ex)
- {
- //we're shutting down so we need to silence the exception here
- logger.error(
- "Failed to properly unregister before shutting down. "
- + getAccountID()
- , ex);
- }
- }
-
- isInitialized = false;
- }
-
- /**
- * Ends the registration of this protocol provider with the current
- * registration service.
- *
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void unregister()
- throws OperationFailedException
- {
- RegistrationState oldState = currentRegistrationState;
- currentRegistrationState = RegistrationState.UNREGISTERED;
-
- if(bonjourService != null)
- bonjourService.shutdown();
-
- fireRegistrationStateChanged(
- oldState
- , currentRegistrationState
- , RegistrationStateChangeEvent.REASON_USER_REQUEST
- , null);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see net.java.sip.communicator.service.protocol.ProtocolProviderService#
- * isSignallingTransportSecure()
- */
- public boolean isSignalingTransportSecure()
- {
- return false;
- }
-
- /**
- * Returns the "transport" protocol of this instance used to carry the
- * control channel for the current protocol service.
- *
- * @return The "transport" protocol of this instance: TCP.
- */
- public TransportProtocol getTransportProtocol()
- {
- return TransportProtocol.TCP;
- }
-
- /**
- * Returns the zeroconf protocol icon.
- * @return the zeroconf protocol icon
- */
- public ProtocolIcon getProtocolIcon()
- {
- return zeroconfIcon;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfAccountID.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfAccountID.java
deleted file mode 100644
index 64e22c7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfAccountID.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The Zeroconf implementation of a sip-communicator AccountID
- *
- * @author Christian Vincenot
- */
-public class ZeroconfAccountID
- extends AccountID
-{
- /* Firstname, lastname, mail address */
- private String first = null;
- private String last = null;
- private String mail = null;
-
- private boolean rememberContacts = false;
-
- /**
- * Creates a zeroconf account id from the specified id and account
- * properties.
- * @param userID id identifying this account
- * @param accountProperties any other properties necessary for the account.
- */
- ZeroconfAccountID(String userID, Map<String, String> accountProperties)
- {
- super(userID,
- accountProperties,
- ProtocolNames.ZEROCONF,
- "zeroconf.org");
-
- first = accountProperties.get("first");
- last = accountProperties.get("last");
- mail = accountProperties.get("mail");
-
- rememberContacts =
- new Boolean(accountProperties.get("rememberContacts"))
- .booleanValue();
- }
-
- /**
- * Returns a String representing the firstname of this user.
- * @return String representing the firstname of this user.
- */
- public String getFirst()
- {
- return first;
- }
-
- /**
- * Returns a String representing the lastname of this user.
- * @return String representing the lastname of this user.
- */
- public String getLast()
- {
- return last;
- }
-
- /**
- * Returns a String representing the mail address of this user.
- * @return String representing the mail address of this user.
- */
- public String getMail()
- {
- return mail;
- }
-
- /**
- * Returns a boolean indicating if we store the contacts we meet or not.
- * @return boolean indicating if we store the contacts we meet or not.
- */
- public boolean isRememberContacts()
- {
- return rememberContacts;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfActivator.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfActivator.java
deleted file mode 100644
index 2544bab..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfActivator.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.osgi.framework.*;
-
-/**
- * Loads the Zeroconf provider factory and registers its services in the OSGI
- * bundle context.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- */
-public class ZeroconfActivator
- implements BundleActivator
-{
- private static final Logger logger
- = Logger.getLogger(ZeroconfActivator.class);
-
- /**
- * A reference to the registration of our Zeroconf protocol provider
- * factory.
- */
- private ServiceRegistration zeroconfPpFactoryServReg = null;
-
- /**
- * A reference to the Zeroconf protocol provider factory.
- */
- private static ProtocolProviderFactoryZeroconfImpl
- zeroconfProviderFactory = null;
-
- /**
- * The currently valid bundle context.
- */
- static BundleContext bundleContext = null;
-
-
- /**
- * Called when this bundle is started. In here we'll export the
- * zeroconf ProtocolProviderFactory implementation so that it could be
- * possible to register accounts with it in SIP Communicator.
- *
- * @param context The execution context of the bundle being started.
- * @throws Exception If this method throws an exception, this bundle is
- * marked as stopped and the Framework will remove this bundle's
- * listeners, unregister all services registered by this bundle, and
- * release all services used by this bundle.
- */
- public void start(BundleContext context)
- throws Exception
- {
-// logger.setLevelAll();
-
- bundleContext = context;
-
- Hashtable<String, String> hashtable = new Hashtable<String, String>();
- hashtable.put(ProtocolProviderFactory.PROTOCOL, "Zeroconf");
-
- zeroconfProviderFactory = new ProtocolProviderFactoryZeroconfImpl();
-
- //register the zeroconf provider factory.
- zeroconfPpFactoryServReg = context.registerService(
- ProtocolProviderFactory.class.getName(),
- zeroconfProviderFactory,
- hashtable);
-
- if (logger.isInfoEnabled())
- logger.info("Zeroconf protocol implementation [STARTED].");
- }
-
- /**
- * Returns a reference to the bundle context that we were started with.
- * @return a reference to the BundleContext instance that we were started
- * witn.
- */
- public static BundleContext getBundleContext()
- {
- return bundleContext;
- }
-
- /**
- * Retrurns a reference to the protocol provider factory that we have
- * registered.
- * @return a reference to the <tt>ProtocolProviderFactoryJabberImpl</tt>
- * instance that we have registered from this package.
- */
- public static ProtocolProviderFactoryZeroconfImpl getProtocolProviderFactory()
- {
- return zeroconfProviderFactory;
- }
-
-
- /**
- * Called when this bundle is stopped so the Framework can perform the
- * bundle-specific activities necessary to stop the bundle.
- *
- * @param context The execution context of the bundle being stopped.
- * @throws Exception If this method throws an exception, the bundle is
- * still marked as stopped, and the Framework will remove the bundle's
- * listeners, unregister all services registered by the bundle, and
- * release all services used by the bundle.
- */
- public void stop(BundleContext context)
- throws Exception
- {
- zeroconfProviderFactory.stop();
- zeroconfPpFactoryServReg.unregister();
-
- if (logger.isInfoEnabled())
- logger.info("Zeroconf protocol implementation [STOPPED].");
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfStatusEnum.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfStatusEnum.java
deleted file mode 100644
index 3fe2745..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfStatusEnum.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * An implementation of <tt>PresenceStatus</tt> that enumerates all states that
- * a Zeroconf contact can fall into.
- *
- * @author Christian Vincenot
- * @author Jonathan Martin
- */
-public class ZeroconfStatusEnum
- extends PresenceStatus
-{
-
- /**
- * Indicates an Offline status or status with 0 connectivity.
- */
- public static final ZeroconfStatusEnum OFFLINE
- = new ZeroconfStatusEnum(
- 0,
- "Offline",
- ProtocolIconZeroconfImpl.getImageInBytes(
- "service.protocol.zeroconf.OFFLINE_STATUS_ICON"));
-
- /**
- * The DND status. Indicates that the user has connectivity but prefers
- * not to be contacted.
- */
- public static final ZeroconfStatusEnum DO_NOT_DISTURB
- = new ZeroconfStatusEnum(
- 30,
- "Do Not Disturb",//, "Do Not Disturb",
- ProtocolIconZeroconfImpl.getImageInBytes(
- "service.protocol.zeroconf.DND_STATUS_ICON"));
-
- /**
- * The Invisible status. Indicates that the user has connectivity even
- * though it may appear otherwise to others, to whom she would appear to be
- * offline.
- */
- public static final ZeroconfStatusEnum INVISIBLE
- = new ZeroconfStatusEnum(
- 45,
- "Invisible",
- ProtocolIconZeroconfImpl.getImageInBytes(
- "service.protocol.zeroconf.INVISIBLE_STATUS_ICON"));
-
- /**
- * The Online status. Indicate that the user is able and willing to
- * communicate.
- */
- public static final ZeroconfStatusEnum ONLINE
- = new ZeroconfStatusEnum(
- 65,
- "Available",//, "Online"
- ProtocolIconZeroconfImpl.getImageInBytes(
- "service.protocol.zeroconf.ONLINE_STATUS_ICON"));
-
-
- /**
- * Initialize the list of supported status states.
- */
- private static List<PresenceStatus> supportedStatusSet = new LinkedList<PresenceStatus>();
- static
- {
- supportedStatusSet.add(OFFLINE);
- supportedStatusSet.add(DO_NOT_DISTURB);
-
- /* INVISIBLE STATUS could be supported by unregistering JmDNS and
- * accepting unknown contacts' messages */
- //supportedStatusSet.add(INVISIBLE);
-
- supportedStatusSet.add(ONLINE);
- }
-
- /**
- * Creates an instance of <tt>ZeroconfPresneceStatus</tt> with the
- * specified parameters.
- * @param status the connectivity level of the new presence status instance
- * @param statusName the name of the presence status.
- * @param statusIcon the icon associated with this status
- */
- private ZeroconfStatusEnum(int status,
- String statusName,
- byte[] statusIcon)
- {
- super(status, statusName, statusIcon);
- }
-
- /**
- * Returns an iterator over all status instances supproted by the zeroconf
- * provider.
- * @return an <tt>Iterator</tt> over all status instances supported by the
- * zeroconf provider.
- */
- static Iterator<PresenceStatus> supportedStatusSet()
- {
- return supportedStatusSet.iterator();
- }
-
- /**
- * @param status String representation of the status
- * @return ZeroconfStatusEnum corresponding the supplied String value
- */
- static ZeroconfStatusEnum statusOf(String status)
- {
- Iterator<PresenceStatus> statusIter = supportedStatusSet();
- while (statusIter.hasNext())
- {
- ZeroconfStatusEnum state = (ZeroconfStatusEnum)statusIter.next();
- if (state.statusName.equalsIgnoreCase(status))
- return state;
- }
- return null;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSCache.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSCache.java
deleted file mode 100644
index 0baaff4..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSCache.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-
-import net.java.sip.communicator.util.*;
-
-/**
- * A table of DNS entries. This is a hash table which
- * can handle multiple entries with the same name.
- * <p/>
- * Storing multiple entries with the same name is implemented using a
- * linked list of <code>CacheNode</code>'s.
- * <p/>
- * The current implementation of the API of DNSCache does expose the
- * cache nodes to clients. Clients must explicitly deal with the nodes
- * when iterating over entries in the cache. Here's how to iterate over
- * all entries in the cache:
- * <pre>
- * for (Iterator i=dnscache.iterator(); i.hasNext(); )
- * {
- * for ( DNSCache.CacheNode n = (DNSCache.CacheNode) i.next();
- * n != null;
- * n.next())
- * {
- * DNSEntry entry = n.getValue();
- * ...do something with entry...
- * }
- * }
- * </pre>
- * <p/>
- * And here's how to iterate over all entries having a given name:
- * <pre>
- * for ( DNSCache.CacheNode n = (DNSCache.CacheNode) dnscache.find(name);
- * n != null;
- * n.next())
- * {
- * DNSEntry entry = n.getValue();
- * ...do something with entry...
- * }
- * </pre>
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Werner Randelshofer, Rick Blair
- */
-class DNSCache
-{
- private static Logger logger = Logger.getLogger(DNSCache.class.toString());
- // Implementation note:
- // We might completely hide the existence of CacheNode's in a future version
- // of DNSCache. But this will require to implement two (inner) classes for
- // the iterators that will be returned by method <code>iterator()</code> and
- // method <code>find(name)</code>.
- // Since DNSCache is not a public class, it does not seem worth the effort
- // to clean its API up that much.
-
- // [PJYF Oct 15 2004] This should implements Collections
- // that would be amuch cleaner implementation
-
- /**
- * The number of DNSEntry's in the cache.
- */
- private int size;
-
- /**
- * The hashtable used internally to store the entries of the cache.
- * Keys are instances of String. The String contains an unqualified service
- * name.
- * Values are linked lists of CacheNode instances.
- */
- private HashMap<String, CacheNode> hashtable;
-
- /**
- * Cache nodes are used to implement storage of multiple DNSEntry's of the
- * same name in the cache.
- */
- public static class CacheNode
- {
- private DNSEntry value;
- private CacheNode next;
-
- public CacheNode(DNSEntry value)
- {
- this.value = value;
-// String SLevel = System.getProperty("jmdns.debug");
-// if (SLevel == null)
-// SLevel = "INFO";
-// logger.setLevel(Level.parse(SLevel));
- }
-
- public CacheNode next()
- {
- return next;
- }
-
- public DNSEntry getValue()
- {
- return value;
- }
- }
-
-
- /**
- * Create a table with a given initial size.
- * @param size initial size.
- */
- public DNSCache(final int size)
- {
- hashtable = new HashMap<String, CacheNode>(size);
-
-// String SLevel = System.getProperty("jmdns.debug");
-// if (SLevel == null) SLevel = "INFO";
-// logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Clears the cache.
- */
- public synchronized void clear()
- {
- hashtable.clear();
- size = 0;
- }
-
- /**
- * Adds an entry to the table.
- * @param entry added to the table.
- */
- public synchronized void add(final DNSEntry entry)
- {
- //logger.log("DNSCache.add("+entry.getName()+")");
- CacheNode newValue = new CacheNode(entry);
- CacheNode node = hashtable.get(entry.getName());
- if (node == null)
- {
- hashtable.put(entry.getName(), newValue);
- }
- else
- {
- newValue.next = node.next;
- node.next = newValue;
- }
- size++;
- }
-
- /**
- * Remove a specific entry from the table.
- * @param entry removed from table.
- * @return Returns true if the entry was found.
- */
- public synchronized boolean remove(DNSEntry entry)
- {
- CacheNode node = hashtable.get(entry.getName());
- if (node != null)
- {
- if (node.value == entry)
- {
- if (node.next == null)
- {
- hashtable.remove(entry.getName());
- }
- else
- {
- hashtable.put(entry.getName(), node.next);
- }
- size--;
- return true;
- }
-
- CacheNode previous = node;
- node = node.next;
- while (node != null)
- {
- if (node.value == entry)
- {
- previous.next = node.next;
- size--;
- return true;
- }
- previous = node;
- node = node.next;
- }
- ;
- }
- return false;
- }
-
- /**
- * Get a matching DNS entry from the table (using equals).
- * @param entry to be found in table.
- * @return Returns the entry that was found.
- */
- public synchronized DNSEntry get(DNSEntry entry)
- {
- for (CacheNode node = find(entry.getName()); node != null; node = node.next)
- {
- if (node.value.equals(entry))
- {
- return node.value;
- }
- }
- return null;
- }
-
- /**
- * Get a matching DNS entry from the table.
- * @param name
- * @param type
- * @param clazz
- * @return Return the entry if found, null otherwise.
- */
- public synchronized DNSEntry get(String name, int type, int clazz)
- {
- for (CacheNode node = find(name); node != null; node = node.next)
- {
- if (node.value.type == type && node.value.clazz == clazz)
- {
- return node.value;
- }
- }
- return null;
- }
-
- /**
- * Iterates over all cache nodes.
- * The iterator returns instances of DNSCache.CacheNode.
- * Each instance returned is the first node of a linked list.
- * To retrieve all entries, one must iterate over this linked list. See
- * code snippets in the header of the class.
- * @return Returns iterator with instances of DNSCache.CacheNode.
- */
- public Iterator<DNSCache.CacheNode> iterator()
- {
- return Collections.unmodifiableCollection(hashtable.values()).iterator();
- }
-
- /**
- * Iterate only over items with matching name.
- * If an instance is returned, it is the first node of a linked list.
- * To retrieve all entries, one must iterate over this linked list.
- * @param name to be found.
- * @return Returns an instance of DNSCache.CacheNode or null.
- */
- public synchronized CacheNode find(String name)
- {
- return hashtable.get(name);
- }
-
- /**
- * List all entries for debugging.
- */
- public synchronized void print()
- {
- for (Iterator<CacheNode> i = iterator(); i.hasNext();)
- {
- for (CacheNode n = i.next(); n != null; n = n.next)
- {
- if (logger.isInfoEnabled())
- logger.info(n.value.toString());
- }
- }
- }
-
- @Override
- public synchronized String toString()
- {
- StringBuffer aLog = new StringBuffer();
- aLog.append("\t---- cache ----");
- for (Iterator<CacheNode> i = iterator(); i.hasNext();)
- {
- for (CacheNode n = i.next(); n != null; n = n.next)
- {
- aLog.append("\n\t\t" + n.value);
- }
- }
- return aLog.toString();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSConstants.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSConstants.java
deleted file mode 100644
index 8792c8d..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSConstants.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff, Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-/**
- * DNS constants.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Jeff Sonstein,
- * Werner Randelshofer, Pierre Frisch, Rick Blair
- */
-public final class DNSConstants
-{
-
- // changed to final class - jeffs
- final static String MDNS_GROUP = "224.0.0.251";
- final static String MDNS_GROUP_IPV6 = "FF02::FB";
- final static int MDNS_PORT = 5353;
- final static int DNS_PORT = 53;
- // default one hour TTL
- final static int DNS_TTL = 60 * 60;
- // two hour TTL (draft-cheshire-dnsext-multicastdns.txt ch 13)
- // final static int DNS_TTL = 120 * 60;
-
- final static int MAX_MSG_TYPICAL = 1460;
- final static int MAX_MSG_ABSOLUTE = 8972;
-
- final static int FLAGS_QR_MASK = 0x8000; // Query response mask
- final static int FLAGS_QR_QUERY = 0x0000; // Query
- final static int FLAGS_QR_RESPONSE = 0x8000;// Response
-
- public final static int FLAGS_AA = 0x0400; // Authorative answer
- final static int FLAGS_TC = 0x0200; // Truncated
- final static int FLAGS_RD = 0x0100; // Recursion desired
- public final static int FLAGS_RA = 0x8000; // Recursion available
-
- final static int FLAGS_Z = 0x0040; // Zero
- final static int FLAGS_AD = 0x0020; // Authentic data
- final static int FLAGS_CD = 0x0010; // Checking disabled
-
- // Final Static Internet
- public final static int CLASS_IN = 1;
- // CSNET
- final static int CLASS_CS = 2;
- // CHAOS
- final static int CLASS_CH = 3;
- // Hesiod
- final static int CLASS_HS = 4;
- // Used in DNS UPDATE [RFC 2136]
- final static int CLASS_NONE = 254;
- // Not a DNS class, but a DNS query class, meaning "all classes"
- final static int CLASS_ANY = 255;
- // Multicast DNS uses the bottom 15 bits to identify the record class...
- final static int CLASS_MASK = 0x7FFF;
- // ... and the top bit indicates that all other cached records are now invalid
- public final static int CLASS_UNIQUE = 0x8000;
-
- final static int TYPE_IGNORE = 0; // This is a hack to stop further processing
- public final static int TYPE_A = 1; // Address
- final static int TYPE_NS = 2; // Name Server
- final static int TYPE_MD = 3; // Mail Destination
- final static int TYPE_MF = 4; // Mail Forwarder
- final static int TYPE_CNAME = 5; // Canonical Name
- final static int TYPE_SOA = 6; // Start of Authority
- final static int TYPE_MB = 7; // Mailbox
- final static int TYPE_MG = 8; // Mail Group
- final static int TYPE_MR = 9; // Mail Rename
- final static int TYPE_NULL = 10; // NULL RR
- final static int TYPE_WKS = 11; // Well-known-service
- final static int TYPE_PTR = 12; // Domain Name pofinal static inter
- final static int TYPE_HINFO = 13; // Host information
- final static int TYPE_MINFO = 14; // Mailbox information
- final static int TYPE_MX = 15; // Mail exchanger
- public final static int TYPE_TXT = 16;// Arbitrary text string
- final static int TYPE_RP = 17; // for Responsible Person [RFC1183]
- final static int TYPE_AFSDB = 18; // for AFS Data Base location [RFC1183]
- final static int TYPE_X25 = 19; // for X.25 PSDN address [RFC1183]
- final static int TYPE_ISDN = 20; // for ISDN address [RFC1183]
- final static int TYPE_RT = 21; // for Route Through [RFC1183]
- final static int TYPE_NSAP = 22; // for NSAP address, NSAP style A record [RFC1706]
- final static int TYPE_NSAP_PTR = 23;//
- final static int TYPE_SIG = 24; // for security signature [RFC2931]
- final static int TYPE_KEY = 25; // for security key [RFC2535]
- final static int TYPE_PX = 26; // X.400 mail mapping information [RFC2163]
- final static int TYPE_GPOS = 27; // Geographical Position [RFC1712]
- final static int TYPE_AAAA = 28; // IP6 Address [Thomson]
- final static int TYPE_LOC = 29; // Location Information [Vixie]
- final static int TYPE_NXT = 30; // Next Domain - OBSOLETE [RFC2535, RFC3755]
- final static int TYPE_EID = 31; // Endpoint Identifier [Patton]
- final static int TYPE_NIMLOC = 32; // Nimrod Locator [Patton]
- public final static int TYPE_SRV = 33;// Server Selection [RFC2782]
- final static int TYPE_ATMA = 34; // ATM Address [Dobrowski]
- final static int TYPE_NAPTR = 35; // Naming Authority Pointer [RFC2168, RFC2915]
- final static int TYPE_KX = 36; // Key Exchanger [RFC2230]
- final static int TYPE_CERT = 37; // CERT [RFC2538]
- final static int TYPE_A6 = 38; // A6 [RFC2874]
- final static int TYPE_DNAME = 39; // DNAME [RFC2672]
- final static int TYPE_SINK = 40; // SINK [Eastlake]
- final static int TYPE_OPT = 41; // OPT [RFC2671]
- final static int TYPE_APL = 42; // APL [RFC3123]
- final static int TYPE_DS = 43; // Delegation Signer [RFC3658]
- final static int TYPE_SSHFP = 44; // SSH Key Fingerprint [RFC-ietf-secsh-dns-05.txt]
- final static int TYPE_RRSIG = 46; // RRSIG [RFC3755]
- final static int TYPE_NSEC = 47; // NSEC [RFC3755]
- final static int TYPE_DNSKEY = 48; // DNSKEY [RFC3755]
- final static int TYPE_UINFO = 100; // [IANA-Reserved]
- final static int TYPE_UID = 101; // [IANA-Reserved]
- final static int TYPE_GID = 102; // [IANA-Reserved]
- final static int TYPE_UNSPEC = 103; // [IANA-Reserved]
- final static int TYPE_TKEY = 249; // Transaction Key [RFC2930]
- final static int TYPE_TSIG = 250; // Transaction Signature [RFC2845]
- final static int TYPE_IXFR = 251; // Incremental transfer [RFC1995]
- final static int TYPE_AXFR = 252; // Transfer of an entire zone [RFC1035]
- final static int TYPE_MAILA = 253; // Mailbox-related records (MB, MG or MR) [RFC1035]
- final static int TYPE_MAILB = 254; // Mail agent RRs (Obsolete - see MX) [RFC1035]
- final static int TYPE_ANY = 255; // Request for all records [RFC1035]
-
- //Time Intervals for various functions
-
- //milliseconds before send shared query
- final static int SHARED_QUERY_TIME = 20;
- //milliseconds between query loops.
- final static int QUERY_WAIT_INTERVAL = 225;
- //milliseconds between probe loops.
- final static int PROBE_WAIT_INTERVAL = 250;
- //minimal wait interval for response.
- final static int RESPONSE_MIN_WAIT_INTERVAL = 20;
- //maximal wait interval for response
- final static int RESPONSE_MAX_WAIT_INTERVAL = 115;
- //milliseconds to wait after conflict.
- final static int PROBE_CONFLICT_INTERVAL = 1000;
- //After x tries go 1 time a sec. on probes.
- final static int PROBE_THROTTLE_COUNT = 10;
- //We only increment the throttle count, if
- // the previous increment is inside this interval.
- final static int PROBE_THROTTLE_COUNT_INTERVAL = 5000;
- //milliseconds between Announce loops.
- final static int ANNOUNCE_WAIT_INTERVAL = 1000;
- //milliseconds between cache cleanups.
- final static int RECORD_REAPER_INTERVAL = 10000;
-
- final static int KNOWN_ANSWER_TTL = 120;
- // 50% of the TTL in milliseconds
- final static int ANNOUNCED_RENEWAL_TTL_INTERVAL = DNS_TTL * 500;
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSEntry.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSEntry.java
deleted file mode 100644
index 7132756..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSEntry.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.logging.*;
-
-/**
- * DNS entry with a name, type, and class. This is the base
- * class for questions and records.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Pierre Frisch, Rick Blair
- * @author Christian Vincenot
- */
-public class DNSEntry
-{
- private static Logger logger = Logger.getLogger(DNSEntry.class.toString());
- String key;
- String name;
- int type;
- int clazz;
- boolean unique;
-
- /**
- * Create an entry.
- */
- DNSEntry(String name, int type, int clazz)
- {
- this.key = name.toLowerCase();
- this.name = name;
- this.type = type;
- this.clazz = clazz & DNSConstants.CLASS_MASK;
- this.unique = (clazz & DNSConstants.CLASS_UNIQUE) != 0;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Check if two entries have exactly the same name, type, and class.
- */
- @Override
- public boolean equals(Object obj)
- {
- if (obj instanceof DNSEntry)
- {
- DNSEntry other = (DNSEntry) obj;
- return name.equals(other.name) &&
- type == other.type &&
- clazz == other.clazz;
- }
- return false;
- }
-
- public String getName()
- {
- return name;
- }
-
- public int getType()
- {
- return type;
- }
-
- public int getClazz()
- {
- return clazz;
- }
-
-
- public boolean isUnique()
- {
- return unique;
- }
-
- /**
- * Overriden, to return a value which is consistent with the value returned
- * by equals(Object).
- */
- @Override
- public int hashCode()
- {
- return name.hashCode() + type + clazz;
- }
-
- /**
- * Get a string given a clazz.
- */
- static String getClazz(int clazz)
- {
- switch (clazz & DNSConstants.CLASS_MASK)
- {
- case DNSConstants.CLASS_IN:
- return "in";
- case DNSConstants.CLASS_CS:
- return "cs";
- case DNSConstants.CLASS_CH:
- return "ch";
- case DNSConstants.CLASS_HS:
- return "hs";
- case DNSConstants.CLASS_NONE:
- return "none";
- case DNSConstants.CLASS_ANY:
- return "any";
- default:
- return "?";
- }
- }
-
- /**
- * Get a string given a type.
- */
- static String getType(int type)
- {
- switch (type)
- {
- case DNSConstants.TYPE_A:
- return "a";
- case DNSConstants.TYPE_AAAA:
- return "aaaa";
- case DNSConstants.TYPE_NS:
- return "ns";
- case DNSConstants.TYPE_MD:
- return "md";
- case DNSConstants.TYPE_MF:
- return "mf";
- case DNSConstants.TYPE_CNAME:
- return "cname";
- case DNSConstants.TYPE_SOA:
- return "soa";
- case DNSConstants.TYPE_MB:
- return "mb";
- case DNSConstants.TYPE_MG:
- return "mg";
- case DNSConstants.TYPE_MR:
- return "mr";
- case DNSConstants.TYPE_NULL:
- return "null";
- case DNSConstants.TYPE_WKS:
- return "wks";
- case DNSConstants.TYPE_PTR:
- return "ptr";
- case DNSConstants.TYPE_HINFO:
- return "hinfo";
- case DNSConstants.TYPE_MINFO:
- return "minfo";
- case DNSConstants.TYPE_MX:
- return "mx";
- case DNSConstants.TYPE_TXT:
- return "txt";
- case DNSConstants.TYPE_SRV:
- return "srv";
- case DNSConstants.TYPE_ANY:
- return "any";
- default:
- return "?";
- }
- }
-
- public String toString(String hdr, String other)
- {
- return hdr + "[" + getType(type) + "," +
- getClazz(clazz) + (unique ? "-unique," : ",") +
- name + ((other != null) ? "," +
- other + "]" : "]");
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSIncoming.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSIncoming.java
deleted file mode 100644
index 3dcedc4..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSIncoming.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * Parse an incoming DNS message into its components.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Werner Randelshofer, Pierre Frisch, Daniel Bobbert
- */
-final class DNSIncoming
-{
- private static Logger logger = Logger.getLogger(DNSIncoming.class.toString());
- // Implementation note: This vector should be immutable.
- // If a client of DNSIncoming changes the contents of this vector,
- // we get undesired results. To fix this, we have to migrate to
- // the Collections API of Java 1.2. i.e we replace Vector by List.
- // final static Vector EMPTY = new Vector();
-
- private DatagramPacket packet;
- private int off;
- private int len;
- private byte data[];
-
- int id;
- private int flags;
- private int numQuestions;
- int numAnswers;
- private int numAuthorities;
- private int numAdditionals;
- private long receivedTime;
-
- List<DNSEntry> questions;
- List<DNSRecord> answers;
-
- /**
- * Parse a message from a datagram packet.
- */
- DNSIncoming(DatagramPacket packet) throws IOException
- {
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
-
- this.packet = packet;
- this.data = packet.getData();
- this.len = packet.getLength();
- this.off = packet.getOffset();
- this.questions = new LinkedList<DNSEntry>();
- this.answers = new LinkedList<DNSRecord>();
- this.receivedTime = System.currentTimeMillis();
-
- try
- {
- id = readUnsignedShort();
- flags = readUnsignedShort();
- numQuestions = readUnsignedShort();
- numAnswers = readUnsignedShort();
- numAuthorities = readUnsignedShort();
- numAdditionals = readUnsignedShort();
-
- // parse questions
- if (numQuestions > 0)
- {
- questions =
- Collections.synchronizedList(
- new ArrayList<DNSEntry>(numQuestions));
- for (int i = 0; i < numQuestions; i++)
- {
- DNSQuestion question =
- new DNSQuestion(
- readName(),
- readUnsignedShort(),
- readUnsignedShort());
-
- questions.add(question);
- }
- }
-
- // parse answers
- int n = numAnswers + numAuthorities + numAdditionals;
- if (n > 0)
- {
- //System.out.println("JMDNS received "+n+" answers!");
- answers = Collections.synchronizedList(
- new ArrayList<DNSRecord>(n));
- for (int i = 0; i < n; i++)
- {
- String domain = readName();
- int type = readUnsignedShort();
- int clazz = readUnsignedShort();
- int ttl = readInt();
- int len = readUnsignedShort();
- int end = off + len;
- DNSRecord rec = null;
-
- switch (type)
- {
- case DNSConstants.TYPE_A: // IPv4
- case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested
- rec = new DNSRecord.Address(
- domain, type, clazz, ttl, readBytes(off, len));
- break;
- case DNSConstants.TYPE_CNAME:
- case DNSConstants.TYPE_PTR:
- rec = new DNSRecord.Pointer(
- domain, type, clazz, ttl, readName());
- break;
- case DNSConstants.TYPE_TXT:
- rec = new DNSRecord.Text(
- domain, type, clazz, ttl, readBytes(off, len));
- break;
- case DNSConstants.TYPE_SRV:
- //System.out.println("JMDNS: One is a SRV field!!");
- rec = new DNSRecord.Service( domain,
- type,
- clazz,
- ttl,
- readUnsignedShort(),
- readUnsignedShort(),
- readUnsignedShort(),
- readName());
- break;
- case DNSConstants.TYPE_HINFO:
- // Maybe we should do something with those
- break;
- default :
- logger.finer("DNSIncoming() unknown type:" + type);
- break;
- }
-
- if (rec != null)
- {
- // Add a record, if we were able to create one.
- answers.add(rec);
- }
- else
- {
- // Addjust the numbers for the skipped record
- if (answers.size() < numAnswers)
- {
- numAnswers--;
- }
- else
- {
- if (answers.size() < numAnswers + numAuthorities)
- {
- numAuthorities--;
- }
- else
- {
- if (answers.size() < numAnswers +
- numAuthorities +
- numAdditionals)
- {
- numAdditionals--;
- }
- }
- }
- }
- off = end;
- }
- }
- }
- catch (IOException e)
- {
- logger.log(Level.WARNING,
- "DNSIncoming() dump " + print(true) + "\n exception ", e);
- throw e;
- }
- }
-
- /**
- * Check if the message is a query.
- */
- boolean isQuery()
- {
- return (flags & DNSConstants.FLAGS_QR_MASK) ==
- DNSConstants.FLAGS_QR_QUERY;
- }
-
- /**
- * Check if the message is truncated.
- */
- boolean isTruncated()
- {
- return (flags & DNSConstants.FLAGS_TC) != 0;
- }
-
- /**
- * Check if the message is a response.
- */
- boolean isResponse()
- {
- return (flags & DNSConstants.FLAGS_QR_MASK) ==
- DNSConstants.FLAGS_QR_RESPONSE;
- }
-
- private int get(int off) throws IOException
- {
- if ((off < 0) || (off >= len))
- {
- throw new IOException("parser error: offset=" + off);
- }
- return data[off] & 0xFF;
- }
-
- private int readUnsignedShort() throws IOException
- {
- return (get(off++) << 8) + get(off++);
- }
-
- private int readInt() throws IOException
- {
- return (readUnsignedShort() << 16) + readUnsignedShort();
- }
-
- private byte[] readBytes(int off, int len) throws IOException
- {
- byte bytes[] = new byte[len];
- System.arraycopy(data, off, bytes, 0, len);
- return bytes;
- }
-
- private void readUTF(StringBuffer buf, int off, int len) throws IOException
- {
- for (int end = off + len; off < end;)
- {
- int ch = get(off++);
- switch (ch >> 4)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- // 0xxxxxxx
- break;
- case 12:
- case 13:
- // 110x xxxx 10xx xxxx
- ch = ((ch & 0x1F) << 6) | (get(off++) & 0x3F);
- break;
- case 14:
- // 1110 xxxx 10xx xxxx 10xx xxxx
- ch = ((ch & 0x0f) << 12) |
- ((get(off++) & 0x3F) << 6) |
- (get(off++) & 0x3F);
- break;
- default:
- // 10xx xxxx, 1111 xxxx
- ch = ((ch & 0x3F) << 4) | (get(off++) & 0x0f);
- break;
- }
- buf.append((char) ch);
- }
- }
-
- private String readName() throws IOException
- {
- StringBuffer buf = new StringBuffer();
- int off = this.off;
- int next = -1;
- int first = off;
-
- while (true)
- {
- int len = get(off++);
- if (len == 0)
- {
- break;
- }
- switch (len & 0xC0)
- {
- case 0x00:
- //buf.append("[" + off + "]");
- readUTF(buf, off, len);
- off += len;
- buf.append('.');
- break;
- case 0xC0:
- //buf.append("<" + (off - 1) + ">");
- if (next < 0)
- {
- next = off + 1;
- }
- off = ((len & 0x3F) << 8) | get(off++);
- if (off >= first)
- {
- throw new IOException(
- "bad domain name: possible circular name detected");
- }
- first = off;
- break;
- default:
- throw new IOException(
- "bad domain name: '" + buf + "' at " + off);
- }
- }
- this.off = (next >= 0) ? next : off;
- return buf.toString();
- }
-
- /**
- * Debugging.
- */
- String print(boolean dump)
- {
- StringBuffer buf = new StringBuffer();
- buf.append(toString() + "\n");
- for (Iterator<DNSEntry> iterator = questions.iterator();
- iterator.hasNext();)
- {
- buf.append(" ques:" + iterator.next() + "\n");
- }
- int count = 0;
- for (Iterator<DNSRecord> iterator = answers.iterator();
- iterator.hasNext();
- count++)
- {
- if (count < numAnswers)
- {
- buf.append(" answ:");
- }
- else
- {
- if (count < numAnswers + numAuthorities)
- {
- buf.append(" auth:");
- }
- else
- {
- buf.append(" addi:");
- }
- }
- buf.append(iterator.next() + "\n");
- }
- if (dump)
- {
- for (int off = 0, len = packet.getLength(); off < len; off += 32)
- {
- int n = Math.min(32, len - off);
- if (off < 10)
- {
- buf.append(' ');
- }
- if (off < 100)
- {
- buf.append(' ');
- }
- buf.append(off);
- buf.append(':');
- for (int i = 0; i < n; i++)
- {
- if ((i % 8) == 0)
- {
- buf.append(' ');
- }
- buf.append(Integer.toHexString((data[off + i] & 0xF0) >> 4));
- buf.append(Integer.toHexString((data[off + i] & 0x0F) >> 0));
- }
- buf.append("\n");
- buf.append(" ");
- for (int i = 0; i < n; i++)
- {
- if ((i % 8) == 0)
- {
- buf.append(' ');
- }
- buf.append(' ');
- int ch = data[off + i] & 0xFF;
- buf.append(((ch > ' ') && (ch < 127)) ? (char) ch : '.');
- }
- buf.append("\n");
-
- // limit message size
- if (off + 32 >= 256)
- {
- buf.append("....\n");
- break;
- }
- }
- }
- return buf.toString();
- }
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append(isQuery() ? "dns[query," : "dns[response,");
- if (packet.getAddress() != null)
- {
- buf.append(packet.getAddress().getHostAddress());
- }
- buf.append(':');
- buf.append(packet.getPort());
- buf.append(",len=");
- buf.append(packet.getLength());
- buf.append(",id=0x");
- buf.append(Integer.toHexString(id));
- if (flags != 0)
- {
- buf.append(",flags=0x");
- buf.append(Integer.toHexString(flags));
- if ((flags & DNSConstants.FLAGS_QR_RESPONSE) != 0)
- {
- buf.append(":r");
- }
- if ((flags & DNSConstants.FLAGS_AA) != 0)
- {
- buf.append(":aa");
- }
- if ((flags & DNSConstants.FLAGS_TC) != 0)
- {
- buf.append(":tc");
- }
- }
- if (numQuestions > 0)
- {
- buf.append(",questions=");
- buf.append(numQuestions);
- }
- if (numAnswers > 0)
- {
- buf.append(",answers=");
- buf.append(numAnswers);
- }
- if (numAuthorities > 0)
- {
- buf.append(",authorities=");
- buf.append(numAuthorities);
- }
- if (numAdditionals > 0)
- {
- buf.append(",additionals=");
- buf.append(numAdditionals);
- }
- buf.append("]");
- return buf.toString();
- }
-
- /**
- * Appends answers to this Incoming.
- *
- * @throws IllegalArgumentException If not a query or if Truncated.
- */
- void append(DNSIncoming that)
- {
- if (this.isQuery() && this.isTruncated() && that.isQuery())
- {
- if (that.numQuestions > 0) {
- if (Collections.EMPTY_LIST.equals(this.questions))
- this.questions =
- Collections.synchronizedList(
- new ArrayList<DNSEntry>(that.numQuestions));
-
- this.questions.addAll(that.questions);
- this.numQuestions += that.numQuestions;
- }
-
- if (Collections.EMPTY_LIST.equals(answers))
- {
- answers = Collections.synchronizedList(
- new ArrayList<DNSRecord>());
- }
-
- if (that.numAnswers > 0)
- {
- this.answers.addAll(this.numAnswers,
- that.answers.subList(0, that.numAnswers));
- this.numAnswers += that.numAnswers;
- }
- if (that.numAuthorities > 0)
- {
- this.answers.addAll(this.numAnswers + this.numAuthorities,
- that.answers.subList(
- that.numAnswers,
- that.numAnswers + that.numAuthorities));
- this.numAuthorities += that.numAuthorities;
- }
- if (that.numAdditionals > 0)
- {
- this.answers.addAll(
- that.answers.subList(
- that.numAnswers + that.numAuthorities,
- that.numAnswers + that.numAuthorities + that.numAdditionals));
- this.numAdditionals += that.numAdditionals;
- }
- }
- else
- {
- throw new IllegalArgumentException();
- }
- }
-
- int elapseSinceArrival()
- {
- return (int) (System.currentTimeMillis() - receivedTime);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSListener.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSListener.java
deleted file mode 100644
index d317953..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSListener.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-// REMIND: Listener should follow Java idiom for listener or have a different
-// name.
-
-/**
- * DNSListener.
- * Listener for record updates.
- *
- * @author Werner Randelshofer, Rick Blair
- * @version 1.0 May 22, 2004 Created.
- */
-public interface DNSListener
-{
- /**
- * Update a DNS record.
- * @param jmdns
- * @param now
- * @param record
- */
- public void updateRecord(JmDNS jmdns, long now, DNSRecord record);
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSOutgoing.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSOutgoing.java
deleted file mode 100644
index 4d099b8..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSOutgoing.java
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * An outgoing DNS message.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Rick Blair, Werner Randelshofer
- */
-final class DNSOutgoing
-{
- private static Logger logger =
- Logger.getLogger(DNSOutgoing.class.toString());
-
- int id;
- int flags;
- private boolean multicast;
- private int numQuestions;
- private int numAnswers;
- private int numAuthorities;
- private int numAdditionals;
- private Hashtable<String, Integer> names;
-
- byte data[];
- int off;
- int len;
-
- /**
- * Create an outgoing multicast query or response.
- */
- DNSOutgoing(int flags)
- {
- this(flags, true);
-
- }
-
- /**
- * Create an outgoing query or response.
- */
- DNSOutgoing(int flags, boolean multicast)
- {
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
-
- this.flags = flags;
- this.multicast = multicast;
- names = new Hashtable<String, Integer>();
- data = new byte[DNSConstants.MAX_MSG_TYPICAL];
- off = 12;
- }
-
- /**
- * Add a question to the message.
- */
- void addQuestion(DNSQuestion rec) throws IOException
- {
- if (numAnswers > 0 || numAuthorities > 0 || numAdditionals > 0)
- {
- throw new IllegalStateException("Questions must be added before answers");
- }
- numQuestions++;
- writeQuestion(rec);
- }
-
- /**
- * Add an answer if it is not suppressed.
- */
- void addAnswer(DNSIncoming in, DNSRecord rec) throws IOException
- {
- if (numAuthorities > 0 || numAdditionals > 0)
- {
- throw new IllegalStateException(
- "Answers must be added before authorities and additionals");
- }
- if (!rec.suppressedBy(in))
- {
- addAnswer(rec, 0);
- }
- }
-
- /**
- * Add an additional answer to the record. Omit if there is no room.
- */
- void addAdditionalAnswer(DNSIncoming in, DNSRecord rec) throws IOException
- {
- if ((off < DNSConstants.MAX_MSG_TYPICAL - 200) && !rec.suppressedBy(in))
- {
- writeRecord(rec, 0);
- numAdditionals++;
- }
- }
-
- /**
- * Add an answer to the message.
- */
- void addAnswer(DNSRecord rec, long now) throws IOException
- {
- if (numAuthorities > 0 || numAdditionals > 0)
- {
- throw new IllegalStateException(
- "Questions must be added before answers");
- }
- if (rec != null)
- {
- if ((now == 0) || !rec.isExpired(now))
- {
- writeRecord(rec, now);
- numAnswers++;
- }
- }
- }
-
- private LinkedList<DNSRecord> authorativeAnswers = new LinkedList<DNSRecord>();
-
- /**
- * Add an authorative answer to the message.
- */
- void addAuthorativeAnswer(DNSRecord rec) throws IOException
- {
- if (numAdditionals > 0)
- {
- throw new IllegalStateException(
- "Authorative answers must be added before additional answers");
- }
- authorativeAnswers.add(rec);
- writeRecord(rec, 0);
- numAuthorities++;
-
- // VERIFY:
-
- }
-
- void writeByte(int value) throws IOException
- {
- if (off >= data.length)
- {
- throw new IOException("buffer full");
- }
- data[off++] = (byte) value;
- }
-
- void writeBytes(String str, int off, int len) throws IOException
- {
- for (int i = 0; i < len; i++)
- {
- writeByte(str.charAt(off + i));
- }
- }
-
- void writeBytes(byte data[]) throws IOException
- {
- if (data != null)
- {
- writeBytes(data, 0, data.length);
- }
- }
-
- void writeBytes(byte data[], int off, int len) throws IOException
- {
- for (int i = 0; i < len; i++)
- {
- writeByte(data[off + i]);
- }
- }
-
- void writeShort(int value) throws IOException
- {
- writeByte(value >> 8);
- writeByte(value);
- }
-
- void writeInt(int value) throws IOException
- {
- writeShort(value >> 16);
- writeShort(value);
- }
-
- void writeUTF(String str, int off, int len) throws IOException
- {
- // compute utf length
- int utflen = 0;
- for (int i = 0; i < len; i++)
- {
- int ch = str.charAt(off + i);
- if ((ch >= 0x0001) && (ch <= 0x007F))
- {
- utflen += 1;
- }
- else
- {
- if (ch > 0x07FF)
- {
- utflen += 3;
- }
- else
- {
- utflen += 2;
- }
- }
- }
- // write utf length
- writeByte(utflen);
- // write utf data
- for (int i = 0; i < len; i++)
- {
- int ch = str.charAt(off + i);
- if ((ch >= 0x0001) && (ch <= 0x007F))
- {
- writeByte(ch);
- }
- else
- {
- if (ch > 0x07FF)
- {
- writeByte(0xE0 | ((ch >> 12) & 0x0F));
- writeByte(0x80 | ((ch >> 6) & 0x3F));
- writeByte(0x80 | ((ch >> 0) & 0x3F));
- }
- else
- {
- writeByte(0xC0 | ((ch >> 6) & 0x1F));
- writeByte(0x80 | ((ch >> 0) & 0x3F));
- }
- }
- }
- }
-
- void writeName(String name) throws IOException
- {
- while (true)
- {
- int n = name.indexOf('.');
- if (n < 0)
- {
- n = name.length();
- }
- if (n <= 0)
- {
- writeByte(0);
- return;
- }
- Integer offset = names.get(name);
- if (offset != null)
- {
- int val = offset.intValue();
-
- if (val > off)
- {
- logger.log(Level.WARNING,
- "DNSOutgoing writeName failed val=" + val + " name=" + name);
- }
-
- writeByte((val >> 8) | 0xC0);
- writeByte(val);
- return;
- }
- names.put(name, off);
- writeUTF(name, 0, n);
- name = name.substring(n);
- if (name.startsWith("."))
- {
- name = name.substring(1);
- }
- }
- }
-
- void writeQuestion(DNSQuestion question) throws IOException
- {
- writeName(question.name);
- writeShort(question.type);
- writeShort(question.clazz);
- }
-
- void writeRecord(DNSRecord rec, long now) throws IOException
- {
- int save = off;
- try
- {
- writeName(rec.name);
- writeShort(rec.type);
- writeShort(rec.clazz |
- ((rec.unique && multicast) ? DNSConstants.CLASS_UNIQUE : 0));
- writeInt((now == 0) ? rec.ttl : rec.getRemainingTTL(now));
- writeShort(0);
- int start = off;
- rec.write(this);
- int len = off - start;
- data[start - 2] = (byte) (len >> 8);
- data[start - 1] = (byte) (len & 0xFF);
- }
- catch (IOException e)
- {
- off = save;
- throw e;
- }
- }
-
- /**
- * Finish the message before sending it off.
- */
- void finish() throws IOException
- {
- int save = off;
- off = 0;
-
- writeShort(multicast ? 0 : id);
- writeShort(flags);
- writeShort(numQuestions);
- writeShort(numAnswers);
- writeShort(numAuthorities);
- writeShort(numAdditionals);
- off = save;
- }
-
- boolean isQuery()
- {
- return (flags & DNSConstants.FLAGS_QR_MASK) ==
- DNSConstants.FLAGS_QR_QUERY;
- }
-
- public boolean isEmpty()
- {
- return numQuestions == 0 && numAuthorities == 0
- && numAdditionals == 0 && numAnswers == 0;
- }
-
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append(isQuery() ? "dns[query," : "dns[response,");
- //buf.append(packet.getAddress().getHostAddress());
- buf.append(':');
- //buf.append(packet.getPort());
- //buf.append(",len=");
- //buf.append(packet.getLength());
- buf.append(",id=0x");
- buf.append(Integer.toHexString(id));
- if (flags != 0)
- {
- buf.append(",flags=0x");
- buf.append(Integer.toHexString(flags));
- if ((flags & DNSConstants.FLAGS_QR_RESPONSE) != 0)
- {
- buf.append(":r");
- }
- if ((flags & DNSConstants.FLAGS_AA) != 0)
- {
- buf.append(":aa");
- }
- if ((flags & DNSConstants.FLAGS_TC) != 0)
- {
- buf.append(":tc");
- }
- }
- if (numQuestions > 0)
- {
- buf.append(",questions=");
- buf.append(numQuestions);
- }
- if (numAnswers > 0)
- {
- buf.append(",answers=");
- buf.append(numAnswers);
- }
- if (numAuthorities > 0)
- {
- buf.append(",authorities=");
- buf.append(numAuthorities);
- }
- if (numAdditionals > 0)
- {
- buf.append(",additionals=");
- buf.append(numAdditionals);
- }
- buf.append(",\nnames=" + names);
- buf.append(",\nauthorativeAnswers=" + authorativeAnswers);
-
- buf.append("]");
- return buf.toString();
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSQuestion.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSQuestion.java
deleted file mode 100644
index f6abaa7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSQuestion.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.logging.*;
-
-/**
- * A DNS question.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff
- */
-public final class DNSQuestion
- extends DNSEntry
-{
- private static Logger logger =
- Logger.getLogger(DNSQuestion.class.toString());
-
- /**
- * Create a question.
- * @param name
- * @param type
- * @param clazz
- */
- public DNSQuestion(String name, int type, int clazz)
- {
- super(name, type, clazz);
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Check if this question is answered by a given DNS record.
- */
- boolean answeredBy(DNSRecord rec)
- {
- return (clazz == rec.clazz) &&
- ((type == rec.type) ||
- (type == DNSConstants.TYPE_ANY)) &&
- name.equals(rec.name);
- }
-
- /**
- * For debugging only.
- */
- @Override
- public String toString()
- {
- return toString("question", null);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSRecord.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSRecord.java
deleted file mode 100644
index 673bbc4..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSRecord.java
+++ /dev/null
@@ -1,796 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.net.*;
-import java.util.logging.*;
-
-/**
- * DNS record
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Rick Blair, Werner Randelshofer, Pierre Frisch
- */
-public abstract class DNSRecord extends DNSEntry
-{
- private static Logger logger =
- Logger.getLogger(DNSRecord.class.toString());
- int ttl;
- private long created;
-
- /**
- * Create a DNSRecord with a name, type, clazz, and ttl.
- */
- DNSRecord(String name, int type, int clazz, int ttl)
- {
- super(name, type, clazz);
- this.ttl = ttl;
- this.created = System.currentTimeMillis();
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * True if this record is the same as some other record.
- * @param other obj to be compared to.
- */
- @Override
- public boolean equals(Object other)
- {
- return (other instanceof DNSRecord) && sameAs((DNSRecord) other);
- }
-
- /**
- * True if this record is the same as some other record.
- */
- boolean sameAs(DNSRecord other)
- {
- return super.equals(other) && sameValue(other);
- }
-
- /**
- * True if this record has the same value as some other record.
- */
- abstract boolean sameValue(DNSRecord other);
-
- /**
- * True if this record has the same type as some other record.
- */
- boolean sameType(DNSRecord other)
- {
- return type == other.type;
- }
-
- /**
- * Handles a query represented by this record.
- *
- * @return Returns true if a conflict with one of the services registered
- * with JmDNS or with the hostname occured.
- */
- abstract boolean handleQuery(JmDNS dns, long expirationTime);
-
- /**
- * Handles a responserepresented by this record.
- *
- * @return Returns true if a conflict with one of the services registered
- * with JmDNS or with the hostname occured.
- */
- abstract boolean handleResponse(JmDNS dns);
-
- /**
- * Adds this as an answer to the provided outgoing datagram.
- */
- abstract DNSOutgoing addAnswer(JmDNS dns, DNSIncoming in, InetAddress addr,
- int port, DNSOutgoing out)
- throws IOException;
-
- /**
- * True if this record is suppressed by the answers in a message.
- */
- boolean suppressedBy(DNSIncoming msg)
- {
- try
- {
- for (int i = msg.numAnswers; i-- > 0;)
- {
- if (suppressedBy(msg.answers.get(i)))
- {
- return true;
- }
- }
- return false;
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- logger.log(Level.WARNING,
- "suppressedBy() message " + msg + " exception ", e);
- // msg.print(true);
- return false;
- }
- }
-
- /**
- * True if this record would be supressed by an answer.
- * This is the case if this record would not have a
- * significantly longer TTL.
- */
- boolean suppressedBy(DNSRecord other)
- {
- if (sameAs(other) && (other.ttl > ttl / 2))
- {
- return true;
- }
- return false;
- }
-
- /**
- * Get the expiration time of this record.
- */
- long getExpirationTime(int percent)
- {
- return created + (percent * ttl * 10L);
- }
-
- /**
- * Get the remaining TTL for this record.
- */
- int getRemainingTTL(long now)
- {
- return (int) Math.max(0, (getExpirationTime(100) - now) / 1000);
- }
-
- /**
- * Check if the record is expired.
- */
- boolean isExpired(long now)
- {
- return getExpirationTime(100) <= now;
- }
-
- /**
- * Check if the record is stale, ie it has outlived
- * more than half of its TTL.
- */
- boolean isStale(long now)
- {
- return getExpirationTime(50) <= now;
- }
-
- /**
- * Reset the TTL of a record. This avoids having to
- * update the entire record in the cache.
- */
- void resetTTL(DNSRecord other)
- {
- created = other.created;
- ttl = other.ttl;
- }
-
- /**
- * Write this record into an outgoing message.
- */
- abstract void write(DNSOutgoing out) throws IOException;
-
- /**
- * Address record.
- */
- static class Address extends DNSRecord
- {
- private static Logger logger =
- Logger.getLogger(Address.class.toString());
- InetAddress addr;
-
- Address(String name, int type, int clazz, int ttl, InetAddress addr)
- {
- super(name, type, clazz, ttl);
- this.addr = addr;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- Address(String name, int type, int clazz, int ttl, byte[] rawAddress)
- {
- super(name, type, clazz, ttl);
- try
- {
- this.addr = InetAddress.getByAddress(rawAddress);
- }
- catch (UnknownHostException exception)
- {
- logger.log(Level.WARNING, "Address() exception ", exception);
- }
- }
-
- @Override
- void write(DNSOutgoing out) throws IOException
- {
- if (addr != null)
- {
- byte[] buffer = addr.getAddress();
- if (DNSConstants.TYPE_A == type)
- {
- // If we have a type A records we should
- // answer with a IPv4 address
- if (addr instanceof Inet4Address)
- {
- // All is good
- }
- else
- {
- // Get the last four bytes
- byte[] tempbuffer = buffer;
- buffer = new byte[4];
- System.arraycopy(tempbuffer, 12, buffer, 0, 4);
- }
- }
- else
- {
- // If we have a type AAAA records we should
- // answer with a IPv6 address
- if (addr instanceof Inet4Address)
- {
- byte[] tempbuffer = buffer;
- buffer = new byte[16];
- for (int i = 0; i < 16; i++)
- {
- if (i < 11)
- {
- buffer[i] = tempbuffer[i - 12];
- }
- else
- {
- buffer[i] = 0;
- }
- }
- }
- }
- int length = buffer.length;
- out.writeBytes(buffer, 0, length);
- }
- }
-
- boolean same(DNSRecord other)
- {
- return ((sameName(other)) && ((sameValue(other))));
- }
-
- boolean sameName(DNSRecord other)
- {
- return name.equalsIgnoreCase(((Address) other).name);
- }
-
- @Override
- boolean sameValue(DNSRecord other)
- {
- return addr.equals(((Address) other).getAddress());
- }
-
- InetAddress getAddress()
- {
- return addr;
- }
-
- /**
- * Creates a byte array representation of this record.
- * This is needed for tie-break tests according to
- * draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2.
- */
- private byte[] toByteArray()
- {
- try
- {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- DataOutputStream dout = new DataOutputStream(bout);
- dout.write(name.getBytes("UTF8"));
- dout.writeShort(type);
- dout.writeShort(clazz);
- //dout.writeInt(len);
- byte[] buffer = addr.getAddress();
- for (int i = 0; i < buffer.length; i++)
- {
- dout.writeByte(buffer[i]);
- }
- dout.close();
- return bout.toByteArray();
- }
- catch (IOException e)
- {
- throw new InternalError();
- }
- }
-
- /**
- * Does a lexicographic comparison of the byte array representation
- * of this record and that record.
- * This is needed for tie-break tests according to
- * draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2.
- */
- private int lexCompare(DNSRecord.Address that)
- {
- byte[] thisBytes = this.toByteArray();
- byte[] thatBytes = that.toByteArray();
- for ( int i = 0, n = Math.min(thisBytes.length, thatBytes.length);
- i < n;
- i++)
- {
- if (thisBytes[i] > thatBytes[i])
- {
- return 1;
- }
- else
- {
- if (thisBytes[i] < thatBytes[i])
- {
- return -1;
- }
- }
- }
- return thisBytes.length - thatBytes.length;
- }
-
- /**
- * Does the necessary actions, when this as a query.
- */
- @Override
- boolean handleQuery(JmDNS dns, long expirationTime)
- {
- DNSRecord.Address dnsAddress =
- dns.getLocalHost().getDNSAddressRecord(this);
- if (dnsAddress != null)
- {
- if (dnsAddress.sameType(this) &&
- dnsAddress.sameName(this) &&
- (!dnsAddress.sameValue(this)))
- {
- logger.finer(
- "handleQuery() Conflicting probe detected. dns state " +
- dns.getState() +
- " lex compare " + lexCompare(dnsAddress));
- // Tie-breaker test
- if (dns.getState().isProbing() && lexCompare(dnsAddress) >= 0)
- {
- // We lost the tie-break. We have to choose a different name.
- dns.getLocalHost().incrementHostName();
- dns.getCache().clear();
- for (ServiceInfo info : dns.services.values())
- info.revertState();
- }
- dns.revertState();
- return true;
- }
- }
- return false;
- }
-
- /**
- * Does the necessary actions, when this as a response.
- */
- @Override
- boolean handleResponse(JmDNS dns)
- {
- DNSRecord.Address dnsAddress =
- dns.getLocalHost().getDNSAddressRecord(this);
- if (dnsAddress != null)
- {
- if (dnsAddress.sameType(this) &&
- dnsAddress.sameName(this) &&
- (!dnsAddress.sameValue(this)))
- {
- logger.finer("handleResponse() Denial detected");
-
- if (dns.getState().isProbing())
- {
- dns.getLocalHost().incrementHostName();
- dns.getCache().clear();
- for (ServiceInfo info : dns.services.values())
- info.revertState();
- }
- dns.revertState();
- return true;
- }
- }
- return false;
- }
-
- @Override
- DNSOutgoing addAnswer(JmDNS dns,
- DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out)
- throws IOException
- {
- return out;
- }
-
- @Override
- public String toString()
- {
- return toString(" address '" +
- (addr != null ? addr.getHostAddress() : "null") + "'");
- }
-
- }
-
- /**
- * Pointer record.
- */
- static class Pointer extends DNSRecord
- {
- private static Logger logger =
- Logger.getLogger(Pointer.class.toString());
- String alias;
-
- Pointer(String name, int type, int clazz, int ttl, String alias)
- {
- super(name, type, clazz, ttl);
- this.alias = alias;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- @Override
- void write(DNSOutgoing out) throws IOException
- {
- out.writeName(alias);
- }
-
- @Override
- boolean sameValue(DNSRecord other)
- {
- return alias.equals(((Pointer) other).alias);
- }
-
- @Override
- boolean handleQuery(JmDNS dns, long expirationTime)
- {
- // Nothing to do (?)
- // I think there is no possibility
- // for conflicts for this record type?
- return false;
- }
-
- @Override
- boolean handleResponse(JmDNS dns)
- {
- // Nothing to do (?)
- // I think there is no possibility for conflicts for this record type?
- return false;
- }
-
- String getAlias()
- {
- return alias;
- }
-
- @Override
- DNSOutgoing addAnswer(JmDNS dns,
- DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out)
- throws IOException
- {
- return out;
- }
-
- @Override
- public String toString()
- {
- return toString(alias);
- }
- }
-
- static class Text extends DNSRecord
- {
- private static Logger logger =
- Logger.getLogger(Text.class.toString());
- byte text[];
-
- Text(String name, int type, int clazz, int ttl, byte text[])
- {
- super(name, type, clazz, ttl);
- this.text = text;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- @Override
- void write(DNSOutgoing out) throws IOException
- {
- out.writeBytes(text, 0, text.length);
- }
-
- @Override
- boolean sameValue(DNSRecord other)
- {
- Text txt = (Text) other;
- if (txt.text.length != text.length)
- {
- return false;
- }
- for (int i = text.length; i-- > 0;)
- {
- if (txt.text[i] != text[i])
- {
- return false;
- }
- }
- return true;
- }
-
- @Override
- boolean handleQuery(JmDNS dns, long expirationTime)
- {
- // Nothing to do (?)
- // I think there is no possibility for conflicts for this record type?
- return false;
- }
-
- @Override
- boolean handleResponse(JmDNS dns)
- {
- // Nothing to do (?)
- // Shouldn't we care if we get a conflict at this level?
- /*
- ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase());
- if (info != null)
- {
- if (! Arrays.equals(text,info.text))
- {
- info.revertState();
- return true;
- }
- }
- */
- return false;
- }
-
- @Override
- DNSOutgoing addAnswer(JmDNS dns,
- DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out)
- throws IOException
- {
- return out;
- }
-
- @Override
- public String toString()
- {
- return toString((text.length > 10) ?
- new String(text, 0, 7) + "..." :
- new String(text));
- }
- }
-
- /**
- * Service record.
- */
- static class Service extends DNSRecord
- {
- private static Logger logger =
- Logger.getLogger(Service.class.toString());
- int priority;
- int weight;
- int port;
- String server;
-
- Service(String name,
- int type,
- int clazz,
- int ttl,
- int priority,
- int weight,
- int port,
- String server)
- {
- super(name, type, clazz, ttl);
- this.priority = priority;
- this.weight = weight;
- this.port = port;
- this.server = server;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- @Override
- void write(DNSOutgoing out) throws IOException
- {
- out.writeShort(priority);
- out.writeShort(weight);
- out.writeShort(port);
- out.writeName(server);
- }
-
- private byte[] toByteArray()
- {
- try
- {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- DataOutputStream dout = new DataOutputStream(bout);
- dout.write(name.getBytes("UTF8"));
- dout.writeShort(type);
- dout.writeShort(clazz);
- //dout.writeInt(len);
- dout.writeShort(priority);
- dout.writeShort(weight);
- dout.writeShort(port);
- dout.write(server.getBytes("UTF8"));
- dout.close();
- return bout.toByteArray();
- }
- catch (IOException e)
- {
- throw new InternalError();
- }
- }
-
- private int lexCompare(DNSRecord.Service that)
- {
- byte[] thisBytes = this.toByteArray();
- byte[] thatBytes = that.toByteArray();
- for (int i = 0, n = Math.min(thisBytes.length, thatBytes.length);
- i < n;
- i++)
- {
- if (thisBytes[i] > thatBytes[i])
- {
- return 1;
- }
- else
- {
- if (thisBytes[i] < thatBytes[i])
- {
- return -1;
- }
- }
- }
- return thisBytes.length - thatBytes.length;
- }
-
- @Override
- boolean sameValue(DNSRecord other)
- {
- Service s = (Service) other;
- return (priority == s.priority) &&
- (weight == s.weight) &&
- (port == s.port) &&
- server.equals(s.server);
- }
-
- @Override
- boolean handleQuery(JmDNS dns, long expirationTime)
- {
- ServiceInfo info = dns.services.get(name.toLowerCase());
- if (info != null &&
- (port != info.port ||
- !server.equalsIgnoreCase(dns.getLocalHost().getName())))
- {
- logger.finer("handleQuery() Conflicting probe detected");
-
- // Tie breaker test
- if (info.getState().isProbing() &&
- lexCompare(new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- dns.getLocalHost().getName())) >= 0)
- {
- // We lost the tie break
- String oldName = info.getQualifiedName().toLowerCase();
- info.setName(dns.incrementName(info.getName()));
- dns.services.remove(oldName);
- dns.services.put(info.getQualifiedName().toLowerCase(), info);
- logger.finer(
- "handleQuery() Lost tie break: new unique name chosen:" + info.getName());
-
- }
- info.revertState();
- return true;
-
- }
- return false;
- }
-
- @Override
- boolean handleResponse(JmDNS dns)
- {
- ServiceInfo info = dns.services.get(name.toLowerCase());
- if (info != null &&
- (port != info.port || !server.equalsIgnoreCase(dns.getLocalHost().getName())))
- {
- logger.finer("handleResponse() Denial detected");
-
- if (info.getState().isProbing())
- {
- String oldName = info.getQualifiedName().toLowerCase();
- info.setName(dns.incrementName(info.getName()));
- dns.services.remove(oldName);
- dns.services.put(info.getQualifiedName().toLowerCase(), info);
- logger.finer(
- "handleResponse() New unique name chose:" + info.getName());
-
- }
- info.revertState();
- return true;
- }
- return false;
- }
-
- @Override
- DNSOutgoing addAnswer(JmDNS dns,
- DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out)
- throws IOException
- {
- ServiceInfo info = dns.services.get(name.toLowerCase());
- if (info != null)
- {
- if (this.port == info.port != server.equals(dns.getLocalHost().getName()))
- {
- return dns.addAnswer(in, addr, port, out,
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- dns.getLocalHost().getName()));
- }
- }
- return out;
- }
-
- @Override
- public String toString()
- {
- return toString(server + ":" + port);
- }
- }
-
- public String toString(String other)
- {
- return toString("record", ttl + "/" +
- getRemainingTTL(System.currentTimeMillis())
-// + "," + other
- );
- }
-}
-
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSState.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSState.java
deleted file mode 100644
index 5016050..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSState.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * DNSState defines the possible states for services registered with JmDNS.
- *
- * @author Werner Randelshofer, Rick Blair
- * @version 1.0 May 23, 2004 Created.
- */
-public class DNSState
- implements Comparable<DNSState>
-{
- private static Logger logger =
- Logger.getLogger(DNSState.class.toString());
-
- private final String name;
-
- /**
- * Ordinal of next state to be created.
- */
- private static int nextOrdinal = 0;
- /**
- * Assign an ordinal to this state.
- */
- private final int ordinal = nextOrdinal++;
- /**
- * Logical sequence of states.
- * The sequence is consistent with the ordinal of a state.
- * This is used for advancing through states.
- */
- private final static ArrayList<DNSState> sequence
- = new ArrayList<DNSState>();
-
- private DNSState(String name)
- {
- this.name = name;
- sequence.add(this);
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- @Override
- public final String toString()
- {
- return name;
- }
-
- public static final DNSState PROBING_1 = new DNSState("probing 1");
- public static final DNSState PROBING_2 = new DNSState("probing 2");
- public static final DNSState PROBING_3 = new DNSState("probing 3");
- public static final DNSState ANNOUNCING_1 = new DNSState("announcing 1");
- public static final DNSState ANNOUNCING_2 = new DNSState("announcing 2");
- public static final DNSState ANNOUNCED = new DNSState("announced");
- public static final DNSState CANCELED = new DNSState("canceled");
-
- /**
- * Returns the next advanced state.
- * In general, this advances one step in the following sequence: PROBING_1,
- * PROBING_2, PROBING_3, ANNOUNCING_1, ANNOUNCING_2, ANNOUNCED.
- * Does not advance for ANNOUNCED and CANCELED state.
- * @return Returns the next advanced state.
- */
- public final DNSState advance()
- {
- return (isProbing() || isAnnouncing()) ?
- sequence.get(ordinal + 1) :
- this;
- }
-
- /**
- * Returns to the next reverted state.
- * All states except CANCELED revert to PROBING_1.
- * Status CANCELED does not revert.
- * @return Returns to the next reverted state.
- */
- public final DNSState revert()
- {
- return (this == CANCELED) ? this : PROBING_1;
- }
-
- /**
- * Returns true, if this is a probing state.
- * @return Returns true, if this is a probing state.
- */
- public boolean isProbing()
- {
- return compareTo(PROBING_1) >= 0 && compareTo(PROBING_3) <= 0;
- }
-
- /**
- * Returns true, if this is an announcing state.
- * @return Returns true, if this is an announcing state.
- */
- public boolean isAnnouncing()
- {
- return compareTo(ANNOUNCING_1) >= 0 && compareTo(ANNOUNCING_2) <= 0;
- }
-
- /**
- * Returns true, if this is an announced state.
- * @return Returns true, if this is an announced state.
- */
- public boolean isAnnounced()
- {
- return compareTo(ANNOUNCED) == 0;
- }
-
- /**
- * Compares two states.
- * The states compare as follows:
- * PROBING_1 &lt; PROBING_2 &lt; PROBING_3 &lt; ANNOUNCING_1 &lt;
- * ANNOUNCING_2 &lt; RESPONDING &lt; ANNOUNCED &lt; CANCELED.
- */
- public int compareTo(DNSState state)
- {
- return ordinal - state.ordinal;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/HostInfo.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/HostInfo.java
deleted file mode 100644
index 644afc9..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/HostInfo.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.net.*;
-import java.util.logging.*;
-
-
-/**
- * HostInfo information on the local host to be able to cope with change of addresses.
- *
- * @version %I%, %G%
- * @author Pierre Frisch, Werner Randelshofer
- */
-class HostInfo
-{
- private static Logger logger = Logger.getLogger(HostInfo.class.toString());
- protected String name;
- protected InetAddress address;
- protected NetworkInterface interfaze;
- /**
- * This is used to create a unique name for the host name.
- */
- private int hostNameCount;
-
- public HostInfo(InetAddress address, String name)
- {
- super();
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
-
- this.address = address;
- this.name = name;
- if (address != null)
- {
- try
- {
- interfaze = NetworkInterface.getByInetAddress(address);
- }
- catch (Exception exception)
- {
- // FIXME Shouldn't we take an action here?
- logger.log(Level.WARNING,
- "LocalHostInfo() exception ", exception);
- }
- }
- }
-
- public String getName()
- {
- return name;
- }
-
- public InetAddress getAddress()
- {
- return address;
- }
-
- public NetworkInterface getInterface()
- {
- return interfaze;
- }
-
- synchronized String incrementHostName()
- {
- hostNameCount++;
- int plocal = name.indexOf(".local.");
- int punder = name.lastIndexOf("-");
- name = name.substring(0, (punder == -1 ? plocal : punder)) + "-" +
- hostNameCount + ".local.";
- return name;
- }
-
- boolean shouldIgnorePacket(DatagramPacket packet)
- {
- boolean result = false;
- if (getAddress() != null)
- {
- InetAddress from = packet.getAddress();
- if (from != null)
- {
- if (from.isLinkLocalAddress() &&
- (!getAddress().isLinkLocalAddress()))
- {
- // Ignore linklocal packets on regular interfaces, unless this is
- // also a linklocal interface. This is to avoid duplicates. This is
- // a terrible hack caused by the lack of an API to get the address
- // of the interface on which the packet was received.
- result = true;
- }
- if (from.isLoopbackAddress() &&
- (!getAddress().isLoopbackAddress()))
- {
- // Ignore loopback packets on a regular interface unless this is
- // also a loopback interface.
- result = true;
- }
- }
- }
- return result;
- }
-
- DNSRecord.Address getDNSAddressRecord(DNSRecord.Address address)
- {
- return (DNSConstants.TYPE_AAAA == address.type ?
- getDNS6AddressRecord() :
- getDNS4AddressRecord());
- }
-
- DNSRecord.Address getDNS4AddressRecord()
- {
- if ((getAddress() != null) &&
- ((getAddress() instanceof Inet4Address) ||
- ((getAddress() instanceof Inet6Address) &&
- (((Inet6Address) getAddress()).isIPv4CompatibleAddress()))))
- {
- return new DNSRecord.Address(getName(),
- DNSConstants.TYPE_A,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL, getAddress());
- }
- return null;
- }
-
- DNSRecord.Address getDNS6AddressRecord()
- {
- if ((getAddress() != null) && (getAddress() instanceof Inet6Address))
- {
- return new DNSRecord.Address(
- getName(),
- DNSConstants.TYPE_AAAA,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- getAddress());
- }
- return null;
- }
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append("local host info[");
- buf.append(getName() != null ? getName() : "no name");
- buf.append(", ");
- buf.append(getInterface() != null ?
- getInterface().getDisplayName() :
- "???");
- buf.append(":");
- buf.append(getAddress() != null ?
- getAddress().getHostAddress() :
- "no address");
- buf.append("]");
- return buf.toString();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/JmDNS.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/JmDNS.java
deleted file mode 100644
index 96420ba..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/JmDNS.java
+++ /dev/null
@@ -1,3048 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.util.*;
-
-// REMIND: multiple IP addresses
-
-/**
- * mDNS implementation in Java.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Rick Blair, Jeff Sonstein,
- * Werner Randelshofer, Pierre Frisch, Scott Lewis
- * @author Christian Vincenot
- */
-public class JmDNS
-{
- private static final Logger logger
- = Logger.getLogger(JmDNS.class);
-
- /**
- * The version of JmDNS.
- */
- public static String VERSION = "2.0";
-
- /**
- * This is the multicast group, we are listening to for
- * multicast DNS messages.
- */
- private InetAddress group;
- /**
- * This is our multicast socket.
- */
- private MulticastSocket socket;
-
- /**
- * Used to fix live lock problem on unregester.
- */
-
- protected boolean closed = false;
-
- /**
- * Holds instances of JmDNS.DNSListener.
- * Must by a synchronized collection, because it is updated from
- * concurrent threads.
- */
- private List<DNSListener> listeners;
- /**
- * Holds instances of ServiceListener's.
- * Keys are Strings holding a fully qualified service type.
- * Values are LinkedList's of ServiceListener's.
- */
- private Map<String, List<ServiceListener>> serviceListeners;
- /**
- * Holds instances of ServiceTypeListener's.
- */
- private List<ServiceTypeListener> typeListeners;
-
-
- /**
- * Cache for DNSEntry's.
- */
- private DNSCache cache;
-
- /**
- * This hashtable holds the services that have been registered.
- * Keys are instances of String which hold an all lower-case version of the
- * fully qualified service name.
- * Values are instances of ServiceInfo.
- */
- Map<String, ServiceInfo> services;
-
- /**
- * This hashtable holds the service types that have been registered or
- * that have been received in an incoming datagram.
- * Keys are instances of String which hold an all lower-case version of the
- * fully qualified service type.
- * Values hold the fully qualified service type.
- */
- Map<String, String> serviceTypes;
-
- /**
- * Handle on the local host
- */
- HostInfo localHost;
-
- private Thread incomingListener = null;
-
- /**
- * Throttle count.
- * This is used to count the overall number of probes sent by JmDNS.
- * When the last throttle increment happened .
- */
- private int throttle;
- /**
- * Last throttle increment.
- */
- private long lastThrottleIncrement;
-
- /**
- * The timer is used to dispatch all outgoing messages of JmDNS.
- * It is also used to dispatch maintenance tasks for the DNS cache.
- */
- private Timer timer;
-
- /**
- * The source for random values.
- * This is used to introduce random delays in responses. This reduces the
- * potential for collisions on the network.
- */
- private final static Random random = new Random();
-
- /**
- * This lock is used to coordinate processing of incoming and outgoing
- * messages. This is needed, because the Rendezvous Conformance Test
- * does not forgive race conditions.
- */
- private Object ioLock = new Object();
-
- /**
- * If an incoming package which needs an answer is truncated, we store it
- * here. We add more incoming DNSRecords to it, until the JmDNS.Responder
- * timer picks it up.
- * Remind: This does not work well with multiple planned answers for packages
- * that came in from different clients.
- */
- private DNSIncoming plannedAnswer;
-
- // State machine
- /**
- * The state of JmDNS.
- * <p/>
- * For proper handling of concurrency, this variable must be
- * changed only using methods advanceState(), revertState() and cancel().
- */
- private DNSState state = DNSState.PROBING_1;
-
- /**
- * Timer task associated to the host name.
- * This is used to prevent from having multiple tasks associated to the host
- * name at the same time.
- */
- TimerTask task;
-
- /**
- * This hashtable is used to maintain a list of service types being collected
- * by this JmDNS instance.
- * The key of the hashtable is a service type name, the value is an instance
- * of JmDNS.ServiceCollector.
- *
- * @see #list
- */
- private HashMap<String, ServiceCollector> serviceCollectors = new HashMap<String, ServiceCollector>();
-
- /**
- * Create an instance of JmDNS.
- * @throws java.io.IOException
- */
- public JmDNS()
- throws IOException
- {
- //String SLevel = System.getProperty("jmdns.debug");
-
- if (logger.isDebugEnabled())
- logger.debug("JmDNS instance created");
- try
- {
- InetAddress addr = InetAddress.getLocalHost();
- // [PJYF Oct 14 2004] Why do we disallow the loopback address?
- init(addr.isLoopbackAddress() ? null : addr, addr.getHostName());
- }
- catch (IOException exc)
- {
- logger.error("Failed to get a reference to localhost", exc);
- init(null, "computer");
- }
- }
-
- /**
- * Create an instance of JmDNS and bind it to a
- * specific network interface given its IP-address.
- * @param addr
- * @throws java.io.IOException
- */
- public JmDNS(InetAddress addr)
- throws IOException
- {
- try
- {
- init(addr, addr.getHostName());
- }
- catch (IOException e)
- {
- init(null, "computer");
- }
- }
-
- /**
- * Initialize everything.
- *
- * @param address The interface to which JmDNS binds to.
- * @param name The host name of the interface.
- */
- private void init(InetAddress address, String name) throws IOException
- {
- // A host name with "." is illegal.
- // so strip off everything and append .local.
- int idx = name.indexOf(".");
- if (idx > 0)
- {
- name = name.substring(0, idx);
- }
- name += ".local.";
- // localHost to IP address binding
- localHost = new HostInfo(address, name);
-
- cache = new DNSCache(100);
-
- listeners = Collections.synchronizedList(new ArrayList<DNSListener>());
- serviceListeners = new HashMap<String, List<ServiceListener>>();
- typeListeners = new ArrayList<ServiceTypeListener>();
-
- services = new Hashtable<String, ServiceInfo>(20);
- serviceTypes = new Hashtable<String, String>(20);
-
- // REMIND: If I could pass in a name for the Timer thread,
- // I would pass 'JmDNS.Timer'.
- timer = new Timer();
- new RecordReaper().start();
-
- incomingListener = new Thread(
- new SocketListener(), "JmDNS.SocketListener");
- incomingListener.setDaemon(true);
- // Bind to multicast socket
- openMulticastSocket(localHost);
- start(services.values());
- }
-
- private void start(Collection<ServiceInfo> serviceInfos)
- {
- state = DNSState.PROBING_1;
- incomingListener.start();
- new Prober().start();
- for (ServiceInfo serviceInfo : serviceInfos)
- {
- try
- {
- registerService(new ServiceInfo(serviceInfo));
- }
- catch (Exception exception)
- {
- logger.warn("start() Registration exception ", exception);
- }
- }
- }
-
- private void openMulticastSocket(HostInfo hostInfo) throws IOException
- {
- if (group == null)
- {
- group = InetAddress.getByName(DNSConstants.MDNS_GROUP);
- }
- if (socket != null)
- {
- this.closeMulticastSocket();
- }
- socket = new MulticastSocket(DNSConstants.MDNS_PORT);
- if ((hostInfo != null) && (localHost.getInterface() != null))
- {
- socket.setNetworkInterface(hostInfo.getInterface());
- }
- socket.setTimeToLive(255);
- socket.joinGroup(group);
- }
-
- private void closeMulticastSocket()
- {
- if (logger.isDebugEnabled())
- logger.debug("closeMulticastSocket()");
- if (socket != null)
- {
- // close socket
- try
- {
- socket.leaveGroup(group);
- socket.close();
- if (incomingListener != null)
- {
- incomingListener.join();
- }
- }
- catch (Exception exception)
- {
- logger.warn("closeMulticastSocket() Close socket exception ",
- exception);
- }
- socket = null;
- }
- }
-
- // State machine
- /**
- * Sets the state and notifies all objects that wait on JmDNS.
- */
- synchronized void advanceState()
- {
- state = state.advance();
- notifyAll();
- }
-
- /**
- * Sets the state and notifies all objects that wait on JmDNS.
- */
- synchronized void revertState()
- {
- state = state.revert();
- notifyAll();
- }
-
- /**
- * Sets the state and notifies all objects that wait on JmDNS.
- */
- synchronized void cancel()
- {
- state = DNSState.CANCELED;
- notifyAll();
- }
-
- /**
- * Returns the current state of this info.
- */
- DNSState getState()
- {
- return state;
- }
-
-
- /**
- * Return the DNSCache associated with the cache variable
- */
- DNSCache getCache()
- {
- return cache;
- }
-
- /**
- * Return the HostName associated with this JmDNS instance.
- * Note: May not be the same as what started. The host name is subject to
- * negotiation.
- * @return Return the HostName associated with this JmDNS instance.
- */
- public String getHostName()
- {
- return localHost.getName();
- }
-
- public HostInfo getLocalHost()
- {
- return localHost;
- }
-
- /**
- * Return the address of the interface to which this instance of JmDNS is
- * bound.
- * @return Return the address of the interface to which this instance
- * of JmDNS is bound.
- * @throws java.io.IOException
- */
- public InetAddress getInterface()
- throws IOException
- {
- return socket.getInterface();
- }
-
- /**
- * Get service information. If the information is not cached, the method
- * will block until updated information is received.
- * <p/>
- * Usage note: Do not call this method from the AWT event dispatcher thread.
- * You will make the user interface unresponsive.
- *
- * @param type fully qualified service type,
- * such as <code>_http._tcp.local.</code> .
- * @param name unqualified service name, such as <code>foobar</code> .
- * @return null if the service information cannot be obtained
- */
- public ServiceInfo getServiceInfo(String type, String name)
- {
- return getServiceInfo(type, name, 3 * 1000);
- }
-
- /**
- * Get service information. If the information is not cached, the method
- * will block for the given timeout until updated information is received.
- * <p/>
- * Usage note: If you call this method from the AWT event dispatcher thread,
- * use a small timeout, or you will make the user interface unresponsive.
- *
- * @param type full qualified service type,
- * such as <code>_http._tcp.local.</code> .
- * @param name unqualified service name, such as <code>foobar</code> .
- * @param timeout timeout in milliseconds
- * @return null if the service information cannot be obtained
- */
- public ServiceInfo getServiceInfo(String type, String name, int timeout)
- {
- ServiceInfo info = new ServiceInfo(type, name);
- new ServiceInfoResolver(info).start();
-
- try
- {
- long end = System.currentTimeMillis() + timeout;
- long delay;
- synchronized (info)
- {
- while (!info.hasData() &&
- (delay = end - System.currentTimeMillis()) > 0)
- {
- info.wait(delay);
- }
- }
- }
- catch (InterruptedException e)
- {
- // empty
- }
-
- return (info.hasData()) ? info : null;
- }
-
- /**
- * Request service information. The information about the service is
- * requested and the ServiceListener.resolveService method is called as soon
- * as it is available.
- * <p/>
- * Usage note: Do not call this method from the AWT event dispatcher thread.
- * You will make the user interface unresponsive.
- *
- * @param type full qualified service type,
- * such as <code>_http._tcp.local.</code> .
- * @param name unqualified service name, such as <code>foobar</code> .
- */
- public void requestServiceInfo(String type, String name)
- {
- requestServiceInfo(type, name, 3 * 1000);
- }
-
- /**
- * Request service information. The information about the service
- * is requested and the ServiceListener.resolveService method is
- * called as soon as it is available.
- *
- * @param type full qualified service type,
- * such as <code>_http._tcp.local.</code> .
- * @param name unqualified service name, such as <code>foobar</code> .
- * @param timeout timeout in milliseconds
- */
- public void requestServiceInfo(String type, String name, int timeout)
- {
- registerServiceType(type);
- ServiceInfo info = new ServiceInfo(type, name);
- new ServiceInfoResolver(info).start();
-
- try
- {
- long end = System.currentTimeMillis() + timeout;
- long delay;
- synchronized (info)
- {
- while (!info.hasData() &&
- (delay = end - System.currentTimeMillis()) > 0)
- {
- info.wait(delay);
- }
- }
- }
- catch (InterruptedException e)
- {
- // empty
- }
- }
-
- void handleServiceResolved(ServiceInfo info)
- {
- List<ServiceListener> list = serviceListeners.get(info.type.toLowerCase());
- if (list != null)
- {
- ServiceEvent event =
- new ServiceEvent(this, info.type, info.getName(), info);
- // Iterate on a copy in case listeners will modify it
- List<ServiceListener> listCopy
- = new ArrayList<ServiceListener> (list);
- for (ServiceListener serviceListener : listCopy)
- serviceListener.serviceResolved(event);
- }
- }
-
- /**
- * Listen for service types.
- *
- * @param listener listener for service types
- * @throws java.io.IOException
- */
- public void addServiceTypeListener(ServiceTypeListener listener)
- throws IOException
- {
- synchronized (this)
- {
- typeListeners.remove(listener);
- typeListeners.add(listener);
- }
-
- // report cached service types
- for (String serviceType : serviceTypes.values())
- {
- listener.serviceTypeAdded(
- new ServiceEvent(this, serviceType, null, null));
- }
-
- new TypeResolver().start();
- }
-
- /**
- * Remove listener for service types.
- *
- * @param listener listener for service types
- */
- public void removeServiceTypeListener(ServiceTypeListener listener)
- {
- synchronized (this)
- {
- typeListeners.remove(listener);
- }
- }
-
- /**
- * Listen for services of a given type. The type has to be a fully
- * qualified type name such as <code>_http._tcp.local.</code>.
- *
- * @param type full qualified service type,
- * such as <code>_http._tcp.local.</code>.
- * @param listener listener for service updates
- */
- public void addServiceListener(String type, ServiceListener listener)
- {
- String lotype = type.toLowerCase();
- removeServiceListener(lotype, listener);
- List<ServiceListener> list = null;
- synchronized (this)
- {
- list = serviceListeners.get(lotype);
- if (list == null)
- {
- list = Collections.synchronizedList(new LinkedList<ServiceListener>());
- serviceListeners.put(lotype, list);
- }
- list.add(listener);
- }
-
- // report cached service types
- for (Iterator<DNSCache.CacheNode> i = cache.iterator(); i.hasNext();)
- {
- for (DNSCache.CacheNode n = i.next(); n != null; n = n.next())
- {
- DNSRecord rec = (DNSRecord) n.getValue();
- if (rec.type == DNSConstants.TYPE_SRV)
- {
- if (rec.name.endsWith(type))
- {
- listener.serviceAdded(
- new ServiceEvent(
- this,
- type,
- toUnqualifiedName(type, rec.name),
- null));
- }
- }
- }
- }
- new ServiceResolver(type).start();
- }
-
- /**
- * Remove listener for services of a given type.
- *
- * @param type of listener to be removed
- * @param listener listener for service updates
- */
- public void removeServiceListener(String type, ServiceListener listener)
- {
- type = type.toLowerCase();
- List<ServiceListener> list = serviceListeners.get(type);
- if (list != null)
- {
- synchronized (this)
- {
- list.remove(listener);
- if (list.size() == 0)
- {
- serviceListeners.remove(type);
- }
- }
- }
- }
-
- /**
- * Register a service. The service is registered
- * for access by other jmdns clients.
- * The name of the service may be changed to make it unique.
- * @param info of service
- * @throws java.io.IOException
- */
- public void registerService(ServiceInfo info) throws IOException
- {
- registerServiceType(info.type);
-
- // bind the service to this address
- info.server = localHost.getName();
- info.addr = localHost.getAddress();
-
- synchronized (this)
- {
- makeServiceNameUnique(info);
- services.put(info.getQualifiedName().toLowerCase(), info);
- }
-
- new /*Service*/Prober().start();
- try
- {
- synchronized (info)
- {
- while (info.getState().compareTo(DNSState.ANNOUNCED) < 0)
- {
- info.wait();
- }
- }
- }
- catch (InterruptedException e)
- {
- logger.error(e.getMessage(), e);
- }
- if (logger.isDebugEnabled())
- logger.debug("registerService() JmDNS registered service as " + info);
- }
-
- /**
- * Unregister a service. The service should have been registered.
- * @param info of service
- */
- public void unregisterService(ServiceInfo info)
- {
- synchronized (this)
- {
- services.remove(info.getQualifiedName().toLowerCase());
- }
- info.cancel();
-
- // Note: We use this lock object to synchronize on it.
- // Synchronizing on another object (e.g. the ServiceInfo) does
- // not make sense, because the sole purpose of the lock is to
- // wait until the canceler has finished. If we synchronized on
- // the ServiceInfo or on the Canceler, we would block all
- // accesses to synchronized methods on that object. This is not
- // what we want!
- Object lock = new Object();
- new Canceler(info, lock).start();
-
- // Remind: We get a deadlock here, if the Canceler does not run!
- try
- {
- synchronized (lock)
- {
- lock.wait();
- }
- }
- catch (InterruptedException e)
- {
- // empty
- }
- }
-
- /**
- * Unregister all services.
- */
- public void unregisterAllServices()
- {
- if (logger.isDebugEnabled())
- logger.debug("unregisterAllServices()");
- if (services.size() == 0)
- {
- return;
- }
-
- Collection<ServiceInfo> list;
- synchronized (this)
- {
- list = new LinkedList<ServiceInfo>(services.values());
- services.clear();
- }
- for (Iterator<ServiceInfo> iterator = list.iterator(); iterator.hasNext();)
- {
- iterator.next().cancel();
- }
-
-
- Object lock = new Object();
- new Canceler(list, lock).start();
- // Remind: We get a livelock here, if the Canceler does not run!
- try
- {
- synchronized (lock)
- {
- if (!closed)
- {
- lock.wait();
- }
- }
- }
- catch (InterruptedException e)
- {
- // empty
- }
- }
-
- /**
- * Register a service type. If this service type was not already known,
- * all service listeners will be notified of the new service type.
- * Service types are automatically registered as they are discovered.
- * @param type of service
- */
- public void registerServiceType(String type)
- {
- String name = type.toLowerCase();
- if (serviceTypes.get(name) == null)
- {
- if ((type.indexOf("._mdns._udp.") < 0) &&
- !type.endsWith(".in-addr.arpa."))
- {
- Collection<ServiceTypeListener> list;
- synchronized (this)
- {
- serviceTypes.put(name, type);
- list = new LinkedList<ServiceTypeListener>(typeListeners);
- }
- for (ServiceTypeListener listener : list)
- listener
- .serviceTypeAdded(
- new ServiceEvent(this, type, null, null));
- }
- }
- }
-
- /**
- * Generate a possibly unique name for a service using the information we
- * have in the cache.
- *
- * @return returns true, if the name of the service info had to be changed.
- */
- private boolean makeServiceNameUnique(ServiceInfo info)
- {
- String originalQualifiedName = info.getQualifiedName();
- long now = System.currentTimeMillis();
-
- boolean collision;
- do
- {
- collision = false;
-
- // Check for collision in cache
- for (DNSCache.CacheNode j = cache.find(
- info.getQualifiedName().toLowerCase());
- j != null;
- j = j.next())
- {
- DNSRecord a = (DNSRecord) j.getValue();
- if ((a.type == DNSConstants.TYPE_SRV) && !a.isExpired(now))
- {
- DNSRecord.Service s = (DNSRecord.Service) a;
- if (s.port != info.port || !s.server.equals(localHost.getName()))
- {
- if (logger.isDebugEnabled())
- logger.debug("makeServiceNameUnique() " +
- "JmDNS.makeServiceNameUnique srv collision:" +
- a + " s.server=" + s.server + " " +
- localHost.getName() + " equals:" +
- (s.server.equals(localHost.getName())));
- info.setName(incrementName(info.getName()));
- collision = true;
- break;
- }
- }
- }
-
- // Check for collision with other service infos published by JmDNS
- Object selfService =
- services.get(info.getQualifiedName().toLowerCase());
- if (selfService != null && selfService != info)
- {
- info.setName(incrementName(info.getName()));
- collision = true;
- }
- }
- while (collision);
-
- return !(originalQualifiedName.equals(info.getQualifiedName()));
- }
-
- String incrementName(String name)
- {
- try
- {
- int l = name.lastIndexOf('(');
- int r = name.lastIndexOf(')');
- if ((l >= 0) && (l < r))
- {
- name = name.substring(0, l) + "(" +
- (Integer.parseInt(name.substring(l + 1, r)) + 1) + ")";
- }
- else
- {
- name += " (2)";
- }
- }
- catch (NumberFormatException e)
- {
- name += " (2)";
- }
- return name;
- }
-
- /**
- * Add a listener for a question. The listener will receive updates
- * of answers to the question as they arrive, or from the cache if they
- * are already available.
- * @param listener to be added
- * @param question - which the listener is responsible for.
- */
- public void addListener(DNSListener listener, DNSQuestion question)
- {
- long now = System.currentTimeMillis();
-
- // add the new listener
- synchronized (this)
- {
- listeners.add(listener);
- }
-
- // report existing matched records
- if (question != null)
- {
- for (DNSCache.CacheNode i = cache.find(question.name);
- i != null;
- i = i.next())
- {
- DNSRecord c = (DNSRecord) i.getValue();
- if (question.answeredBy(c) && !c.isExpired(now))
- {
- listener.updateRecord(this, now, c);
- }
- }
- }
- }
-
- /**
- * Remove a listener from all outstanding questions.
- * The listener will no longer receive any updates.
- */
- void removeListener(DNSListener listener)
- {
- synchronized (this)
- {
- listeners.remove(listener);
- }
- }
-
-
- // Remind: Method updateRecord should receive a better name.
- /**
- * Notify all listeners that a record was updated.
- */
- void updateRecord(long now, DNSRecord rec)
- {
- // We do not want to block the entire DNS
- // while we are updating the record for each listener (service info)
- List<DNSListener> listenerList = null;
- synchronized (this)
- {
- listenerList = new ArrayList<DNSListener>(listeners);
- }
-
- //System.out.println("OUT OF MUTEX!!!!!");
-
- for (DNSListener listener : listenerList)
- listener.updateRecord(this, now, rec);
-
- if (rec.type == DNSConstants.TYPE_PTR ||
- rec.type == DNSConstants.TYPE_SRV)
- {
- List<ServiceListener> serviceListenerList = null;
- synchronized (this)
- {
- serviceListenerList = serviceListeners.get(rec.name.toLowerCase());
- // Iterate on a copy in case listeners will modify it
- if (serviceListenerList != null)
- {
- serviceListenerList = new ArrayList<ServiceListener>(serviceListenerList);
- }
- }
- if (serviceListenerList != null)
- {
- boolean expired = rec.isExpired(now);
- String type = rec.getName();
- String name = ((DNSRecord.Pointer) rec).getAlias();
- // DNSRecord old = (DNSRecord)services.get(name.toLowerCase());
- if (!expired)
- {
- // new record
- ServiceEvent event =
- new ServiceEvent(
- this,
- type,
- toUnqualifiedName(type, name),
- null);
- for (Iterator<ServiceListener> iterator = serviceListenerList.iterator();
- iterator.hasNext();)
- {
- iterator.next().serviceAdded(event);
- }
- }
- else
- {
- // expire record
- ServiceEvent event =
- new ServiceEvent(
- this,
- type,
- toUnqualifiedName(type, name),
- null);
- for (Iterator<ServiceListener> iterator = serviceListenerList.iterator();
- iterator.hasNext();)
- {
- iterator.next().serviceRemoved(event);
- }
- }
- }
- }
- }
-
- /**
- * Handle an incoming response. Cache answers, and pass them on to
- * the appropriate questions.
- */
- private void handleResponse(DNSIncoming msg)
- throws IOException
- {
- long now = System.currentTimeMillis();
-
- boolean hostConflictDetected = false;
- boolean serviceConflictDetected = false;
-
- if (logger.isTraceEnabled())
- logger.trace("JMDNS/handleResponse received " +
- msg.answers.size()+ " messages");
- for (DNSRecord rec : msg.answers)
- {
- if (logger.isTraceEnabled())
- logger.trace("PRINT: "+ rec);
- //cache.add(rec);
- }
-
- for (DNSRecord rec : msg.answers)
- {
- boolean isInformative = false;
- boolean expired = rec.isExpired(now);
-
- if (logger.isTraceEnabled())
- logger.trace("JMDNS received : " + rec + " expired: "+expired);
-
- // update the cache
- DNSRecord c = (DNSRecord) cache.get(rec);
- if (c != null)
- {
- if (logger.isTraceEnabled())
- logger.trace("JMDNS has found "+rec+" in cache");
- if (expired)
- {
- isInformative = true;
- cache.remove(c);
- }
- else
- {
- /* Special case for SIP Communicator.
- * We want to be informed if a cache entry is modified
- */
-// if ((c.isUnique()
-// && c.getType() == DNSConstants.TYPE_TXT
-// && ((c.getClazz() & DNSConstants.CLASS_IN) != 0)))
-// isInformative = true;
-// c.resetTTL(rec);
-// rec = c;
- if (logger.isTraceEnabled())
- logger.trace(
- new Boolean(c.isUnique()).toString() +
- c.getType()+c.getClazz() + "/" +
- DNSConstants.TYPE_TXT + " "+DNSConstants.CLASS_IN);
-
- if ((rec.isUnique()
- && ((rec.getType() & DNSConstants.TYPE_TXT) != 0)
- && ((rec.getClazz() & DNSConstants.CLASS_IN) != 0)))
- {
- if (logger.isTraceEnabled())
- logger.trace("UPDATING CACHE !! ");
- isInformative = true;
- cache.remove(c);
- cache.add(rec);
- }
- else
- {
- c.resetTTL(rec);
- rec = c;
- }
- }
- }
- else
- {
- if (!expired)
- {
- isInformative = true;
- if (logger.isTraceEnabled())
- logger.trace("Adding "+rec+" to the cache");
- cache.add(rec);
- }
- }
- switch (rec.type)
- {
- case DNSConstants.TYPE_PTR:
- // handle _mdns._udp records
- if (rec.getName().indexOf("._mdns._udp.") >= 0)
- {
- if (!expired &&
- rec.name.startsWith("_services._mdns._udp."))
- {
- isInformative = true;
- registerServiceType(((DNSRecord.Pointer)rec).alias);
- }
- continue;
- }
- registerServiceType(rec.name);
- break;
- }
-
-
- if ((rec.getType() == DNSConstants.TYPE_A) ||
- (rec.getType() == DNSConstants.TYPE_AAAA))
- {
- hostConflictDetected |= rec.handleResponse(this);
- }
- else
- {
- serviceConflictDetected |= rec.handleResponse(this);
- }
-
- // notify the listeners
- if (isInformative)
- {
- updateRecord(now, rec);
- }
-
-
- }
-
- if (hostConflictDetected || serviceConflictDetected)
- {
- new Prober().start();
- }
- }
-
- /**
- * Handle an incoming query. See if we can answer any part of it
- * given our service infos.
- */
- private void handleQuery(DNSIncoming in, InetAddress addr, int port)
- throws IOException
- {
- // Track known answers
- boolean hostConflictDetected = false;
- boolean serviceConflictDetected = false;
- long expirationTime = System.currentTimeMillis() +
- DNSConstants.KNOWN_ANSWER_TTL;
- for (DNSRecord answer : in.answers)
- {
- if ((answer.getType() == DNSConstants.TYPE_A) ||
- (answer.getType() == DNSConstants.TYPE_AAAA))
- {
- hostConflictDetected |=
- answer.handleQuery(this, expirationTime);
- }
- else
- {
- serviceConflictDetected |=
- answer.handleQuery(this, expirationTime);
- }
- }
-
- if (plannedAnswer != null)
- {
- plannedAnswer.append(in);
- }
- else
- {
- if (in.isTruncated())
- {
- plannedAnswer = in;
- }
-
- new Responder(in, addr, port).start();
- }
-
- if (hostConflictDetected || serviceConflictDetected)
- {
- new Prober().start();
- }
- }
-
- /**
- * Add an answer to a question. Deal with the case when the
- * outgoing packet overflows
- */
- DNSOutgoing addAnswer(DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out,
- DNSRecord rec)
- throws IOException
- {
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- }
- try
- {
- out.addAnswer(in, rec);
- }
- catch (IOException e)
- {
- out.flags |= DNSConstants.FLAGS_TC;
- out.id = in.id;
- out.finish();
- send(out);
-
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- out.addAnswer(in, rec);
- }
- return out;
- }
-
-
- /**
- * Send an outgoing multicast DNS message.
- */
- private void send(DNSOutgoing out) throws IOException
- {
- out.finish();
- if (!out.isEmpty())
- {
- DatagramPacket packet =
- new DatagramPacket(
- out.data, out.off, group, DNSConstants.MDNS_PORT);
-
- try
- {
- DNSIncoming msg = new DNSIncoming(packet);
- if (logger.isTraceEnabled())
- logger.trace("send() JmDNS out:" + msg.print(true));
- }
- catch (IOException exc)
- {
- logger.error(
- "send(DNSOutgoing) - JmDNS can not parse what it sends!!!",
- exc);
- }
- socket.send(packet);
- }
- }
-
- /**
- * Listen for multicast packets.
- */
- class SocketListener implements Runnable
- {
- public void run()
- {
- try
- {
- byte buf[] = new byte[DNSConstants.MAX_MSG_ABSOLUTE];
- DatagramPacket packet = new DatagramPacket(buf, buf.length);
- while (state != DNSState.CANCELED)
- {
- packet.setLength(buf.length);
- socket.receive(packet);
- if (state == DNSState.CANCELED)
- {
- break;
- }
- try
- {
- if (localHost.shouldIgnorePacket(packet))
- {
- continue;
- }
-
- DNSIncoming msg = new DNSIncoming(packet);
- if (logger.isTraceEnabled())
- logger.trace("SocketListener.run() JmDNS in:" +
- msg.print(true));
-
- synchronized (ioLock)
- {
- if (msg.isQuery())
- {
- if (packet.getPort() != DNSConstants.MDNS_PORT)
- {
- handleQuery(msg,
- packet.getAddress(),
- packet.getPort());
- }
- handleQuery(msg, group, DNSConstants.MDNS_PORT);
- }
- else
- {
- handleResponse(msg);
- }
- }
- }
- catch (IOException e)
- {
- logger.warn( "run() exception ", e);
- }
- }
- }
- catch (IOException e)
- {
- if (state != DNSState.CANCELED)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
- }
-
-
- /**
- * Periodicaly removes expired entries from the cache.
- */
- private class RecordReaper extends TimerTask
- {
- public void start()
- {
- timer.schedule( this,
- DNSConstants.RECORD_REAPER_INTERVAL,
- DNSConstants.RECORD_REAPER_INTERVAL);
- }
-
- @Override
- public void run()
- {
- synchronized (JmDNS.this)
- {
- if (state == DNSState.CANCELED)
- {
- return;
- }
- if (logger.isTraceEnabled())
- logger.trace("run() JmDNS reaping cache");
-
- // Remove expired answers from the cache
- // -------------------------------------
- // To prevent race conditions, we defensively copy all cache
- // entries into a list.
- List<DNSEntry> list = new ArrayList<DNSEntry>();
- synchronized (cache)
- {
- for (Iterator<DNSCache.CacheNode> i = cache.iterator();
- i.hasNext();)
- {
- for (DNSCache.CacheNode n = i.next();
- n != null;
- n = n.next())
- {
- list.add(n.getValue());
- }
- }
- }
- // Now, we remove them.
- long now = System.currentTimeMillis();
- for (Iterator<DNSEntry> i = list.iterator(); i.hasNext();)
- {
- DNSRecord c = (DNSRecord)i.next();
- if (c.isExpired(now))
- {
- updateRecord(now, c);
- cache.remove(c);
- }
- }
- }
- }
- }
-
-
- /**
- * The Prober sends three consecutive probes for all service infos
- * that needs probing as well as for the host name.
- * The state of each service info of the host name is advanced,
- * when a probe has been sent for it.
- * When the prober has run three times, it launches an Announcer.
- * <p/>
- * If a conflict during probes occurs, the affected service
- * infos (and affected host name) are taken away from the prober.
- * This eventually causes the prober tho cancel itself.
- */
- private class Prober extends TimerTask
- {
- /**
- * The state of the prober.
- */
- DNSState taskState = DNSState.PROBING_1;
-
- public Prober()
- {
- // Associate the host name to this, if it needs probing
- if (state == DNSState.PROBING_1)
- {
- task = this;
- }
- // Associate services to this, if they need probing
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> iterator = services.values().iterator();
- iterator.hasNext();)
- {
- ServiceInfo info = iterator.next();
- if (info.getState() == DNSState.PROBING_1)
- {
- info.task = this;
- }
- }
- }
- }
-
-
- public void start()
- {
- long now = System.currentTimeMillis();
- if (now - lastThrottleIncrement <
- DNSConstants.PROBE_THROTTLE_COUNT_INTERVAL)
- {
- throttle++;
- }
- else
- {
- throttle = 1;
- }
- lastThrottleIncrement = now;
-
- if (state == DNSState.ANNOUNCED &&
- throttle < DNSConstants.PROBE_THROTTLE_COUNT)
- {
- timer.schedule(this,
- random.nextInt(1 + DNSConstants.PROBE_WAIT_INTERVAL),
- DNSConstants.PROBE_WAIT_INTERVAL);
- }
- else
- {
- timer.schedule(this,
- DNSConstants.PROBE_CONFLICT_INTERVAL,
- DNSConstants.PROBE_CONFLICT_INTERVAL);
- }
- }
-
- @Override
- public boolean cancel()
- {
- // Remove association from host name to this
- if (task == this)
- {
- task = null;
- }
-
- // Remove associations from services to this
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> i = services.values().iterator();
- i.hasNext();)
- {
- ServiceInfo info = i.next();
- if (info.task == this)
- {
- info.task = null;
- }
- }
- }
-
- return super.cancel();
- }
-
- @Override
- public void run()
- {
- synchronized (ioLock)
- {
- DNSOutgoing out = null;
- try
- {
- // send probes for JmDNS itself
- if (state == taskState && task == this)
- {
- if (out == null)
- {
- out = new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
- }
- out.addQuestion(
- new DNSQuestion(
- localHost.getName(),
- DNSConstants.TYPE_ANY,
- DNSConstants.CLASS_IN));
- DNSRecord answer = localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- out.addAuthorativeAnswer(answer);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- out.addAuthorativeAnswer(answer);
- }
- advanceState();
- }
- // send probes for services
- // Defensively copy the services into a local list,
- // to prevent race conditions with methods registerService
- // and unregisterService.
- List<ServiceInfo> list;
- synchronized (JmDNS.this)
- {
- list = new LinkedList<ServiceInfo>(services.values());
- }
- for (Iterator<ServiceInfo> i = list.iterator(); i.hasNext();)
- {
- ServiceInfo info = i.next();
-
- synchronized (info)
- {
- if (info.getState() == taskState &&
- info.task == this)
- {
- info.advanceState();
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS probing " +
- info.getQualifiedName() + " state " +
- info.getState());
-
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_QUERY);
- out.addQuestion(
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_ANY,
- DNSConstants.CLASS_IN));
- }
- out.addAuthorativeAnswer(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()));
- }
- }
- }
- if (out != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS probing #" + taskState);
- send(out);
- }
- else
- {
- // If we have nothing to send, another timer taskState
- // ahead of us has done the job for us. We can cancel.
- cancel();
- return;
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
-
- taskState = taskState.advance();
- if (!taskState.isProbing())
- {
- cancel();
-
- new Announcer().start();
- }
- }
- }
-
- }
-
- /**
- * The Announcer sends an accumulated query of all announces, and advances
- * the state of all serviceInfos, for which it has sent an announce.
- * The Announcer also sends announcements and advances the state of JmDNS
- * itself.
- * <p/>
- * When the announcer has run two times, it finishes.
- */
- private class Announcer extends TimerTask
- {
- /**
- * The state of the announcer.
- */
- DNSState taskState = DNSState.ANNOUNCING_1;
-
- public Announcer()
- {
- // Associate host to this, if it needs announcing
- if (state == DNSState.ANNOUNCING_1)
- {
- task = this;
- }
- // Associate services to this, if they need announcing
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> s = services.values().iterator(); s.hasNext();)
- {
- ServiceInfo info = s.next();
- if (info.getState() == DNSState.ANNOUNCING_1)
- {
- info.task = this;
- }
- }
- }
- }
-
- public void start()
- {
- timer.schedule(this,
- DNSConstants.ANNOUNCE_WAIT_INTERVAL,
- DNSConstants.ANNOUNCE_WAIT_INTERVAL);
- }
-
- @Override
- public boolean cancel()
- {
- // Remove association from host to this
- if (task == this)
- {
- task = null;
- }
-
- // Remove associations from services to this
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> i = services.values().iterator();
- i.hasNext();)
- {
- ServiceInfo info = i.next();
- if (info.task == this)
- {
- info.task = null;
- }
- }
- }
-
- return super.cancel();
- }
-
- @Override
- public void run()
- {
- DNSOutgoing out = null;
- try
- {
- // send probes for JmDNS itself
- if (state == taskState)
- {
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- }
- DNSRecord answer = localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- advanceState();
- }
- // send announces for services
- // Defensively copy the services into a local list,
- // to prevent race conditions with methods registerService
- // and unregisterService.
- List<ServiceInfo> list;
- synchronized (JmDNS.this)
- {
- list = new ArrayList<ServiceInfo>(services.values());
- }
- for (Iterator<ServiceInfo> i = list.iterator(); i.hasNext();)
- {
- ServiceInfo info = i.next();
- synchronized (info)
- {
- if (info.getState() == taskState && info.task == this)
- {
- info.advanceState();
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS announcing " +
- info.getQualifiedName() +
- " state " + info.getState());
-
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE |
- DNSConstants.FLAGS_AA);
- }
- out.addAnswer(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()), 0);
- out.addAnswer(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.text), 0);
- }
- }
- }
- if (out != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS announcing #" + taskState);
- send(out);
- }
- else
- {
- // If we have nothing to send, another timer taskState ahead
- // of us has done the job for us. We can cancel.
- cancel();
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
-
- taskState = taskState.advance();
- if (!taskState.isAnnouncing())
- {
- cancel();
-
- new Renewer().start();
- }
- }
- }
-
- /**
- * The Renewer is there to send renewal announcment
- * when the record expire for ours infos.
- */
- private class Renewer extends TimerTask
- {
- /**
- * The state of the announcer.
- */
- DNSState taskState = DNSState.ANNOUNCED;
-
- public Renewer()
- {
- // Associate host to this, if it needs renewal
- if (state == DNSState.ANNOUNCED)
- {
- task = this;
- }
- // Associate services to this, if they need renewal
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> s = services.values().iterator(); s.hasNext();)
- {
- ServiceInfo info = s.next();
- if (info.getState() == DNSState.ANNOUNCED)
- {
- info.task = this;
- }
- }
- }
- }
-
- public void start()
- {
- timer.schedule(this,
- DNSConstants.ANNOUNCED_RENEWAL_TTL_INTERVAL,
- DNSConstants.ANNOUNCED_RENEWAL_TTL_INTERVAL);
- }
-
- @Override
- public boolean cancel()
- {
- // Remove association from host to this
- if (task == this)
- {
- task = null;
- }
-
- // Remove associations from services to this
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> i = services.values().iterator();
- i.hasNext();)
- {
- ServiceInfo info = i.next();
- if (info.task == this)
- {
- info.task = null;
- }
- }
- }
-
- return super.cancel();
- }
-
- @Override
- public void run()
- {
- DNSOutgoing out = null;
- try
- {
- // send probes for JmDNS itself
- if (state == taskState)
- {
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- }
- DNSRecord answer = localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- advanceState();
- }
- // send announces for services
- // Defensively copy the services into a local list,
- // to prevent race conditions with methods registerService
- // and unregisterService.
- List<ServiceInfo> list;
- synchronized (JmDNS.this)
- {
- list = new ArrayList<ServiceInfo>(services.values());
- }
- for (Iterator<ServiceInfo> i = list.iterator(); i.hasNext();)
- {
- ServiceInfo info = i.next();
- synchronized (info)
- {
- if (info.getState() == taskState && info.task == this)
- {
- info.advanceState();
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS announced " +
- info.getQualifiedName() + " state " + info.getState());
-
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE |
- DNSConstants.FLAGS_AA);
- }
- out.addAnswer(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()), 0);
- out.addAnswer(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.text), 0);
- }
- }
- }
- if (out != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS announced");
- send(out);
- }
- else
- {
- // If we have nothing to send, another timer taskState ahead
- // of us has done the job for us. We can cancel.
- cancel();
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
-
- taskState = taskState.advance();
- if (!taskState.isAnnounced())
- {
- cancel();
-
- }
- }
- }
-
- /**
- * The Responder sends a single answer for the specified service infos
- * and for the host name.
- */
- private class Responder extends TimerTask
- {
- private DNSIncoming in;
- private InetAddress addr;
- private int port;
-
- public Responder(DNSIncoming in, InetAddress addr, int port)
- {
- this.in = in;
- this.addr = addr;
- this.port = port;
- }
-
- public void start()
- {
- // According to draft-cheshire-dnsext-multicastdns.txt
- // chapter "8 Responding":
- // We respond immediately if we know for sure, that we are
- // the only one who can respond to the query.
- // In all other cases, we respond within 20-120 ms.
- //
- // According to draft-cheshire-dnsext-multicastdns.txt
- // chapter "7.2 Multi-Packet Known Answer Suppression":
- // We respond after 20-120 ms if the query is truncated.
-
- boolean iAmTheOnlyOne = true;
- for (DNSEntry entry : in.questions)
- {
- if (entry instanceof DNSQuestion)
- {
- DNSQuestion q = (DNSQuestion) entry;
- if (logger.isTraceEnabled())
- logger.trace("start() question=" + q);
- iAmTheOnlyOne &= (q.type == DNSConstants.TYPE_SRV
- || q.type == DNSConstants.TYPE_TXT
- || q.type == DNSConstants.TYPE_A
- || q.type == DNSConstants.TYPE_AAAA
- || localHost.getName().equalsIgnoreCase(q.name)
- || services.containsKey(q.name.toLowerCase()));
- if (!iAmTheOnlyOne)
- {
- break;
- }
- }
- }
- int delay = (iAmTheOnlyOne && !in.isTruncated()) ?
- 0 :
- DNSConstants.RESPONSE_MIN_WAIT_INTERVAL +
- random.nextInt(
- DNSConstants.RESPONSE_MAX_WAIT_INTERVAL -
- DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + 1) -
- in.elapseSinceArrival();
- if (delay < 0)
- {
- delay = 0;
- }
- if (logger.isTraceEnabled())
- logger.trace("start() Responder chosen delay=" + delay);
- timer.schedule(this, delay);
- }
-
- @Override
- public void run()
- {
- synchronized (ioLock)
- {
- if (plannedAnswer == in)
- {
- plannedAnswer = null;
- }
-
- // We use these sets to prevent duplicate records
- // FIXME - This should be moved into DNSOutgoing
- HashSet<DNSQuestion> questions = new HashSet<DNSQuestion>();
- HashSet<DNSRecord> answers = new HashSet<DNSRecord>();
-
-
- if (state == DNSState.ANNOUNCED)
- {
- try
- {
- boolean isUnicast = (port != DNSConstants.MDNS_PORT);
-
-
- // Answer questions
- for (Iterator<DNSEntry> iterator = in.questions.iterator();
- iterator.hasNext();)
- {
- DNSEntry entry = iterator.next();
- if (entry instanceof DNSQuestion)
- {
- DNSQuestion q = (DNSQuestion) entry;
-
- // for unicast responses the question
- // must be included
- if (isUnicast)
- {
- //out.addQuestion(q);
- questions.add(q);
- }
-
- int type = q.type;
- if (type == DNSConstants.TYPE_ANY ||
- type == DNSConstants.TYPE_SRV)
- { // I ama not sure of why there is a special
- // case here [PJYF Oct 15 2004]
- if (localHost.getName().
- equalsIgnoreCase(q.getName()))
- {
- // type = DNSConstants.TYPE_A;
- DNSRecord answer =
- localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- type = DNSConstants.TYPE_IGNORE;
- }
- else
- {
- if (serviceTypes.containsKey(
- q.getName().toLowerCase()))
- {
- type = DNSConstants.TYPE_PTR;
- }
- }
- }
-
- switch (type)
- {
- case DNSConstants.TYPE_A:
- {
- // Answer a query for a domain name
- //out = addAnswer( in, addr, port, out, host );
- DNSRecord answer =
- localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- break;
- }
- case DNSConstants.TYPE_AAAA:
- {
- // Answer a query for a domain name
- DNSRecord answer =
- localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- break;
- }
- case DNSConstants.TYPE_PTR:
- {
- // Answer a query for services of a given type
-
- // find matching services
- for (Iterator<ServiceInfo> serviceIterator =
- services.values().iterator();
- serviceIterator.hasNext();)
- {
- ServiceInfo info = serviceIterator.next();
- if (info.getState() == DNSState.ANNOUNCED)
- {
- if (q.name.equalsIgnoreCase(info.type))
- {
- DNSRecord answer =
- localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answer =
- localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answers.add(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()));
- answers.add(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()));
- answers.add(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.text));
- }
- }
- }
- if (q.name.equalsIgnoreCase("_services._mdns._udp.local."))
- {
- for (Iterator<String> serviceTypeIterator = serviceTypes.values().iterator();
- serviceTypeIterator.hasNext();)
- {
- answers.add(
- new DNSRecord.Pointer(
- "_services._mdns._udp.local.",
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- serviceTypeIterator.next()));
- }
- }
- break;
- }
- case DNSConstants.TYPE_SRV:
- case DNSConstants.TYPE_ANY:
- case DNSConstants.TYPE_TXT:
- {
- ServiceInfo info = services.get(q.name.toLowerCase());
- if (info != null &&
- info.getState() == DNSState.ANNOUNCED)
- {
- DNSRecord answer =
- localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answer =
- localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answers.add(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()));
- answers.add(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()));
- answers.add(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.text));
- }
- break;
- }
- default :
- {
- //System.out.println("JmDNSResponder.unhandled query:"+q);
- break;
- }
- }
- }
- }
-
-
- // remove known answers, if the ttl is at least half of
- // the correct value. (See Draft Cheshire chapter 7.1.).
- for (DNSRecord knownAnswer : in.answers)
- {
- if (knownAnswer.ttl > DNSConstants.DNS_TTL / 2 &&
- answers.remove(knownAnswer))
- {
- if (logger.isDebugEnabled())
- logger.debug(
- "JmDNS Responder Known Answer Removed");
- }
- }
-
-
- // responde if we have answers
- if (answers.size() != 0)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS responding");
- DNSOutgoing out = null;
- if (isUnicast)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE
- | DNSConstants.FLAGS_AA,
- false);
- }
-
- for (Iterator<DNSQuestion> i = questions.iterator();
- i.hasNext();)
- {
- out.addQuestion(i.next());
- }
- for (Iterator<DNSRecord> i = answers.iterator();
- i.hasNext();)
- {
- out = addAnswer(in, addr, port, out, i.next());
- }
- send(out);
- }
- this.cancel();
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- close();
- }
- }
- }
- }
- }
-
- /**
- * Helper class to resolve service types.
- * <p/>
- * The TypeResolver queries three times consecutively for service types, and then
- * removes itself from the timer.
- * <p/>
- * The TypeResolver will run only if JmDNS is in state ANNOUNCED.
- */
- private class TypeResolver extends TimerTask
- {
- public void start()
- {
- timer.schedule(this,
- DNSConstants.QUERY_WAIT_INTERVAL,
- DNSConstants.QUERY_WAIT_INTERVAL);
- }
-
- /**
- * Counts the number of queries that were sent.
- */
- int count = 0;
-
- @Override
- public void run()
- {
- try
- {
- if (state == DNSState.ANNOUNCED)
- {
- if (count++ < 3)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS querying type");
- DNSOutgoing out =
- new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
- out.addQuestion(
- new DNSQuestion(
- "_services._mdns._udp.local.",
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN));
- for (String serviceType : serviceTypes.values())
- {
- out.addAnswer(
- new DNSRecord.Pointer(
- "_services._mdns._udp.local.",
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- serviceType), 0);
- }
- send(out);
- }
- else
- {
- // After three queries, we can quit.
- this.cancel();
- }
- }
- else
- {
- if (state == DNSState.CANCELED)
- {
- this.cancel();
- }
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
-
- /**
- * The ServiceResolver queries three times consecutively for services of
- * a given type, and then removes itself from the timer.
- * <p/>
- * The ServiceResolver will run only if JmDNS is in state ANNOUNCED.
- * REMIND: Prevent having multiple service resolvers for the same type in the
- * timer queue.
- */
- private class ServiceResolver extends TimerTask
- {
- /**
- * Counts the number of queries being sent.
- */
- int count = 0;
- private String type;
-
- public ServiceResolver(String type)
- {
- this.type = type;
- }
-
- public void start()
- {
- timer.schedule(this,
- DNSConstants.QUERY_WAIT_INTERVAL,
- DNSConstants.QUERY_WAIT_INTERVAL);
- }
-
- @Override
- public void run()
- {
- try
- {
- if (state == DNSState.ANNOUNCED)
- {
- if (count++ < 3)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS querying service");
- long now = System.currentTimeMillis();
- DNSOutgoing out =
- new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
- out.addQuestion(
- new DNSQuestion(
- type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN));
- for (Iterator<ServiceInfo> s = services.values().iterator(); s.hasNext();)
- {
- final ServiceInfo info = s.next();
- try
- {
- out.addAnswer(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()), now);
- }
- catch (IOException ee)
- {
- break;
- }
- }
- send(out);
- }
- else
- {
- // After three queries, we can quit.
- this.cancel();
- }
- }
- else
- {
- if (state == DNSState.CANCELED)
- {
- this.cancel();
- }
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
-
- /**
- * The ServiceInfoResolver queries up to three times consecutively for
- * a service info, and then removes itself from the timer.
- * <p/>
- * The ServiceInfoResolver will run only if JmDNS is in state ANNOUNCED.
- * REMIND: Prevent having multiple service resolvers for the same info in the
- * timer queue.
- */
- private class ServiceInfoResolver extends TimerTask
- {
- /**
- * Counts the number of queries being sent.
- */
- int count = 0;
- private ServiceInfo info;
-
- public ServiceInfoResolver(ServiceInfo info)
- {
- this.info = info;
- info.dns = JmDNS.this;
- addListener(info,
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_ANY,
- DNSConstants.CLASS_IN));
- }
-
- public void start()
- {
- timer.schedule(this,
- DNSConstants.QUERY_WAIT_INTERVAL,
- DNSConstants.QUERY_WAIT_INTERVAL);
- }
-
- @Override
- public void run()
- {
- try
- {
- if (state == DNSState.ANNOUNCED)
- {
- if (count++ < 3 && !info.hasData())
- {
- long now = System.currentTimeMillis();
- DNSOutgoing out =
- new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
- out.addQuestion(
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN));
- out.addQuestion(
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN));
- if (info.server != null)
- {
- out.addQuestion(
- new DNSQuestion(
- info.server,
- DNSConstants.TYPE_A,
- DNSConstants.CLASS_IN));
- }
- out.addAnswer((DNSRecord) cache.get(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN), now);
- out.addAnswer((DNSRecord) cache.get(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN), now);
- if (info.server != null)
- {
- out.addAnswer((DNSRecord) cache.get(
- info.server,
- DNSConstants.TYPE_A,
- DNSConstants.CLASS_IN), now);
- }
- send(out);
- }
- else
- {
- // After three queries, we can quit.
- this.cancel();
- removeListener(info);
- }
- }
- else
- {
- if (state == DNSState.CANCELED)
- {
- this.cancel();
- removeListener(info);
- }
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
-
- /**
- * The Canceler sends two announces with TTL=0 for the specified services.
- */
- /* TODO: Clarify whether 2 or 3 announces should be sent. The header says 2,
- * run() uses the (misleading) ++count < 3 (while all other tasks use count++ < 3)
- * and the comment in the else block in run() says: "After three successful..."
- */
- public class Canceler extends TimerTask
- {
- /**
- * Counts the number of announces being sent.
- */
- int count = 0;
- /**
- * The services that need cancelling.
- * Note: We have to use a local variable here, because the services
- * that are canceled, are removed immediately from variable JmDNS.services.
- */
- private ServiceInfo[] infos;
- /**
- * We call notifyAll() on the lock object, when we have canceled the
- * service infos.
- * This is used by method JmDNS.unregisterService() and
- * JmDNS.unregisterAllServices, to ensure that the JmDNS
- * socket stays open until the Canceler has canceled all services.
- * <p/>
- * Note: We need this lock, because ServiceInfos do the transition from
- * state ANNOUNCED to state CANCELED before we get here. We could get
- * rid of this lock, if we added a state named CANCELLING to DNSState.
- */
- private Object lock;
- int ttl = 0;
-
- public Canceler(ServiceInfo info, Object lock)
- {
- this.infos = new ServiceInfo[]{info};
- this.lock = lock;
- addListener(info,
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_ANY,
- DNSConstants.CLASS_IN));
- }
-
- public Canceler(ServiceInfo[] infos, Object lock)
- {
- this.infos = infos;
- this.lock = lock;
- }
-
- public Canceler(Collection<ServiceInfo> infos, Object lock)
- {
- this.infos = infos.toArray(new ServiceInfo[infos.size()]);
- this.lock = lock;
- }
-
- public void start()
- {
- timer.schedule(this, 0, DNSConstants.ANNOUNCE_WAIT_INTERVAL);
- }
-
- @Override
- public void run()
- {
- try
- {
- if (++count < 3)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS canceling service");
- // announce the service
- //long now = System.currentTimeMillis();
- DNSOutgoing out =
- new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- for (int i = 0; i < infos.length; i++)
- {
- ServiceInfo info = infos[i];
- out.addAnswer(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- ttl,
- info.getQualifiedName()), 0);
- out.addAnswer(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN,
- ttl,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN,
- ttl,
- info.text), 0);
- DNSRecord answer = localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- }
- send(out);
- }
- else
- {
- // After three successful announcements, we are finished.
- synchronized (lock)
- {
- closed=true;
- lock.notifyAll();
- }
- this.cancel();
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
-
- /**
- * Recover jmdns when there is an error.
- */
- protected void recover()
- {
- if (logger.isDebugEnabled())
- logger.debug("recover()");
- // We have an IO error so lets try to recover if anything happens lets close it.
- // This should cover the case of the IP address changing under our feet
- if (DNSState.CANCELED != state)
- {
- synchronized (this)
- { // Synchronize only if we are not already in process to prevent dead locks
- //
- if (logger.isDebugEnabled())
- logger.debug("recover() Cleanning up");
- // Stop JmDNS
- state = DNSState.CANCELED; // This protects against recursive calls
-
- // We need to keep a copy for reregistration
- Collection<ServiceInfo> oldServiceInfos = new ArrayList<ServiceInfo>(services.values());
-
- // Cancel all services
- unregisterAllServices();
- disposeServiceCollectors();
- //
- // close multicast socket
- closeMulticastSocket();
- //
- cache.clear();
- if (logger.isDebugEnabled())
- logger.debug("recover() All is clean");
- //
- // All is clear now start the services
- //
- try
- {
- openMulticastSocket(localHost);
- start(oldServiceInfos);
- }
- catch (Exception exception)
- {
- logger.warn(
- "recover() Start services exception ", exception);
- }
- logger.warn( "recover() We are back!");
- }
- }
- }
-
- /**
- * Close down jmdns. Release all resources and unregister all services.
- */
- public void close()
- {
- if (state != DNSState.CANCELED)
- {
- synchronized (this)
- { // Synchronize only if we are not already in process to prevent dead locks
- // Stop JmDNS
- state = DNSState.CANCELED; // This protects against recursive calls
-
- unregisterAllServices();
- disposeServiceCollectors();
-
- // close socket
- closeMulticastSocket();
-
- // Stop the timer
- timer.cancel();
- }
- }
- }
-
- /**
- * List cache entries, for debugging only.
- */
- void print()
- {
- if (logger.isInfoEnabled())
- logger.info("---- cache ----\n");
- cache.print();
- if (logger.isInfoEnabled())
- logger.info("\n");
- }
-
- /**
- * List Services and serviceTypes.
- * Debugging Only
- */
-
- public void printServices()
- {
- if (logger.isInfoEnabled())
- logger.info(toString());
- }
-
- @Override
- public String toString()
- {
- StringBuffer aLog = new StringBuffer();
- aLog.append("\t---- Services -----");
- if (services != null)
- {
- for (Map.Entry<String, ServiceInfo> entry : services.entrySet())
- {
- aLog.append("\n\t\tService: " + entry.getKey() + ": "
- + entry.getValue());
- }
- }
- aLog.append("\n");
- aLog.append("\t---- Types ----");
- if (serviceTypes != null)
- {
- for (Map.Entry<String, String> entry : serviceTypes.entrySet())
- {
- aLog.append("\n\t\tType: " + entry.getKey() + ": "
- + entry.getValue());
- }
- }
- aLog.append("\n");
- aLog.append(cache.toString());
- aLog.append("\n");
- aLog.append("\t---- Service Collectors ----");
- if (serviceCollectors != null)
- {
- synchronized (serviceCollectors)
- {
- for (Map.Entry<String, ServiceCollector> entry
- : serviceCollectors.entrySet())
- {
- aLog.append("\n\t\tService Collector: " + entry.getKey()
- + ": " + entry.getValue());
- }
- serviceCollectors.clear();
- }
- }
- return aLog.toString();
- }
-
- /**
- * Returns a list of service infos of the specified type.
- *
- * @param type Service type name, such as <code>_http._tcp.local.</code>.
- * @return An array of service instance names.
- */
- public ServiceInfo[] list(String type)
- {
- // Implementation note: The first time a list for a given type is
- // requested, a ServiceCollector is created which collects service
- // infos. This greatly speeds up the performance of subsequent calls
- // to this method. The caveats are, that 1) the first call to this method
- // for a given type is slow, and 2) we spawn a ServiceCollector
- // instance for each service type which increases network traffic a
- // little.
-
- ServiceCollector collector;
-
- boolean newCollectorCreated;
- synchronized (serviceCollectors)
- {
- collector = serviceCollectors.get(type);
- if (collector == null)
- {
- collector = new ServiceCollector(type);
- serviceCollectors.put(type, collector);
- addServiceListener(type, collector);
- newCollectorCreated = true;
- }
- else
- {
- newCollectorCreated = false;
- }
- }
-
- // After creating a new ServiceCollector, we collect service infos for
- // 200 milliseconds. This should be enough time, to get some service
- // infos from the network.
- if (newCollectorCreated)
- {
- try
- {
- Thread.sleep(200);
- }
- catch (InterruptedException e)
- {
- }
- }
-
- return collector.list();
- }
-
- /**
- * This method disposes all ServiceCollector instances which have been
- * created by calls to method <code>list(type)</code>.
- *
- * @see #list
- */
- private void disposeServiceCollectors()
- {
- if (logger.isDebugEnabled())
- logger.debug("disposeServiceCollectors()");
- synchronized (serviceCollectors)
- {
- for (Iterator<ServiceCollector> i = serviceCollectors.values().iterator(); i.hasNext();)
- {
- ServiceCollector collector = i.next();
- removeServiceListener(collector.type, collector);
- }
- serviceCollectors.clear();
- }
- }
-
- /**
- * Instances of ServiceCollector are used internally to speed up the
- * performance of method <code>list(type)</code>.
- *
- * @see #list
- */
- private static class ServiceCollector implements ServiceListener
- {
-
- /**
- * A set of collected service instance names.
- */
- private Map<String, ServiceInfo> infos = Collections.synchronizedMap(new HashMap<String, ServiceInfo>());
-
- public String type;
-
- public ServiceCollector(String type)
- {
- this.type = type;
- }
-
- /**
- * A service has been added.
- */
- public void serviceAdded(ServiceEvent event)
- {
- synchronized (infos)
- {
- event.getDNS().requestServiceInfo(
- event.getType(), event.getName(), 0);
- }
- }
-
- /**
- * A service has been removed.
- */
- public void serviceRemoved(ServiceEvent event)
- {
- synchronized (infos)
- {
- infos.remove(event.getName());
- }
- }
-
- /**
- * A service hase been resolved. Its details are now available in the
- * ServiceInfo record.
- */
- public void serviceResolved(ServiceEvent event)
- {
- synchronized (infos)
- {
- infos.put(event.getName(), event.getInfo());
- }
- }
-
- /**
- * Returns an array of all service infos which have been collected by this
- * ServiceCollector.
- * @return
- */
- public ServiceInfo[] list()
- {
- synchronized (infos)
- {
- return infos.values().
- toArray(new ServiceInfo[infos.size()]);
- }
- }
-
- @Override
- public String toString()
- {
- StringBuffer aLog = new StringBuffer();
- synchronized (infos)
- {
- for (Map.Entry<String, ServiceInfo> entry : infos.entrySet())
- {
- aLog.append("\n\t\tService: " + entry.getKey() + ": "
- + entry.getValue());
- }
- }
- return aLog.toString();
- }
- };
-
- private static String toUnqualifiedName(String type, String qualifiedName)
- {
- if (qualifiedName.endsWith(type))
- {
- return qualifiedName.substring(0,
- qualifiedName.length() - type.length() - 1);
- }
- else
- {
- return qualifiedName;
- }
- }
-
- /**
- * SC-Bonjour Implementation : Method used to update the corresponding DNS
- * entry in the cache of JmDNS with the new information in this ServiceInfo.
- * A call to getLocalService must first be issued to get the
- * ServiceInfo object to be modified.
- * THIS METHOD MUST BE USED INSTEAD OF ANY DIRECT ACCESS TO JMDNS' CACHE!!
- * This is used in the implementation of Zeroconf in SIP Communicator
- * to be able to change fields declared by the local contact (status, etc).
- * @param info Updated service data to be used to replace the old
- * stuff contained in JmDNS' cache
- * @param old info bytes
- */
- public void updateInfos(ServiceInfo info, byte[] old)
- {
-
- DNSOutgoing out, out2;
- synchronized (JmDNS.this)
- {
- //list = new ArrayList(services.values());
- services.put(info.getQualifiedName().toLowerCase(), info);
- }
-
- synchronized (info)
- {
- if (logger.isDebugEnabled())
- logger.debug("updateInfos() JmDNS updating " +
- info.getQualifiedName() + " state " +
- info.getState());
-
- out = new DNSOutgoing(
- /*DNSConstants.FLAGS_QR_RESPONSE*/
- DNSConstants.FLAGS_RA | DNSConstants.FLAGS_AA);
- out2 = new DNSOutgoing(
- /*DNSConstants.FLAGS_QR_RESPONSE*/
- DNSConstants.FLAGS_RA | DNSConstants.FLAGS_AA);
-
-
- try
- {
- //out.addAnswer(new DNSRecord.Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName()), 0);
- //out.addAnswer(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_A, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName()), 0);
- //out.addAnswer(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName()), 0);
-// out.addAnswer(
-// new DNSRecord.Text(
-// info.getQualifiedName(),
-// DNSConstants.TYPE_TXT,
-// DNSConstants.CLASS_IN ,
-// DNSConstants.DNS_TTL,
-// info.text), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN ,
- 0,
- old), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.text), 0);
-
- out2.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.text), 0);
-
- if (logger.isDebugEnabled())
- logger.debug("updateInfos() JmDNS updated infos for "+info);
-
- send(out);
- Thread.sleep(1000);
- send(out2);
- Thread.sleep(2000);
- send(out2);
- }
- catch( Exception e)
- {
- logger.warn( "", e);
- }
- }
- }
-
-
- /**
- * SC-Bonjour Implementation: Method to retrieve the DNS Entry corresponding to a service
- * that has been declared and return it as a ServiceInfo structure.
- * It is used in the implementation of Bonjour in SIP Communicator to retrieve the information
- * concerning the service declared by the local contact. THIS METHOD MUST BE USED INSTEAD OF ANY
- * LOCAL COPY SAVED BEFORE SERVICE REGISTRATION!!
- * @return information corresponding to the specified service
- * @param FQN String representing the Fully Qualified name of the service we want info about
- */
- public ServiceInfo getLocalService(String FQN)
- {
- return services.get(FQN);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceEvent.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceEvent.java
deleted file mode 100644
index ff922d1..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceEvent.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * ServiceEvent.
- *
- * @author Werner Randelshofer, Rick Blair
- * @version %I%, %G%
- */
-public class ServiceEvent
- extends EventObject
-{
- private static Logger logger =
- Logger.getLogger(ServiceEvent.class.toString());
- /**
- * The type name of the service.
- */
- private String type;
- /**
- * The instance name of the service. Or null, if the event was
- * fired to a service type listener.
- */
- private String name;
- /**
- * The service info record, or null if the service could be be resolved.
- * This is also null, if the event was fired to a service type listener.
- */
- private ServiceInfo info;
-
- /**
- * Creates a new instance.
- *
- * @param source the JmDNS instance which originated the event.
- * @param type the type name of the service.
- * @param name the instance name of the service.
- * @param info the service info record, or null if the
- * service could be be resolved.
- */
- public ServiceEvent(JmDNS source, String type, String name, ServiceInfo info)
- {
- super(source);
- this.type = type;
- this.name = name;
- this.info = info;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Returns the JmDNS instance which originated the event.
- * @return Returns the JmDNS instance which originated the event.
- */
- public JmDNS getDNS()
- {
- return (JmDNS) getSource();
- }
-
- /**
- * Returns the fully qualified type of the service.
- * @return Returns the fully qualified type of the service.
- */
- public String getType()
- {
- return type;
- }
-
- /**
- * Returns the instance name of the service.
- * Always returns null, if the event is sent to a service type listener.
- * @return Returns the instance name of the service.
- */
- public String getName()
- {
- return name;
- }
-
- /**
- * Returns the service info record, or null if the service could not be
- * resolved.
- * Always returns null, if the event is sent to a service type listener.
- * @return Returns the service info record.
- */
- public ServiceInfo getInfo()
- {
- return info;
- }
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append("<" + getClass().getName() + "> ");
- buf.append(super.toString());
- buf.append(" name ");
- buf.append(getName());
- buf.append(" type ");
- buf.append(getType());
- buf.append(" info ");
- buf.append(getInfo());
- return buf.toString();
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceInfo.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceInfo.java
deleted file mode 100644
index b7f7f2d..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceInfo.java
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * JmDNS service information.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Jeff Sonstein, Werner Randelshofer
- * @author Christian Vincenot
- */
-public class ServiceInfo implements DNSListener
-{
- private static Logger logger =
- Logger.getLogger(ServiceInfo.class.toString());
- public final static byte[] NO_VALUE = new byte[0];
- JmDNS dns;
-
- // State machine
- /**
- * The state of this service info.
- * This is used only for services announced by JmDNS.
- * <p/>
- * For proper handling of concurrency, this variable must be
- * changed only using methods advanceState(), revertState() and cancel().
- */
- private DNSState state = DNSState.PROBING_1;
-
- /**
- * Task associated to this service info.
- * Possible tasks are JmDNS.Prober, JmDNS.Announcer, JmDNS.Responder,
- * JmDNS.Canceler.
- */
- TimerTask task;
-
- String type;
- private String name;
- String server;
- int port;
- int weight;
- int priority;
- byte text[];
- private Map<String, Object> props;
- InetAddress addr;
-
-
- /**
- * Construct a service description for registrating with JmDNS.
- *
- * @param type fully qualified service type name,
- * such as <code>_http._tcp.local.</code>.
- * @param name unqualified service instance name,
- * such as <code>foobar</code>
- * @param port the local port on which the service runs
- * @param text string describing the service
- */
- public ServiceInfo(String type, String name, int port, String text)
- {
- this(type, name, port, 0, 0, text);
- }
-
- /**
- * Construct a service description for registrating with JmDNS.
- *
- * @param type fully qualified service type name,
- * such as <code>_http._tcp.local.</code>.
- * @param name unqualified service instance name,
- * such as <code>foobar</code>
- * @param port the local port on which the service runs
- * @param weight weight of the service
- * @param priority priority of the service
- * @param text string describing the service
- */
- public ServiceInfo(String type, String name,
- int port, int weight,
- int priority, String text)
- {
- this(type, name, port, weight, priority, (byte[]) null);
- try
- {
- ByteArrayOutputStream out = new ByteArrayOutputStream(text.length());
- writeUTF(out, text);
- this.text = out.toByteArray();
- }
- catch (IOException e)
- {
- throw new RuntimeException("unexpected exception: " + e);
- }
- }
-
- /**
- * Construct a service description for registrating with JmDNS. The properties hashtable must
- * map property names to either Strings or byte arrays describing the property values.
- *
- * @param type fully qualified service type name, such as <code>_http._tcp.local.</code>.
- * @param name unqualified service instance name, such as <code>foobar</code>
- * @param port the local port on which the service runs
- * @param weight weight of the service
- * @param priority priority of the service
- * @param props properties describing the service
- */
- public ServiceInfo(String type, String name,
- int port, int weight,
- int priority, Map<String, Object> props)
- {
- this(type, name, port, weight, priority, new byte[0]);
- if (props != null)
- {
- try
- {
- ByteArrayOutputStream out = new ByteArrayOutputStream(256);
- for (Map.Entry<String, Object> prop : props.entrySet())
- {
- String key = prop.getKey();
- Object val = prop.getValue();
- ByteArrayOutputStream out2 = new ByteArrayOutputStream(100);
- writeUTF(out2, key);
- if (val instanceof String)
- {
- out2.write('=');
- writeUTF(out2, (String) val);
- }
- else
- {
- if (val instanceof byte[])
- {
- out2.write('=');
- byte[] bval = (byte[]) val;
- out2.write(bval, 0, bval.length);
- }
- else
- {
- if (val != NO_VALUE)
- {
- throw new IllegalArgumentException(
- "invalid property value: " + val);
- }
- }
- }
- byte data[] = out2.toByteArray();
- out.write(data.length);
- out.write(data, 0, data.length);
- }
- this.text = out.toByteArray();
- }
- catch (IOException e)
- {
- throw new RuntimeException("unexpected exception: " + e);
- }
- }
- }
-
- /**
- * Construct a service description for registrating with JmDNS.
- *
- * @param type fully qualified service type name,
- * such as <code>_http._tcp.local.</code>.
- * @param name unqualified service instance name,
- * such as <code>foobar</code>
- * @param port the local port on which the service runs
- * @param weight weight of the service
- * @param priority priority of the service
- * @param text bytes describing the service
- */
- public ServiceInfo(String type, String name,
- int port, int weight,
- int priority, byte text[])
- {
- this.type = type;
- this.name = name;
- this.port = port;
- this.weight = weight;
- this.priority = priority;
- this.text = text;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Construct a service record during service discovery.
- */
- ServiceInfo(String type, String name)
- {
- if (!type.endsWith("."))
- {
- throw new IllegalArgumentException(
- "type must be fully qualified DNS name ending in '.': " + type);
- }
-
- this.type = type;
- this.name = name;
- }
-
- /**
- * During recovery we need to duplicate service info to reregister them
- */
- ServiceInfo(ServiceInfo info)
- {
- if (info != null)
- {
- this.type = info.type;
- this.name = info.name;
- this.port = info.port;
- this.weight = info.weight;
- this.priority = info.priority;
- this.text = info.text;
- }
- }
-
- /**
- * Fully qualified service type name,
- * such as <code>_http._tcp.local.</code> .
- * @return Returns fully qualified service type name.
- */
- public String getType()
- {
- return type;
- }
-
- /**
- * Unqualified service instance name,
- * such as <code>foobar</code> .
- * @return Returns unqualified service instance name.
- */
- public String getName()
- {
- return name;
- }
-
- /**
- * Sets the service instance name.
- *
- * @param name unqualified service instance name,
- * such as <code>foobar</code>
- */
- void setName(String name)
- {
- this.name = name;
- }
-
- /**
- * Fully qualified service name,
- * such as <code>foobar._http._tcp.local.</code> .
- * @return Returns fully qualified service name.
- */
- public String getQualifiedName()
- {
- return name + "." + type;
- }
-
- /**
- * Get the name of the server.
- * @return Returns name of the server.
- */
- public String getServer()
- {
- return server;
- }
-
- /**
- * Get the host address of the service (ie X.X.X.X).
- * @return Returns host address of the service.
- */
- public String getHostAddress()
- {
- return (addr != null ? addr.getHostAddress() : "");
- }
-
- public InetAddress getAddress()
- {
- return addr;
- }
-
- /**
- * Get the InetAddress of the service.
- * @return Returns the InetAddress of the service.
- */
- public InetAddress getInetAddress()
- {
- return addr;
- }
-
- /**
- * Get the port for the service.
- * @return Returns port for the service.
- */
- public int getPort()
- {
- return port;
- }
-
- /**
- * Get the priority of the service.
- * @return Returns the priority of the service.
- */
- public int getPriority()
- {
- return priority;
- }
-
- /**
- * Get the weight of the service.
- * @return Returns the weight of the service.
- */
- public int getWeight()
- {
- return weight;
- }
-
- /**
- * Get the text for the serivce as raw bytes.
- * @return Returns the text for the serivce as raw bytes.
- */
- public byte[] getTextBytes()
- {
- return text;
- }
-
- /**
- * Get the text for the service. This will interpret the text bytes
- * as a UTF8 encoded string. Will return null if the bytes are not
- * a valid UTF8 encoded string.
- * @return Returns the text for the service.
- */
- public String getTextString()
- {
- if ((text == null) ||
- (text.length == 0) ||
- ((text.length == 1) && (text[0] == 0)))
- {
- return null;
- }
- return readUTF(text, 0, text.length);
- }
-
- /**
- * Get the URL for this service. An http URL is created by
- * combining the address, port, and path properties.
- * @return Returns the URL for this service.
- */
- public String getURL()
- {
- return getURL("http");
- }
-
- /**
- * Get the URL for this service. An URL is created by
- * combining the protocol, address, port, and path properties.
- * @param protocol
- * @return Returns URL for this service.
- */
- public String getURL(String protocol)
- {
- String url = protocol + "://" + getHostAddress() + ":" + getPort();
- String path = getPropertyString("path");
- if (path != null)
- {
- if (path.indexOf("://") >= 0)
- {
- url = path;
- }
- else
- {
- url += path.startsWith("/") ? path : "/" + path;
- }
- }
- return url;
- }
-
- /**
- * Get a property of the service. This involves decoding the
- * text bytes into a property list. Returns null if the property
- * is not found or the text data could not be decoded correctly.
- * @param name
- * @return Returns property of the service as bytes.
- */
- public synchronized byte[] getPropertyBytes(String name)
- {
- return (byte[]) getProperties().get(name);
- }
-
- /**
- * Get a property of the service. This involves decoding the
- * text bytes into a property list. Returns null if the property
- * is not found, the text data could not be decoded correctly, or
- * the resulting bytes are not a valid UTF8 string.
- * @param name
- * @return Returns property of the service as string.
- */
- public synchronized String getPropertyString(String name)
- {
- byte data[] = (byte[]) getProperties().get(name);
-
- if (data == null)
- {
- return null;
- }
- if (data == NO_VALUE)
- {
- return "true";
- }
- String res = readUTF(data, 0, data.length);
-
- return res;
- }
-
- /**
- * Iterator<String> of the property names.
- * @return Iterator<String> of the property names.
- */
- public Iterator<String> getPropertyNames()
- {
- Map<String, Object> properties = getProperties();
- Iterable<String> propertyNames
- = (properties != null) ? properties.keySet() : new Vector<String>();
- return propertyNames.iterator();
- }
-
- /**
- * Write a UTF string with a length to a stream.
- */
- void writeUTF(OutputStream out, String str) throws IOException
- {
- for (int i = 0, len = str.length(); i < len; i++)
- {
- int c = str.charAt(i);
- if ((c >= 0x0001) && (c <= 0x007F))
- {
- out.write(c);
- }
- else
- {
- if (c > 0x07FF)
- {
- out.write(0xE0 | ((c >> 12) & 0x0F));
- out.write(0x80 | ((c >> 6) & 0x3F));
- out.write(0x80 | ((c >> 0) & 0x3F));
- }
- else
- {
- out.write(0xC0 | ((c >> 6) & 0x1F));
- out.write(0x80 | ((c >> 0) & 0x3F));
- }
- }
- }
- }
-
- /**
- * Read data bytes as a UTF stream.
- */
- String readUTF(byte data[], int off, int len)
- {
- StringBuffer buf = new StringBuffer();
- for (int end = off + len; off < end;)
- {
- int ch = data[off++] & 0xFF;
- switch (ch >> 4)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- // 0xxxxxxx
- break;
- case 12:
- case 13:
- if (off >= len)
- {
- return null;
- }
- // 110x xxxx 10xx xxxx
- ch = ((ch & 0x1F) << 6) | (data[off++] & 0x3F);
- break;
- case 14:
- if (off + 2 >= len)
- {
- return null;
- }
- // 1110 xxxx 10xx xxxx 10xx xxxx
- ch = ((ch & 0x0f) << 12) |
- ((data[off++] & 0x3F) << 6) |
- (data[off++] & 0x3F);
- break;
- default:
- if (off + 1 >= len)
- {
- return null;
- }
- // 10xx xxxx, 1111 xxxx
- ch = ((ch & 0x3F) << 4) | (data[off++] & 0x0f);
- break;
- }
- buf.append((char) ch);
- }
- return buf.toString();
- }
-
- synchronized Map<String, Object> getProperties()
- {
- if ((props == null) && (text != null))
- {
- Map<String, Object> props = new Hashtable<String, Object>();
- int off = 0;
- while (off < text.length)
- {
- // length of the next key value pair
- int len = text[off++] & 0xFF;
- if ((len == 0) || (off + len > text.length))
- {
- props.clear();
- break;
- }
- // look for the '='
- int i = 0;
- for (; (i < len) && (text[off + i] != '='); i++)
- {
- ;
- }
-
- // get the property name
- String name = readUTF(text, off, i);
- if (name == null)
- {
- props.clear();
- break;
- }
- if (i == len)
- {
- props.put(name, NO_VALUE);
- }
- else
- {
- byte value[] = new byte[len - ++i];
- System.arraycopy(text, off + i, value, 0, len - i);
- props.put(name, value);
- off += len;
- }
- }
- this.props = props;
- }
- return props;
- }
-
-
- /**
- * JmDNS callback to update a DNS record.
- * @param rec
- */
- public void updateRecord(JmDNS jmdns, long now, DNSRecord rec)
- {
- if ((rec != null) && !rec.isExpired(now))
- {
- switch (rec.type)
- {
- case DNSConstants.TYPE_A: // IPv4
- case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested
- if (rec.name.equals(server))
- {
- addr = ((DNSRecord.Address) rec).getAddress();
-
- }
- break;
- case DNSConstants.TYPE_SRV:
- if (rec.name.equals(getQualifiedName()))
- {
- DNSRecord.Service srv = (DNSRecord.Service) rec;
- server = srv.server;
- port = srv.port;
- weight = srv.weight;
- priority = srv.priority;
- addr = null;
- // changed to use getCache() instead - jeffs
- // updateRecord(jmdns, now, (DNSRecord)jmdns.cache.get(server, TYPE_A, CLASS_IN));
- updateRecord(jmdns,
- now,
- (DNSRecord) jmdns.getCache().get(
- server,
- DNSConstants.TYPE_A,
- DNSConstants.CLASS_IN));
- }
- break;
- case DNSConstants.TYPE_TXT:
- if (rec.name.equals(getQualifiedName()))
- {
- DNSRecord.Text txt = (DNSRecord.Text) rec;
- text = txt.text;
- }
- break;
- }
- // Future Design Pattern
- // This is done, to notify the wait loop in method
- // JmDNS.getServiceInfo(type, name, timeout);
- if (hasData() && dns != null)
- {
- dns.handleServiceResolved(this);
- dns = null;
- }
- synchronized (this)
- {
- notifyAll();
- }
- }
- }
-
- /**
- * Returns true if the service info is filled with data.
- */
- boolean hasData()
- {
- return server != null && addr != null && text != null;
- }
-
-
- // State machine
- /**
- * Sets the state and notifies all objects that wait on the ServiceInfo.
- */
- synchronized void advanceState()
- {
- state = state.advance();
- notifyAll();
- }
-
- /**
- * Sets the state and notifies all objects that wait on the ServiceInfo.
- */
- synchronized void revertState()
- {
- state = state.revert();
- notifyAll();
- }
-
- /**
- * Sets the state and notifies all objects that wait on the ServiceInfo.
- */
- synchronized void cancel()
- {
- state = DNSState.CANCELED;
- notifyAll();
- }
-
- /**
- * Returns the current state of this info.
- */
- DNSState getState()
- {
- return state;
- }
-
-
- @Override
- public int hashCode()
- {
- return getQualifiedName().hashCode();
- }
-
- @Override
- public boolean equals(Object obj)
- {
- return (obj instanceof ServiceInfo) &&
- getQualifiedName().equals(((ServiceInfo) obj).getQualifiedName());
- }
-
- public String getNiceTextString()
- {
- StringBuffer buf = new StringBuffer();
- for (int i = 0, len = text.length; i < len; i++)
- {
- if (i >= 20)
- {
- buf.append("...");
- break;
- }
- int ch = text[i] & 0xFF;
- if ((ch < ' ') || (ch > 127))
- {
- buf.append("\\0");
- buf.append(Integer.toString(ch, 8));
- }
- else
- {
- buf.append((char) ch);
- }
- }
- return buf.toString();
- }
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append("service[");
- buf.append(getQualifiedName());
- buf.append(',');
- buf.append(getAddress());
- buf.append(':');
- buf.append(port);
- buf.append(',');
- buf.append(getNiceTextString());
- buf.append(']');
- return buf.toString();
- }
-
- /**
- * SC-Bonjour Implementation: Method used to set the properties of an existing ServiceInfo.
- * This is used in the implementation of Bonjour in SIP Communicator to be able to replace
- * old properties of the service we've declared to announce the local user with new properties
- * (for example in case of a status change).
- * @param props Hashtable containing all the new properties to set
- */
- public void setProps(Map<String, Object> props)
- {
- if (props != null)
- {
- try
- {
- ByteArrayOutputStream out = new ByteArrayOutputStream(256);
- for (Map.Entry<String, Object> prop : props.entrySet())
- {
- String key = prop.getKey();
- Object val = prop.getValue();
-
- ByteArrayOutputStream out2 = new ByteArrayOutputStream(100);
- writeUTF(out2, key);
- if (val instanceof String)
- {
- out2.write('=');
- writeUTF(out2, (String) val);
- }
- else
- {
- if (val instanceof byte[])
- {
- out2.write('=');
- byte[] bval = (byte[]) val;
- out2.write(bval, 0, bval.length);
- }
- else
- {
- if (val != NO_VALUE)
- {
- throw new IllegalArgumentException(
- "invalid property value: " + val);
- }
- }
- }
- byte data[] = out2.toByteArray();
- out.write(data.length);
- out.write(data, 0, data.length);
- }
- this.text = out.toByteArray();
- }
- catch (IOException e)
- {
- throw new RuntimeException("unexpected exception: " + e);
- }
- }
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceListener.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceListener.java
deleted file mode 100644
index 1c34adf..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceListener.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-
-/**
- * Listener for service updates.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Werner Randelshofer
- */
-public interface ServiceListener extends EventListener
-{
- /**
- * A service has been added.
- *
- * @param event The ServiceEvent providing the name and fully qualified type
- * of the service.
- */
-
- void serviceAdded(ServiceEvent event);
-
- /**
- * A service has been removed.
- *
- * @param event The ServiceEvent providing the name and fully qualified type
- * of the service.
- */
- void serviceRemoved(ServiceEvent event);
-
- /**
- * A service has been resolved. Its details are now available in the
- * ServiceInfo record.
- *
- * @param event The ServiceEvent providing the name, the fully qualified
- * type of the service, and the service info record,
- * or null if the service could not be resolved.
- */
-
- void serviceResolved(ServiceEvent event);
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceTypeListener.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceTypeListener.java
deleted file mode 100644
index 84e5c59..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceTypeListener.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-
-/**
- * Listener for service types.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Werner Randelshofer
- */
-public interface ServiceTypeListener extends EventListener
-{
- /**
- * A new service type was discovered.
- *
- * @param event The service event providing the fully qualified type of
- * the service.
- */
- void serviceTypeAdded(ServiceEvent event);
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/zeroconf.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/zeroconf/zeroconf.provider.manifest.mf
deleted file mode 100644
index 24daba0..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/zeroconf.provider.manifest.mf
+++ /dev/null
@@ -1,12 +0,0 @@
-Bundle-Activator: net.java.sip.communicator.impl.protocol.zeroconf.ZeroconfActivator
-Bundle-Name: Zeroconf Protocol Provider
-Bundle-Description: A bundle providing support for the Zeroconf protocol.
-Bundle-Vendor: jitsi.org
-Bundle-Version: 0.0.1
-Bundle-SymbolicName: net.java.sip.communicator.protocol.zeroconf
-Import-Package: org.osgi.framework,
- org.jitsi.service.configuration,
- org.jitsi.service.resources, net.java.sip.communicator.service.resources,
- net.java.sip.communicator.util,
- net.java.sip.communicator.service.protocol,
- net.java.sip.communicator.service.protocol.event