mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 04:22:05 +01:00
Merge from 3.3 branch
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@13663 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
commit
dac68c64a9
163 changed files with 2304 additions and 2366 deletions
|
@ -28,7 +28,7 @@
|
||||||
<property name="version.major" value="3" />
|
<property name="version.major" value="3" />
|
||||||
<property name="version.minor" value="3" />
|
<property name="version.minor" value="3" />
|
||||||
<property name="version.revision" value="0" />
|
<property name="version.revision" value="0" />
|
||||||
<property name="version.extra" value="SNAPSHOT" />
|
<property name="version.extra" value="" />
|
||||||
|
|
||||||
<if>
|
<if>
|
||||||
<equals arg1="${version.extra}" arg2=""/>
|
<equals arg1="${version.extra}" arg2=""/>
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2,21 +2,6 @@
|
||||||
<!-- Smack configuration file. -->
|
<!-- Smack configuration file. -->
|
||||||
<smack>
|
<smack>
|
||||||
|
|
||||||
<!-- Classes that will be loaded when Smack starts -->
|
|
||||||
<startupClasses>
|
|
||||||
<className>org.jivesoftware.smackx.ServiceDiscoveryManager</className>
|
|
||||||
<className>org.jivesoftware.smack.PrivacyListManager</className>
|
|
||||||
<className>org.jivesoftware.smackx.XHTMLManager</className>
|
|
||||||
<className>org.jivesoftware.smackx.muc.MultiUserChat</className>
|
|
||||||
<className>org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager</className>
|
|
||||||
<className>org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager</className>
|
|
||||||
<className>org.jivesoftware.smackx.filetransfer.FileTransferManager</className>
|
|
||||||
<className>org.jivesoftware.smackx.LastActivityManager</className>
|
|
||||||
<className>org.jivesoftware.smack.ReconnectionManager</className>
|
|
||||||
<className>org.jivesoftware.smackx.commands.AdHocCommandManager</className>
|
|
||||||
<className>org.jivesoftware.smack.util.dns.JavaxResolver</className>
|
|
||||||
</startupClasses>
|
|
||||||
|
|
||||||
<!-- Packet reply timeout in milliseconds -->
|
<!-- Packet reply timeout in milliseconds -->
|
||||||
<packetReplyTimeout>5000</packetReplyTimeout>
|
<packetReplyTimeout>5000</packetReplyTimeout>
|
||||||
|
|
||||||
|
@ -32,10 +17,24 @@
|
||||||
<!-- Port of the local Socks5 proxy -->
|
<!-- Port of the local Socks5 proxy -->
|
||||||
<packetCollectorSize>10000</packetCollectorSize>
|
<packetCollectorSize>10000</packetCollectorSize>
|
||||||
|
|
||||||
<!-- Default interval (seconds) in which the Ping Manager sends ping request to the server (30 minutes) -->
|
|
||||||
<defaultPingInterval>1800</defaultPingInterval>
|
|
||||||
|
|
||||||
<!-- Automatic enable Entity Caps (XEP-0115) for new connections -->
|
<!-- Automatic enable Entity Caps (XEP-0115) for new connections -->
|
||||||
<autoEnableEntityCaps>false</autoEnableEntityCaps>
|
<autoEnableEntityCaps>false</autoEnableEntityCaps>
|
||||||
|
|
||||||
|
<!-- Classes that will be loaded when Smack starts -->
|
||||||
|
<startupClasses>
|
||||||
|
<className>org.jivesoftware.smackx.ServiceDiscoveryManager</className>
|
||||||
|
<className>org.jivesoftware.smack.PrivacyListManager</className>
|
||||||
|
<className>org.jivesoftware.smack.keepalive.KeepAliveManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.XHTMLManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.muc.MultiUserChat</className>
|
||||||
|
<className>org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.filetransfer.FileTransferManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.LastActivityManager</className>
|
||||||
|
<className>org.jivesoftware.smack.ReconnectionManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.commands.AdHocCommandManager</className>
|
||||||
|
<className>org.jivesoftware.smack.util.dns.JavaxResolver</className>
|
||||||
|
<className>org.jivesoftware.smackx.ping.PingManager</className>
|
||||||
|
</startupClasses>
|
||||||
|
|
||||||
</smack>
|
</smack>
|
||||||
|
|
|
@ -241,7 +241,7 @@
|
||||||
<iqProvider>
|
<iqProvider>
|
||||||
<elementName>ping</elementName>
|
<elementName>ping</elementName>
|
||||||
<namespace>urn:xmpp:ping</namespace>
|
<namespace>urn:xmpp:ping</namespace>
|
||||||
<className>org.jivesoftware.smackx.ping.provider.PingProvider</className>
|
<className>org.jivesoftware.smack.ping.provider.PingProvider</className>
|
||||||
</iqProvider>
|
</iqProvider>
|
||||||
|
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
|
@ -641,32 +641,6 @@
|
||||||
<className>org.jivesoftware.smackx.packet.AttentionExtension$Provider</className>
|
<className>org.jivesoftware.smackx.packet.AttentionExtension$Provider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
<!-- XEP-0297 Stanza Forwarding -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>forwarded</elementName>
|
|
||||||
<namespace>urn:xmpp:forward:0</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.forward.Forwarded$Provider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0280 Message Carbons -->
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>sent</elementName>
|
|
||||||
<namespace>urn:xmpp:carbons:2</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.carbons.Carbon$Provider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
<extensionProvider>
|
|
||||||
<elementName>received</elementName>
|
|
||||||
<namespace>urn:xmpp:carbons:2</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.carbons.Carbon$Provider</className>
|
|
||||||
</extensionProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0199 XMPP Ping -->
|
|
||||||
<iqProvider>
|
|
||||||
<elementName>ping</elementName>
|
|
||||||
<namespace>urn:xmpp:ping</namespace>
|
|
||||||
<className>org.jivesoftware.smackx.ping.provider.PingProvider</className>
|
|
||||||
</iqProvider>
|
|
||||||
|
|
||||||
<!-- XEP-0184 Message Delivery Receipts -->
|
<!-- XEP-0184 Message Delivery Receipts -->
|
||||||
<extensionProvider>
|
<extensionProvider>
|
||||||
<elementName>received</elementName>
|
<elementName>received</elementName>
|
||||||
|
|
|
@ -203,6 +203,36 @@ last release.
|
||||||
to use these icons outside of Smack.</li>
|
to use these icons outside of Smack.</li>
|
||||||
|
|
||||||
<li>Third-party source code is licensed as noted in their source files.
|
<li>Third-party source code is licensed as noted in their source files.
|
||||||
|
<li>Third-party binary code is licensed as follows.
|
||||||
|
<pre>
|
||||||
|
<b>dnsjava</b> <a href="http://dnsjava.org">(http://dnsjava.org)</a>
|
||||||
|
|
||||||
|
Copyright (c) 1999-2005, Brian Wellington
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the dnsjava project nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
</pre></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -141,9 +141,61 @@ hr {
|
||||||
|
|
||||||
<div id="pageBody">
|
<div id="pageBody">
|
||||||
|
|
||||||
|
<h2>3.3.0 -- <span style="font-weight: normal;">May 4, 2013</span></h2>
|
||||||
|
|
||||||
|
<h2>Bug Fixes</h2>
|
||||||
|
<ul>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-225'>SMACK-225</a>] - Improper handeling of DNS SRV records</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-238'>SMACK-238</a>] - The vCard avatar type always return jpg</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-270'>SMACK-270</a>] - Fix for a memory leak in MUC with MUC.finalize()</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-278'>SMACK-278</a>] - Deadlock during Smack disconnect</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-342'>SMACK-342</a>] - VCards causes ConcurrentModificationException</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-344'>SMACK-344</a>] - Bug in SASL authentication mechanism when SRV records are being used.</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-351'>SMACK-351</a>] - Rework File Transfer</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-352'>SMACK-352</a>] - Update the licensing headers in various files.</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-355'>SMACK-355</a>] - IO Error if smack cant use port for local proxy</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-371'>SMACK-371</a>] - Some MUC tasks are using stanza's as defined in an older version of the spec. Fails to work on some servers.</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-375'>SMACK-375</a>] - Node strings in the discovery info packets are not escaped as in the other packets</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-382'>SMACK-382</a>] - Prevent memory leak in AdHocCommandManager</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-384'>SMACK-384</a>] - Endless waiting for connection to be established</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-390'>SMACK-390</a>] - Smack login will fail if a bad delay packet is received</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-392'>SMACK-392</a>] - In ant build, compile-test target doesn't work.</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-394'>SMACK-394</a>] - Erroneous cast in IBBInputStream's read() method</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-395'>SMACK-395</a>] - Socks5BytestreamManager's establishConnection() should still try to use the local streamhost proxy if the server doesn't provide one</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-404'>SMACK-404</a>] - Smack uses the wrong method to decode Base64 Strings</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-413'>SMACK-413</a>] - VCardProvider incorrectly parses binary value of avatars</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-415'>SMACK-415</a>] - ItemProvider relies on incorrect behavior of MXParser, violating the contract of the XMLPullParser interface</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-417'>SMACK-417</a>] - If both PacketReader and PacketWriter fail at the same time, connectionClosedonError() is called two times</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>New Features</h2>
|
||||||
|
<ul>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-331'>SMACK-331</a>] - Add support for XEP-0184: Message Delivery Receipts</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-345'>SMACK-345</a>] - Inproved detection of last activity</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-361'>SMACK-361</a>] - Add support for XEP-0115 Entity Capabilities</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-376'>SMACK-376</a>] - Setting a custom trust manager to control certificates from outside</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-388'>SMACK-388</a>] - XEP-199 XMPP Ping support</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Improvements</h2>
|
||||||
|
<ul>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-341'>SMACK-341</a>] - Update the PacketCollector and ConnectionDetachedPacketCollector to use the java concurrent classes.</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-358'>SMACK-358</a>] - Support additional properties for account creation in test cases.</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-363'>SMACK-363</a>] - Code Cleanup</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-377'>SMACK-377</a>] - avoid unnecessary DNS requests in XMPPconnection</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-379'>SMACK-379</a>] - Sessions were removed from the specification but Smack still uses them. Should be updated to reflect the spec changes.</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-385'>SMACK-385</a>] - Reusing KeyStore in order to reduce memory usage</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-389'>SMACK-389</a>] - Add java.util.zip.Deflater(In|Out)putStream as Java7 API native alternative to JZlib </li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-391'>SMACK-391</a>] - Improve date parsing in StringUtils and make DelayInformationProvider use StringUtils for date parsing.</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-412'>SMACK-412</a>] - Replace the whitespace ping with a XEP-0199 ping</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-419'>SMACK-419</a>] - PacketWriter: Only flush the BufferedWriter if the packet queue is empty</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-423'>SMACK-423</a>] - Investigate whether unhandled packets should still parse the child xml into a string as content</li>
|
||||||
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-430'>SMACK-430</a>] - Throw an exception if FileTransferManager.createOutgoingFileTransfer() was used with a bare JID</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h2>3.2.2 -- <span style="font-weight: normal;">Dec. 23, 2011</span></h2>
|
<h2>3.2.2 -- <span style="font-weight: normal;">Dec. 23, 2011</span></h2>
|
||||||
|
|
||||||
<h3>Bug</h3>
|
<h3>Bug Fixes</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-263'>SMACK-263</a>] - Set file info in all send* methods</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-263'>SMACK-263</a>] - Set file info in all send* methods</li>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-322'>SMACK-322</a>] - NPE in XMPPConnection</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-322'>SMACK-322</a>] - NPE in XMPPConnection</li>
|
||||||
|
@ -157,15 +209,14 @@ hr {
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-362'>SMACK-362</a>] - smack throw NoSuchElementException if the muc#roominfo_subject has no values</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-362'>SMACK-362</a>] - smack throw NoSuchElementException if the muc#roominfo_subject has no values</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Improvement</h3>
|
<h3>Improvements</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-343'>SMACK-343</a>] - Make Smack jar an OSGi bundle.</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-343'>SMACK-343</a>] - Make Smack jar an OSGi bundle.</li>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-354'>SMACK-354</a>] - Provide milliseconds in timestamp colum debugwindow</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-354'>SMACK-354</a>] - Provide milliseconds in timestamp colum debugwindow</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<h2>3.2.1 -- <span style="font-weight: normal;">July 4, 2011</span></h2>
|
<h2>3.2.1 -- <span style="font-weight: normal;">July 4, 2011</span></h2>
|
||||||
<h3>Bug</h3>
|
<h3>Bug Fixes</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-129'>SMACK-129</a>] - MultiUserChat will Store Messages in its PacketCollector irregardless of whether or not they are being read</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-129'>SMACK-129</a>] - MultiUserChat will Store Messages in its PacketCollector irregardless of whether or not they are being read</li>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-230'>SMACK-230</a>] - Disconnect Can Cause Null Pointer Exception</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-230'>SMACK-230</a>] - Disconnect Can Cause Null Pointer Exception</li>
|
||||||
|
@ -176,14 +227,14 @@ hr {
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>3.2.0 -- <span style="font-weight: normal;">May 3, 2011</span></h2>
|
<h2>3.2.0 -- <span style="font-weight: normal;">May 3, 2011</span></h2>
|
||||||
<h3>New Feature</h3>
|
<h3>New Features</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-272'>SMACK-272</a>] - Add support for pubsub (XEP-0060)</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-272'>SMACK-272</a>] - Add support for pubsub (XEP-0060)</li>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-296'>SMACK-296</a>] - Add support for XEP-0224: Attention</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-296'>SMACK-296</a>] - Add support for XEP-0224: Attention</li>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-319'>SMACK-319</a>] - Add common interfaces for SOCKS5 Bytestreams and In-Band Bytestreams</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-319'>SMACK-319</a>] - Add common interfaces for SOCKS5 Bytestreams and In-Band Bytestreams</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Improvement</h3>
|
<h3>Improvements</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-137'>SMACK-137</a>] - File Transfer Settings</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-137'>SMACK-137</a>] - File Transfer Settings</li>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-156'>SMACK-156</a>] - Add the ability to register for roster events before logging in</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-156'>SMACK-156</a>] - Add the ability to register for roster events before logging in</li>
|
||||||
|
@ -208,7 +259,7 @@ hr {
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-310'>SMACK-310</a>] - Add Support for Localized Message Subjects</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-310'>SMACK-310</a>] - Add Support for Localized Message Subjects</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Bug</h3>
|
<h3>Bug Fixes</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-163'>SMACK-163</a>] - Fix NPE in RoomInfo when subject has not value</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-163'>SMACK-163</a>] - Fix NPE in RoomInfo when subject has not value</li>
|
||||||
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-207'>SMACK-207</a>] - Parsing of messages may disconnect Smack/Spark</li>
|
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-207'>SMACK-207</a>] - Parsing of messages may disconnect Smack/Spark</li>
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -178,12 +178,12 @@ public abstract class Connection {
|
||||||
protected SmackDebugger debugger = null;
|
protected SmackDebugger debugger = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Reader which is used for the {@see debugger}.
|
* The Reader which is used for the debugger.
|
||||||
*/
|
*/
|
||||||
protected Reader reader;
|
protected Reader reader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Writer which is used for the {@see debugger}.
|
* The Writer which is used for the debugger.
|
||||||
*/
|
*/
|
||||||
protected Writer writer;
|
protected Writer writer;
|
||||||
|
|
||||||
|
|
|
@ -40,18 +40,11 @@ import java.util.concurrent.BlockingQueue;
|
||||||
class PacketWriter {
|
class PacketWriter {
|
||||||
|
|
||||||
private Thread writerThread;
|
private Thread writerThread;
|
||||||
private Thread keepAliveThread;
|
|
||||||
private Writer writer;
|
private Writer writer;
|
||||||
private XMPPConnection connection;
|
private XMPPConnection connection;
|
||||||
private final BlockingQueue<Packet> queue;
|
private final BlockingQueue<Packet> queue;
|
||||||
volatile boolean done;
|
volatile boolean done;
|
||||||
|
|
||||||
/**
|
|
||||||
* Timestamp when the last stanza was sent to the server. This information is used
|
|
||||||
* by the keep alive process to only send heartbeats when the connection has been idle.
|
|
||||||
*/
|
|
||||||
private long lastActive = System.currentTimeMillis();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new packet writer with the specified connection.
|
* Creates a new packet writer with the specified connection.
|
||||||
*
|
*
|
||||||
|
@ -117,25 +110,6 @@ class PacketWriter {
|
||||||
writerThread.start();
|
writerThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the keep alive process. A white space (aka heartbeat) is going to be
|
|
||||||
* sent to the server every 30 seconds (by default) since the last stanza was sent
|
|
||||||
* to the server.
|
|
||||||
*/
|
|
||||||
void startKeepAliveProcess() {
|
|
||||||
// Schedule a keep-alive task to run if the feature is enabled. will write
|
|
||||||
// out a space character each time it runs to keep the TCP/IP connection open.
|
|
||||||
int keepAliveInterval = SmackConfiguration.getKeepAliveInterval();
|
|
||||||
if (keepAliveInterval > 0) {
|
|
||||||
KeepAliveTask task = new KeepAliveTask(keepAliveInterval);
|
|
||||||
keepAliveThread = new Thread(task);
|
|
||||||
task.setThread(keepAliveThread);
|
|
||||||
keepAliveThread.setDaemon(true);
|
|
||||||
keepAliveThread.setName("Smack Keep Alive (" + connection.connectionCounterValue + ")");
|
|
||||||
keepAliveThread.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWriter(Writer writer) {
|
void setWriter(Writer writer) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
}
|
}
|
||||||
|
@ -149,9 +123,6 @@ class PacketWriter {
|
||||||
synchronized (queue) {
|
synchronized (queue) {
|
||||||
queue.notifyAll();
|
queue.notifyAll();
|
||||||
}
|
}
|
||||||
// Interrupt the keep alive thread if one was created
|
|
||||||
if (keepAliveThread != null)
|
|
||||||
keepAliveThread.interrupt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,13 +162,10 @@ class PacketWriter {
|
||||||
while (!done && (writerThread == thisThread)) {
|
while (!done && (writerThread == thisThread)) {
|
||||||
Packet packet = nextPacket();
|
Packet packet = nextPacket();
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
synchronized (writer) {
|
|
||||||
writer.write(packet.toXML());
|
writer.write(packet.toXML());
|
||||||
|
|
||||||
if (queue.isEmpty()) {
|
if (queue.isEmpty()) {
|
||||||
writer.flush();
|
writer.flush();
|
||||||
// Keep track of the last time a stanza was sent to the server
|
|
||||||
lastActive = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,14 +173,12 @@ class PacketWriter {
|
||||||
// we won't have time to entirely flush it before the socket is forced closed
|
// we won't have time to entirely flush it before the socket is forced closed
|
||||||
// by the shutdown process.
|
// by the shutdown process.
|
||||||
try {
|
try {
|
||||||
synchronized (writer) {
|
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
Packet packet = queue.remove();
|
Packet packet = queue.remove();
|
||||||
writer.write(packet.toXML());
|
writer.write(packet.toXML());
|
||||||
}
|
}
|
||||||
writer.flush();
|
writer.flush();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -268,54 +234,4 @@ class PacketWriter {
|
||||||
writer.write(stream.toString());
|
writer.write(stream.toString());
|
||||||
writer.flush();
|
writer.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A TimerTask that keeps connections to the server alive by sending a space
|
|
||||||
* character on an interval.
|
|
||||||
*/
|
|
||||||
private class KeepAliveTask implements Runnable {
|
|
||||||
|
|
||||||
private int delay;
|
|
||||||
private Thread thread;
|
|
||||||
|
|
||||||
public KeepAliveTask(int delay) {
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setThread(Thread thread) {
|
|
||||||
this.thread = thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
// Sleep a minimum of 15 seconds plus delay before sending first heartbeat. This will give time to
|
|
||||||
// properly finish TLS negotiation and then start sending heartbeats.
|
|
||||||
Thread.sleep(15000 + delay);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ie) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
while (!done && keepAliveThread == thread) {
|
|
||||||
synchronized (writer) {
|
|
||||||
// Send heartbeat if no packet has been sent to the server for a given time
|
|
||||||
if (System.currentTimeMillis() - lastActive >= delay) {
|
|
||||||
try {
|
|
||||||
writer.write(" ");
|
|
||||||
writer.flush();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// Sleep until we should write the next keep-alive.
|
|
||||||
Thread.sleep(delay);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ie) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -316,7 +316,12 @@ public class SASLAuthentication implements UserAuthentication {
|
||||||
// Trigger SASL authentication with the selected mechanism. We use
|
// Trigger SASL authentication with the selected mechanism. We use
|
||||||
// connection.getHost() since GSAPI requires the FQDN of the server, which
|
// connection.getHost() since GSAPI requires the FQDN of the server, which
|
||||||
// may not match the XMPP domain.
|
// may not match the XMPP domain.
|
||||||
currentMechanism.authenticate(username, connection.getServiceName(), password);
|
|
||||||
|
//The serviceName is basically the value that XMPP server sends to the client as being the location
|
||||||
|
//of the XMPP service we are trying to connect to. This should have the format: host [ "/" serv-name ]
|
||||||
|
//as per RFC-2831 guidelines
|
||||||
|
String serviceName = connection.getServiceName();
|
||||||
|
currentMechanism.authenticate(username, connection.getHost(), serviceName, password);
|
||||||
|
|
||||||
// Wait until SASL negotiation finishes
|
// Wait until SASL negotiation finishes
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
@ -383,7 +388,7 @@ public class SASLAuthentication implements UserAuthentication {
|
||||||
public String authenticateAnonymously() throws XMPPException {
|
public String authenticateAnonymously() throws XMPPException {
|
||||||
try {
|
try {
|
||||||
currentMechanism = new SASLAnonymous(this);
|
currentMechanism = new SASLAnonymous(this);
|
||||||
currentMechanism.authenticate(null,null,"");
|
currentMechanism.authenticate(null,null,null,"");
|
||||||
|
|
||||||
// Wait until SASL negotiation finishes
|
// Wait until SASL negotiation finishes
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ import org.xmlpull.v1.XmlPullParser;
|
||||||
*/
|
*/
|
||||||
public final class SmackConfiguration {
|
public final class SmackConfiguration {
|
||||||
|
|
||||||
private static final String SMACK_VERSION = "3.2.2";
|
private static final String SMACK_VERSION = "3.3.0";
|
||||||
|
|
||||||
private static int packetReplyTimeout = 5000;
|
private static int packetReplyTimeout = 5000;
|
||||||
private static int keepAliveInterval = 30000;
|
private static int keepAliveInterval = 30000;
|
||||||
|
@ -58,11 +58,6 @@ public final class SmackConfiguration {
|
||||||
private static int localSocks5ProxyPort = 7777;
|
private static int localSocks5ProxyPort = 7777;
|
||||||
private static int packetCollectorSize = 5000;
|
private static int packetCollectorSize = 5000;
|
||||||
|
|
||||||
/**
|
|
||||||
* defaultPingInterval (in seconds)
|
|
||||||
*/
|
|
||||||
private static int defaultPingInterval = 1800; // 30 min (30*60)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This automatically enables EntityCaps for new connections if it is set to true
|
* This automatically enables EntityCaps for new connections if it is set to true
|
||||||
*/
|
*/
|
||||||
|
@ -117,8 +112,8 @@ public final class SmackConfiguration {
|
||||||
else if (parser.getName().equals("packetCollectorSize")) {
|
else if (parser.getName().equals("packetCollectorSize")) {
|
||||||
packetCollectorSize = parseIntProperty(parser, packetCollectorSize);
|
packetCollectorSize = parseIntProperty(parser, packetCollectorSize);
|
||||||
}
|
}
|
||||||
else if (parser.getName().equals("defaultPingInterval")) {
|
else if (parser.getName().equals("autoEnableEntityCaps")) {
|
||||||
defaultPingInterval = parseIntProperty(parser, defaultPingInterval);
|
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
|
||||||
}
|
}
|
||||||
else if (parser.getName().equals("autoEnableEntityCaps")) {
|
else if (parser.getName().equals("autoEnableEntityCaps")) {
|
||||||
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
|
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
|
||||||
|
@ -320,21 +315,12 @@ public final class SmackConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default ping interval (seconds)
|
* Set if Entity Caps are enabled or disabled for every new connection
|
||||||
*
|
*
|
||||||
* @return
|
* @param true if Entity Caps should be auto enabled, false if not
|
||||||
*/
|
*/
|
||||||
public static int getDefaultPingInterval() {
|
public static void setAutoEnableEntityCaps(boolean b) {
|
||||||
return defaultPingInterval;
|
autoEnableEntityCaps = b;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default ping interval (seconds). Set it to '-1' to disable the periodic ping
|
|
||||||
*
|
|
||||||
* @param defaultPingInterval
|
|
||||||
*/
|
|
||||||
public static void setDefaultPingInterval(int defaultPingInterval) {
|
|
||||||
SmackConfiguration.defaultPingInterval = defaultPingInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -345,15 +331,6 @@ public final class SmackConfiguration {
|
||||||
return autoEnableEntityCaps;
|
return autoEnableEntityCaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set if Entity Caps are enabled or disabled for every new connection
|
|
||||||
*
|
|
||||||
* @param true if Entity Caps should be auto enabled, false if not
|
|
||||||
*/
|
|
||||||
public static void setAutoEnableEntityCaps(boolean b) {
|
|
||||||
autoEnableEntityCaps = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void parseClassToLoad(XmlPullParser parser) throws Exception {
|
private static void parseClassToLoad(XmlPullParser parser) throws Exception {
|
||||||
String className = parser.nextText();
|
String className = parser.nextText();
|
||||||
// Attempt to load the class so that the class can get initialized
|
// Attempt to load the class so that the class can get initialized
|
||||||
|
|
24
source/org/jivesoftware/smack/SmackError.java
Normal file
24
source/org/jivesoftware/smack/SmackError.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package org.jivesoftware.smack;
|
||||||
|
|
||||||
|
public enum SmackError {
|
||||||
|
NO_RESPONSE_FROM_SERVER("No response from server.");
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private SmackError(String errMessage) {
|
||||||
|
message = errMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SmackError getErrorCode(String message) {
|
||||||
|
for (SmackError code : values()) {
|
||||||
|
if (code.message.equals(message)) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -650,10 +650,6 @@ public class XMPPConnection extends Connection {
|
||||||
// Make note of the fact that we're now connected.
|
// Make note of the fact that we're now connected.
|
||||||
connected = true;
|
connected = true;
|
||||||
|
|
||||||
// Start keep alive process (after TLS was negotiated - if available)
|
|
||||||
packetWriter.startKeepAliveProcess();
|
|
||||||
|
|
||||||
|
|
||||||
if (isFirstInitialization) {
|
if (isFirstInitialization) {
|
||||||
// Notify listeners that a new connection has been established
|
// Notify listeners that a new connection has been established
|
||||||
for (ConnectionCreationListener listener : getConnectionCreationListeners()) {
|
for (ConnectionCreationListener listener : getConnectionCreationListeners()) {
|
||||||
|
|
|
@ -41,10 +41,12 @@ import java.io.PrintWriter;
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public class XMPPException extends Exception {
|
public class XMPPException extends Exception {
|
||||||
|
private static final long serialVersionUID = 6881651633890968625L;
|
||||||
|
|
||||||
private StreamError streamError = null;
|
private StreamError streamError = null;
|
||||||
private XMPPError error = null;
|
private XMPPError error = null;
|
||||||
private Throwable wrappedThrowable = null;
|
private Throwable wrappedThrowable = null;
|
||||||
|
private SmackError smackError = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XMPPException.
|
* Creates a new XMPPException.
|
||||||
|
@ -62,6 +64,16 @@ public class XMPPException extends Exception {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new XMPPException with a Smack specific error code.
|
||||||
|
*
|
||||||
|
* @param code the root cause of the exception.
|
||||||
|
*/
|
||||||
|
public XMPPException(SmackError code) {
|
||||||
|
super(code.getErrorMessage());
|
||||||
|
smackError = code;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XMPPException with the Throwable that was the root cause of the
|
* Creates a new XMPPException with the Throwable that was the root cause of the
|
||||||
* exception.
|
* exception.
|
||||||
|
@ -74,7 +86,7 @@ public class XMPPException extends Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cretaes a new XMPPException with the stream error that was the root case of the
|
* Creates a new XMPPException with the stream error that was the root case of the
|
||||||
* exception. When a stream error is received from the server then the underlying
|
* exception. When a stream error is received from the server then the underlying
|
||||||
* TCP connection will be closed by the server.
|
* TCP connection will be closed by the server.
|
||||||
*
|
*
|
||||||
|
@ -144,6 +156,16 @@ public class XMPPException extends Exception {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the SmackError asscociated with this exception, or <tt>null</tt> if there
|
||||||
|
* isn't one.
|
||||||
|
*
|
||||||
|
* @return the SmackError asscociated with this exception.
|
||||||
|
*/
|
||||||
|
public SmackError getSmackError() {
|
||||||
|
return smackError;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the StreamError asscociated with this exception, or <tt>null</tt> if there
|
* Returns the StreamError asscociated with this exception, or <tt>null</tt> if there
|
||||||
* isn't one. The underlying TCP connection is closed by the server after sending the
|
* isn't one. The underlying TCP connection is closed by the server after sending the
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
* Copyright 2003 Jive Software.
|
||||||
*
|
*
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
312
source/org/jivesoftware/smack/keepalive/KeepAliveManager.java
Normal file
312
source/org/jivesoftware/smack/keepalive/KeepAliveManager.java
Normal file
|
@ -0,0 +1,312 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2012-2013 Florian Schmaus
|
||||||
|
*
|
||||||
|
* All rights reserved. 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 org.jivesoftware.smack.keepalive;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.Connection;
|
||||||
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
|
import org.jivesoftware.smack.ConnectionListener;
|
||||||
|
import org.jivesoftware.smack.PacketCollector;
|
||||||
|
import org.jivesoftware.smack.PacketListener;
|
||||||
|
import org.jivesoftware.smack.SmackConfiguration;
|
||||||
|
import org.jivesoftware.smack.filter.PacketFilter;
|
||||||
|
import org.jivesoftware.smack.filter.PacketIDFilter;
|
||||||
|
import org.jivesoftware.smack.packet.Packet;
|
||||||
|
import org.jivesoftware.smack.ping.PingFailedListener;
|
||||||
|
import org.jivesoftware.smack.ping.packet.Ping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using an implementation of <a href="http://www.xmpp.org/extensions/xep-0199.html">XMPP Ping (XEP-0199)</a>. This
|
||||||
|
* class provides keepalive functionality with the server that will periodically "ping" the server to maintain and/or
|
||||||
|
* verify that the connection still exists.
|
||||||
|
* <p>
|
||||||
|
* The ping is done at the application level and is therefore protocol agnostic. It will thus work for both standard TCP
|
||||||
|
* connections as well as BOSH or any other transport protocol. It will also work regardless of whether the server
|
||||||
|
* supports the Ping extension, since an error response to the ping serves the same purpose as a pong.
|
||||||
|
*
|
||||||
|
* @author Florian Schmaus
|
||||||
|
*/
|
||||||
|
public class KeepAliveManager {
|
||||||
|
private static Map<Connection, KeepAliveManager> instances = new HashMap<Connection, KeepAliveManager>();
|
||||||
|
private static volatile ScheduledExecutorService periodicPingExecutorService;
|
||||||
|
|
||||||
|
static {
|
||||||
|
if (SmackConfiguration.getKeepAliveInterval() > 0) {
|
||||||
|
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
|
public void connectionCreated(Connection connection) {
|
||||||
|
new KeepAliveManager(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Connection connection;
|
||||||
|
private long pingInterval = SmackConfiguration.getKeepAliveInterval();
|
||||||
|
private Set<PingFailedListener> pingFailedListeners = Collections.synchronizedSet(new HashSet<PingFailedListener>());
|
||||||
|
private volatile ScheduledFuture<?> periodicPingTask;
|
||||||
|
private volatile long lastSuccessfulContact = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a {@link KeepAliveManager} for the specified {@link Connection}, creating one if it doesn't already
|
||||||
|
* exist.
|
||||||
|
*
|
||||||
|
* @param connection
|
||||||
|
* The connection the manager is attached to.
|
||||||
|
* @return The new or existing manager.
|
||||||
|
*/
|
||||||
|
public synchronized static KeepAliveManager getInstanceFor(Connection connection) {
|
||||||
|
KeepAliveManager pingManager = instances.get(connection);
|
||||||
|
|
||||||
|
if (pingManager == null) {
|
||||||
|
pingManager = new KeepAliveManager(connection);
|
||||||
|
instances.put(connection, pingManager);
|
||||||
|
}
|
||||||
|
return pingManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the executor service if it hasn't been started yet.
|
||||||
|
*/
|
||||||
|
private synchronized static void enableExecutorService() {
|
||||||
|
if (periodicPingExecutorService == null) {
|
||||||
|
periodicPingExecutorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable runnable) {
|
||||||
|
Thread pingThread = new Thread(runnable, "Smack Keepalive");
|
||||||
|
pingThread.setDaemon(true);
|
||||||
|
return pingThread;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop the executor service if all monitored connections are disconnected.
|
||||||
|
*/
|
||||||
|
private synchronized static void handleDisconnect(Connection con) {
|
||||||
|
if (periodicPingExecutorService != null) {
|
||||||
|
instances.remove(con);
|
||||||
|
|
||||||
|
if (instances.isEmpty()) {
|
||||||
|
periodicPingExecutorService.shutdownNow();
|
||||||
|
periodicPingExecutorService = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeepAliveManager(Connection connection) {
|
||||||
|
this.connection = connection;
|
||||||
|
init();
|
||||||
|
handleConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call after every connection to add the packet listener.
|
||||||
|
*/
|
||||||
|
private void handleConnect() {
|
||||||
|
// Listen for all incoming packets and reset the scheduled ping whenever
|
||||||
|
// one arrives.
|
||||||
|
connection.addPacketListener(new PacketListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processPacket(Packet packet) {
|
||||||
|
// reschedule the ping based on this last server contact
|
||||||
|
lastSuccessfulContact = System.currentTimeMillis();
|
||||||
|
schedulePingServerTask();
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
connection.addConnectionListener(new ConnectionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectionClosed() {
|
||||||
|
stopPingServerTask();
|
||||||
|
handleDisconnect(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectionClosedOnError(Exception arg0) {
|
||||||
|
stopPingServerTask();
|
||||||
|
handleDisconnect(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reconnectionSuccessful() {
|
||||||
|
handleConnect();
|
||||||
|
schedulePingServerTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reconnectingIn(int seconds) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reconnectionFailed(Exception e) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
instances.put(connection, this);
|
||||||
|
schedulePingServerTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ping interval.
|
||||||
|
*
|
||||||
|
* @param pingInterval
|
||||||
|
* The new ping time interval in milliseconds.
|
||||||
|
*/
|
||||||
|
public void setPingInterval(long newPingInterval) {
|
||||||
|
if (pingInterval == newPingInterval)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Enable the executor service
|
||||||
|
if (newPingInterval > 0)
|
||||||
|
enableExecutorService();
|
||||||
|
|
||||||
|
pingInterval = newPingInterval;
|
||||||
|
|
||||||
|
if (pingInterval < 0) {
|
||||||
|
stopPinging();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
schedulePingServerTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops pinging the server. This cannot stop a ping that has already started, but will prevent another from being triggered.
|
||||||
|
* <p>
|
||||||
|
* To restart, call {@link #setPingInterval(long)}.
|
||||||
|
*/
|
||||||
|
public void stopPinging() {
|
||||||
|
pingInterval = -1;
|
||||||
|
stopPingServerTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ping interval.
|
||||||
|
*
|
||||||
|
* @return The ping interval in milliseconds.
|
||||||
|
*/
|
||||||
|
public long getPingInterval() {
|
||||||
|
return pingInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add listener for notification when a server ping fails.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Please note that this doesn't necessarily mean that the connection is lost, a slow to respond server could also
|
||||||
|
* cause a failure due to taking too long to respond and thus causing a reply timeout.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
* The listener to be called
|
||||||
|
*/
|
||||||
|
public void addPingFailedListener(PingFailedListener listener) {
|
||||||
|
pingFailedListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the listener.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
* The listener to be removed.
|
||||||
|
*/
|
||||||
|
public void removePingFailedListener(PingFailedListener listener) {
|
||||||
|
pingFailedListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the elapsed time (in milliseconds) since the last successful contact with the server
|
||||||
|
* (i.e. the last time any message was received).
|
||||||
|
* <p>
|
||||||
|
* <b>Note</b>: Result is -1 if no message has been received since manager was created and
|
||||||
|
* 0 if the elapsed time is negative due to a clock reset.
|
||||||
|
*
|
||||||
|
* @return Elapsed time since last message was received.
|
||||||
|
*/
|
||||||
|
public long getTimeSinceLastContact() {
|
||||||
|
if (lastSuccessfulContact == -1)
|
||||||
|
return lastSuccessfulContact;
|
||||||
|
long delta = System.currentTimeMillis() - lastSuccessfulContact;
|
||||||
|
|
||||||
|
return (delta < 0) ? 0 : delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels any existing periodic ping task if there is one and schedules a new ping task if pingInterval is greater
|
||||||
|
* then zero.
|
||||||
|
*
|
||||||
|
* This is designed so only one executor is used for scheduling all pings on all connections. This results in only 1 thread used for pinging.
|
||||||
|
*/
|
||||||
|
private synchronized void schedulePingServerTask() {
|
||||||
|
enableExecutorService();
|
||||||
|
stopPingServerTask();
|
||||||
|
|
||||||
|
if (pingInterval > 0) {
|
||||||
|
periodicPingTask = periodicPingExecutorService.schedule(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Ping ping = new Ping();
|
||||||
|
PacketFilter responseFilter = new PacketIDFilter(ping.getPacketID());
|
||||||
|
final PacketCollector response = connection.createPacketCollector(responseFilter);
|
||||||
|
connection.sendPacket(ping);
|
||||||
|
|
||||||
|
if (!pingFailedListeners.isEmpty()) {
|
||||||
|
// Schedule a collector for the ping reply, notify listeners if none is received.
|
||||||
|
periodicPingExecutorService.schedule(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Packet result = response.nextResult(1);
|
||||||
|
|
||||||
|
// Stop queuing results
|
||||||
|
response.cancel();
|
||||||
|
|
||||||
|
// The actual result of the reply can be ignored since we only care if we actually got one.
|
||||||
|
if (result == null) {
|
||||||
|
for (PingFailedListener listener : pingFailedListeners) {
|
||||||
|
listener.pingFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, SmackConfiguration.getPacketReplyTimeout(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, getPingInterval(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopPingServerTask() {
|
||||||
|
if (periodicPingTask != null) {
|
||||||
|
periodicPingTask.cancel(true);
|
||||||
|
periodicPingTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -14,8 +14,14 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jivesoftware.smackx.ping;
|
package org.jivesoftware.smack.ping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the callback used whenever the server ping fails.
|
||||||
|
*/
|
||||||
public interface PingFailedListener {
|
public interface PingFailedListener {
|
||||||
|
/**
|
||||||
|
* Called when the server ping fails.
|
||||||
|
*/
|
||||||
void pingFailed();
|
void pingFailed();
|
||||||
}
|
}
|
|
@ -14,25 +14,26 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jivesoftware.smackx.ping.packet;
|
package org.jivesoftware.smack.ping.packet;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smackx.ping.PingManager;
|
import org.jivesoftware.smackx.ping.PingManager;
|
||||||
|
|
||||||
public class Ping extends IQ {
|
public class Ping extends IQ {
|
||||||
|
|
||||||
|
public static final String NAMESPACE = "urn:xmpp:ping";
|
||||||
|
public static final String ELEMENT = "ping";
|
||||||
|
|
||||||
public Ping() {
|
public Ping() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Ping(String from, String to) {
|
public Ping(String to) {
|
||||||
setTo(to);
|
setTo(to);
|
||||||
setFrom(from);
|
|
||||||
setType(IQ.Type.GET);
|
setType(IQ.Type.GET);
|
||||||
setPacketID(getPacketID());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getChildElementXML() {
|
public String getChildElementXML() {
|
||||||
return "<" + PingManager.ELEMENT + " xmlns=\'" + PingManager.NAMESPACE + "\' />";
|
return "<" + ELEMENT + " xmlns=\'" + NAMESPACE + "\' />";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -14,11 +14,11 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jivesoftware.smackx.ping.provider;
|
package org.jivesoftware.smack.ping.provider;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.ping.packet.Ping;
|
||||||
import org.jivesoftware.smack.provider.IQProvider;
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
import org.jivesoftware.smackx.ping.packet.Ping;
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
public class PingProvider implements IQProvider {
|
public class PingProvider implements IQProvider {
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
@ -92,8 +90,7 @@ class HTTPProxySocketFactory
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
String password = proxy.getProxyPassword();
|
String password = proxy.getProxyPassword();
|
||||||
proxyLine = "\r\nProxy-Authorization: Basic "
|
proxyLine = "\r\nProxy-Authorization: Basic " + StringUtils.encodeBase64(username + ":" + password);
|
||||||
+ new String(StringUtils.encodeBase64(username + ":" + password));
|
|
||||||
}
|
}
|
||||||
socket.getOutputStream().write((hostport + " HTTP/1.1\r\nHost: "
|
socket.getOutputStream().write((hostport + " HTTP/1.1\r\nHost: "
|
||||||
+ hostport + proxyLine + "\r\n\r\n").getBytes("UTF-8"));
|
+ hostport + proxyLine + "\r\n\r\n").getBytes("UTF-8"));
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -51,6 +51,30 @@ import javax.security.sasl.SaslException;
|
||||||
* using the CallbackHandler method.</li>
|
* using the CallbackHandler method.</li>
|
||||||
* <li>{@link #challengeReceived(String)} -- Handle a challenge from the server.</li>
|
* <li>{@link #challengeReceived(String)} -- Handle a challenge from the server.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
|
* Basic XMPP SASL authentication steps:
|
||||||
|
* 1. Client authentication initialization, stanza sent to the server (Base64 encoded):
|
||||||
|
* <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>
|
||||||
|
* 2. Server sends back to the client the challenge response (Base64 encoded)
|
||||||
|
* sample:
|
||||||
|
* realm=<sasl server realm>,nonce="OA6MG9tEQGm2hh",qop="auth",charset=utf-8,algorithm=md5-sess
|
||||||
|
* 3. The client responds back to the server (Base 64 encoded):
|
||||||
|
* sample:
|
||||||
|
* username=<userid>,realm=<sasl server realm from above>,nonce="OA6MG9tEQGm2hh",
|
||||||
|
* cnonce="OA6MHXh6VqTrRk",nc=00000001,qop=auth,
|
||||||
|
* digest-uri=<digesturi>,
|
||||||
|
* response=d388dad90d4bbd760a152321f2143af7,
|
||||||
|
* charset=utf-8,
|
||||||
|
* authzid=<id>
|
||||||
|
* 4. The server evaluates if the user is present and contained in the REALM
|
||||||
|
* if successful it sends: <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/> (Base64 encoded)
|
||||||
|
* if not successful it sends:
|
||||||
|
* sample:
|
||||||
|
* <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
|
||||||
|
* cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZA==
|
||||||
|
* </challenge>
|
||||||
|
*
|
||||||
|
|
||||||
*
|
*
|
||||||
* @author Jay Kline
|
* @author Jay Kline
|
||||||
*/
|
*/
|
||||||
|
@ -62,7 +86,6 @@ public abstract class SASLMechanism implements CallbackHandler {
|
||||||
protected String password;
|
protected String password;
|
||||||
protected String hostname;
|
protected String hostname;
|
||||||
|
|
||||||
|
|
||||||
public SASLMechanism(SASLAuthentication saslAuthentication) {
|
public SASLMechanism(SASLAuthentication saslAuthentication) {
|
||||||
this.saslAuthentication = saslAuthentication;
|
this.saslAuthentication = saslAuthentication;
|
||||||
}
|
}
|
||||||
|
@ -72,13 +95,49 @@ public abstract class SASLMechanism implements CallbackHandler {
|
||||||
* authentication is not recommended, since it is very inflexable. Use
|
* authentication is not recommended, since it is very inflexable. Use
|
||||||
* {@link #authenticate(String, String, CallbackHandler)} whenever possible.
|
* {@link #authenticate(String, String, CallbackHandler)} whenever possible.
|
||||||
*
|
*
|
||||||
|
* Explanation of auth stanza:
|
||||||
|
*
|
||||||
|
* The client authentication stanza needs to include the digest-uri of the form: xmpp/serverName
|
||||||
|
* From RFC-2831:
|
||||||
|
* digest-uri = "digest-uri" "=" digest-uri-value
|
||||||
|
* digest-uri-value = serv-type "/" host [ "/" serv-name ]
|
||||||
|
*
|
||||||
|
* digest-uri:
|
||||||
|
* Indicates the principal name of the service with which the client
|
||||||
|
* wishes to connect, formed from the serv-type, host, and serv-name.
|
||||||
|
* For example, the FTP service
|
||||||
|
* on "ftp.example.com" would have a "digest-uri" value of "ftp/ftp.example.com"; the SMTP
|
||||||
|
* server from the example above would have a "digest-uri" value of
|
||||||
|
* "smtp/mail3.example.com/example.com".
|
||||||
|
*
|
||||||
|
* host:
|
||||||
|
* The DNS host name or IP address for the service requested. The DNS host name
|
||||||
|
* must be the fully-qualified canonical name of the host. The DNS host name is the
|
||||||
|
* preferred form; see notes on server processing of the digest-uri.
|
||||||
|
*
|
||||||
|
* serv-name:
|
||||||
|
* Indicates the name of the service if it is replicated. The service is
|
||||||
|
* considered to be replicated if the client's service-location process involves resolution
|
||||||
|
* using standard DNS lookup operations, and if these operations involve DNS records (such
|
||||||
|
* as SRV, or MX) which resolve one DNS name into a set of other DNS names. In this case,
|
||||||
|
* the initial name used by the client is the "serv-name", and the final name is the "host"
|
||||||
|
* component. For example, the incoming mail service for "example.com" may be replicated
|
||||||
|
* through the use of MX records stored in the DNS, one of which points at an SMTP server
|
||||||
|
* called "mail3.example.com"; it's "serv-name" would be "example.com", it's "host" would be
|
||||||
|
* "mail3.example.com". If the service is not replicated, or the serv-name is identical to
|
||||||
|
* the host, then the serv-name component MUST be omitted
|
||||||
|
*
|
||||||
|
* digest-uri verification is needed for ejabberd 2.0.3 and higher
|
||||||
|
*
|
||||||
* @param username the username of the user being authenticated.
|
* @param username the username of the user being authenticated.
|
||||||
* @param host the hostname where the user account resides.
|
* @param host the hostname where the user account resides.
|
||||||
|
* @param serviceName the xmpp service location - used by the SASL client in digest-uri creation
|
||||||
|
* serviceName format is: host [ "/" serv-name ] as per RFC-2831
|
||||||
* @param password the password for this account.
|
* @param password the password for this account.
|
||||||
* @throws IOException If a network error occurs while authenticating.
|
* @throws IOException If a network error occurs while authenticating.
|
||||||
* @throws XMPPException If a protocol error occurs or the user is not authenticated.
|
* @throws XMPPException If a protocol error occurs or the user is not authenticated.
|
||||||
*/
|
*/
|
||||||
public void authenticate(String username, String host, String password) throws IOException, XMPPException {
|
public void authenticate(String username, String host, String serviceName, String password) throws IOException, XMPPException {
|
||||||
//Since we were not provided with a CallbackHandler, we will use our own with the given
|
//Since we were not provided with a CallbackHandler, we will use our own with the given
|
||||||
//information
|
//information
|
||||||
|
|
||||||
|
@ -89,10 +148,26 @@ public abstract class SASLMechanism implements CallbackHandler {
|
||||||
|
|
||||||
String[] mechanisms = { getName() };
|
String[] mechanisms = { getName() };
|
||||||
Map<String,String> props = new HashMap<String,String>();
|
Map<String,String> props = new HashMap<String,String>();
|
||||||
sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
|
sc = Sasl.createSaslClient(mechanisms, username, "xmpp", serviceName, props, this);
|
||||||
authenticate();
|
authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link #authenticate(String, String, String, String)}, but with the hostname used as the serviceName.
|
||||||
|
* <p>
|
||||||
|
* Kept for backward compatibility only.
|
||||||
|
*
|
||||||
|
* @param username the username of the user being authenticated.
|
||||||
|
* @param host the hostname where the user account resides.
|
||||||
|
* @param password the password for this account.
|
||||||
|
* @throws IOException If a network error occurs while authenticating.
|
||||||
|
* @throws XMPPException If a protocol error occurs or the user is not authenticated.
|
||||||
|
* @deprecated Please use {@link #authenticate(String, String, String, String)} instead.
|
||||||
|
*/
|
||||||
|
public void authenticate(String username, String host, String password) throws IOException, XMPPException {
|
||||||
|
authenticate(username, host, host, password);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and sends the <tt>auth</tt> stanza to the server. The callback handler will handle
|
* Builds and sends the <tt>auth</tt> stanza to the server. The callback handler will handle
|
||||||
* any additional information, such as the authentication ID or realm, if it is needed.
|
* any additional information, such as the authentication ID or realm, if it is needed.
|
||||||
|
@ -178,7 +253,13 @@ public abstract class SASLMechanism implements CallbackHandler {
|
||||||
pcb.setPassword(password.toCharArray());
|
pcb.setPassword(password.toCharArray());
|
||||||
} else if(callbacks[i] instanceof RealmCallback) {
|
} else if(callbacks[i] instanceof RealmCallback) {
|
||||||
RealmCallback rcb = (RealmCallback)callbacks[i];
|
RealmCallback rcb = (RealmCallback)callbacks[i];
|
||||||
rcb.setText(hostname);
|
//Retrieve the REALM from the challenge response that the server returned when the client initiated the authentication
|
||||||
|
//exchange. If this value is not null or empty, *this value* has to be sent back to the server in the client's response
|
||||||
|
//to the server's challenge
|
||||||
|
String text = rcb.getDefaultText();
|
||||||
|
//The SASL client (sc) created in smack uses rcb.getText when creating the negotiatedRealm to send it back to the server
|
||||||
|
//Make sure that this value matches the server's realm
|
||||||
|
rcb.setText(text);
|
||||||
} else if(callbacks[i] instanceof RealmChoiceCallback){
|
} else if(callbacks[i] instanceof RealmChoiceCallback){
|
||||||
//unused
|
//unused
|
||||||
//RealmChoiceCallback rccb = (RealmChoiceCallback)callbacks[i];
|
//RealmChoiceCallback rccb = (RealmChoiceCallback)callbacks[i];
|
||||||
|
|
|
@ -29,7 +29,7 @@ import java.io.IOException;
|
||||||
*/
|
*/
|
||||||
public class Base32Encoder implements StringEncoder {
|
public class Base32Encoder implements StringEncoder {
|
||||||
|
|
||||||
private static Base32Encoder instance;
|
private static Base32Encoder instance = new Base32Encoder();
|
||||||
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ2345678";
|
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ2345678";
|
||||||
|
|
||||||
private Base32Encoder() {
|
private Base32Encoder() {
|
||||||
|
@ -37,9 +37,6 @@ public class Base32Encoder implements StringEncoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Base32Encoder getInstance() {
|
public static Base32Encoder getInstance() {
|
||||||
if (instance == null) {
|
|
||||||
instance = new Base32Encoder();
|
|
||||||
}
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,65 +8,8 @@ package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Encodes and decodes to and from Base64 notation.</p>
|
* <p>Encodes and decodes to and from Base64 notation.</p>
|
||||||
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
|
* This code was obtained from <a href="http://iharder.net/base64">http://iharder.net/base64</a></p>
|
||||||
*
|
*
|
||||||
* <p>
|
|
||||||
* Change Log:
|
|
||||||
* </p>
|
|
||||||
* <ul>
|
|
||||||
* <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
|
|
||||||
* when using very small files (~< 40 bytes).</li>
|
|
||||||
* <li>v2.2 - Added some helper methods for encoding/decoding directly from
|
|
||||||
* one file to the next. Also added a main() method to support command line
|
|
||||||
* encoding/decoding from one file to the next. Also added these Base64 dialects:
|
|
||||||
* <ol>
|
|
||||||
* <li>The default is RFC3548 format.</li>
|
|
||||||
* <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
|
|
||||||
* URL and file name friendly format as described in Section 4 of RFC3548.
|
|
||||||
* http://www.faqs.org/rfcs/rfc3548.html</li>
|
|
||||||
* <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
|
|
||||||
* URL and file name friendly format that preserves lexical ordering as described
|
|
||||||
* in http://www.faqs.org/qa/rfcc-1940.html</li>
|
|
||||||
* </ol>
|
|
||||||
* Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
|
|
||||||
* for contributing the new Base64 dialects.
|
|
||||||
* </li>
|
|
||||||
*
|
|
||||||
* <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
|
|
||||||
* some convenience methods for reading and writing to and from files.</li>
|
|
||||||
* <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
|
|
||||||
* with other encodings (like EBCDIC).</li>
|
|
||||||
* <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
|
|
||||||
* encoded data was a single byte.</li>
|
|
||||||
* <li>v2.0 - I got rid of methods that used booleans to set options.
|
|
||||||
* Now everything is more consolidated and cleaner. The code now detects
|
|
||||||
* when data that's being decoded is gzip-compressed and will decompress it
|
|
||||||
* automatically. Generally things are cleaner. You'll probably have to
|
|
||||||
* change some method calls that you were making to support the new
|
|
||||||
* options format (<tt>int</tt>s that you "OR" together).</li>
|
|
||||||
* <li>v1.5.1 - Fixed bug when decompressing and decoding to a
|
|
||||||
* byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.
|
|
||||||
* Added the ability to "suspend" encoding in the Output Stream so
|
|
||||||
* you can turn on and off the encoding if you need to embed base64
|
|
||||||
* data in an otherwise "normal" stream (like an XML file).</li>
|
|
||||||
* <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
|
|
||||||
* This helps when using GZIP streams.
|
|
||||||
* Added the ability to GZip-compress objects before encoding them.</li>
|
|
||||||
* <li>v1.4 - Added helper methods to read/write files.</li>
|
|
||||||
* <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
|
|
||||||
* <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
|
|
||||||
* where last buffer being read, if not completely full, was not returned.</li>
|
|
||||||
* <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
|
|
||||||
* <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* I am placing this code in the Public Domain. Do with it as you will.
|
|
||||||
* This software comes with no guarantees or warranties but with
|
|
||||||
* plenty of well-wishing instead!
|
|
||||||
* Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
|
|
||||||
* periodically to check for updates or to contribute improvements.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @author Robert Harder
|
* @author Robert Harder
|
||||||
* @author rob@iharder.net
|
* @author rob@iharder.net
|
||||||
|
@ -368,33 +311,6 @@ public class Base64
|
||||||
/** Defeats instantiation. */
|
/** Defeats instantiation. */
|
||||||
private Base64(){}
|
private Base64(){}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes or decodes two files from the command line;
|
|
||||||
* <strong>feel free to delete this method (in fact you probably should)
|
|
||||||
* if you're embedding this code into a larger program.</strong>
|
|
||||||
*/
|
|
||||||
public final static void main( String[] args )
|
|
||||||
{
|
|
||||||
if( args.length < 3 ){
|
|
||||||
usage("Not enough arguments.");
|
|
||||||
} // end if: args.length < 3
|
|
||||||
else {
|
|
||||||
String flag = args[0];
|
|
||||||
String infile = args[1];
|
|
||||||
String outfile = args[2];
|
|
||||||
if( flag.equals( "-e" ) ){
|
|
||||||
Base64.encodeFileToFile( infile, outfile );
|
|
||||||
} // end if: encode
|
|
||||||
else if( flag.equals( "-d" ) ) {
|
|
||||||
Base64.decodeFileToFile( infile, outfile );
|
|
||||||
} // end else if: decode
|
|
||||||
else {
|
|
||||||
usage( "Unknown flag: " + flag );
|
|
||||||
} // end else
|
|
||||||
} // end else
|
|
||||||
} // end main
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints command line usage.
|
* Prints command line usage.
|
||||||
*
|
*
|
||||||
|
|
|
@ -16,20 +16,18 @@ package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A Base 64 encoding implementation.
|
||||||
* @author Florian Schmaus
|
* @author Florian Schmaus
|
||||||
*/
|
*/
|
||||||
public class Base64Encoder implements StringEncoder {
|
public class Base64Encoder implements StringEncoder {
|
||||||
|
|
||||||
private static Base64Encoder instance;
|
private static Base64Encoder instance = new Base64Encoder();
|
||||||
|
|
||||||
private Base64Encoder() {
|
private Base64Encoder() {
|
||||||
// Use getInstance()
|
// Use getInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Base64Encoder getInstance() {
|
public static Base64Encoder getInstance() {
|
||||||
if (instance == null) {
|
|
||||||
instance = new Base64Encoder();
|
|
||||||
}
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
48
source/org/jivesoftware/smack/util/Base64FileUrlEncoder.java
Normal file
48
source/org/jivesoftware/smack/util/Base64FileUrlEncoder.java
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* All rights reserved. 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 org.jivesoftware.smack.util;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Base 64 encoding implementation that generates filename and Url safe encodings.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Note: This does NOT produce standard Base 64 encodings, but a variant as defined in
|
||||||
|
* Section 4 of RFC3548:
|
||||||
|
* <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
|
||||||
|
*
|
||||||
|
* @author Robin Collier
|
||||||
|
*/
|
||||||
|
public class Base64FileUrlEncoder implements StringEncoder {
|
||||||
|
|
||||||
|
private static Base64FileUrlEncoder instance = new Base64FileUrlEncoder();
|
||||||
|
|
||||||
|
private Base64FileUrlEncoder() {
|
||||||
|
// Use getInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Base64FileUrlEncoder getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String encode(String s) {
|
||||||
|
return Base64.encodeBytes(s.getBytes(), Base64.URL_SAFE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String decode(String s) {
|
||||||
|
return new String(Base64.decode(s, Base64.URL_SAFE));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -81,7 +81,12 @@ public class DNSUtil {
|
||||||
* @return List of HostAddress, which encompasses the hostname and port that the
|
* @return List of HostAddress, which encompasses the hostname and port that the
|
||||||
* XMPP server can be reached at for the specified domain.
|
* XMPP server can be reached at for the specified domain.
|
||||||
*/
|
*/
|
||||||
public static List<HostAddress> resolveXMPPDomain(String domain) {
|
public static List<HostAddress> resolveXMPPDomain(final String domain) {
|
||||||
|
if (dnsResolver == null) {
|
||||||
|
List<HostAddress> addresses = new ArrayList<HostAddress>(1);
|
||||||
|
addresses.add(new HostAddress(domain, 5222));
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
return resolveDomain(domain, 'c');
|
return resolveDomain(domain, 'c');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +107,12 @@ public class DNSUtil {
|
||||||
* @return List of HostAddress, which encompasses the hostname and port that the
|
* @return List of HostAddress, which encompasses the hostname and port that the
|
||||||
* XMPP server can be reached at for the specified domain.
|
* XMPP server can be reached at for the specified domain.
|
||||||
*/
|
*/
|
||||||
public static List<HostAddress> resolveXMPPServerDomain(String domain) {
|
public static List<HostAddress> resolveXMPPServerDomain(final String domain) {
|
||||||
|
if (dnsResolver == null) {
|
||||||
|
List<HostAddress> addresses = new ArrayList<HostAddress>(1);
|
||||||
|
addresses.add(new HostAddress(domain, 5269));
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
return resolveDomain(domain, 's');
|
return resolveDomain(domain, 's');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,9 +127,6 @@ public class DNSUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dnsResolver == null)
|
|
||||||
throw new IllegalStateException("No DNS resolver active.");
|
|
||||||
|
|
||||||
List<HostAddress> addresses = new ArrayList<HostAddress>();
|
List<HostAddress> addresses = new ArrayList<HostAddress>();
|
||||||
|
|
||||||
// Step one: Do SRV lookups
|
// Step one: Do SRV lookups
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
* Copyright 2013 Robin Collier.
|
||||||
*
|
*
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -23,11 +23,12 @@ import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the various date and time profiles used in XMPP along with their associated formats.
|
* Defines the various date and time profiles used in XMPP along with their associated formats.
|
||||||
|
*
|
||||||
* @author Robin Collier
|
* @author Robin Collier
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public enum DateFormatType
|
public enum DateFormatType {
|
||||||
{
|
// @formatter:off
|
||||||
XEP_0082_DATE_PROFILE("yyyy-MM-dd"),
|
XEP_0082_DATE_PROFILE("yyyy-MM-dd"),
|
||||||
XEP_0082_DATETIME_PROFILE("yyyy-MM-dd'T'HH:mm:ssZ"),
|
XEP_0082_DATETIME_PROFILE("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||||
XEP_0082_DATETIME_MILLIS_PROFILE("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),
|
XEP_0082_DATETIME_MILLIS_PROFILE("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),
|
||||||
|
@ -36,29 +37,29 @@ public enum DateFormatType
|
||||||
XEP_0082_TIME_MILLIS_PROFILE("hh:mm:ss.SSS"),
|
XEP_0082_TIME_MILLIS_PROFILE("hh:mm:ss.SSS"),
|
||||||
XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSSZ"),
|
XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSSZ"),
|
||||||
XEP_0091_DATETIME("yyyyMMdd'T'HH:mm:ss");
|
XEP_0091_DATETIME("yyyyMMdd'T'HH:mm:ss");
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
private String formatString;
|
private String formatString;
|
||||||
|
|
||||||
private DateFormatType(String dateFormat)
|
private DateFormatType(String dateFormat) {
|
||||||
{
|
|
||||||
formatString = dateFormat;
|
formatString = dateFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the format string as defined in either XEP-0082 or XEP-0091.
|
* Get the format string as defined in either XEP-0082 or XEP-0091.
|
||||||
|
*
|
||||||
* @return The defined string format for the date.
|
* @return The defined string format for the date.
|
||||||
*/
|
*/
|
||||||
public String getFormatString()
|
public String getFormatString() {
|
||||||
{
|
|
||||||
return formatString;
|
return formatString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a {@link SimpleDateFormat} object with the format defined by {@link #getFormatString()}.
|
* Create a {@link SimpleDateFormat} object with the format defined by {@link #getFormatString()}.
|
||||||
|
*
|
||||||
* @return A new date formatter.
|
* @return A new date formatter.
|
||||||
*/
|
*/
|
||||||
public SimpleDateFormat createFormatter()
|
public SimpleDateFormat createFormatter() {
|
||||||
{
|
|
||||||
return new SimpleDateFormat(getFormatString());
|
return new SimpleDateFormat(getFormatString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.util;
|
package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
// TODO move StringEncoder, Base64Encoder and Base32Encoder to smack.util
|
|
||||||
|
|
||||||
public interface StringEncoder {
|
public interface StringEncoder {
|
||||||
/**
|
/**
|
||||||
* Encodes an string to another representation
|
* Encodes an string to another representation
|
||||||
|
@ -26,7 +24,7 @@ public interface StringEncoder {
|
||||||
* @param string
|
* @param string
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String encode(String string);
|
String encode(String string);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes an string back to it's initial representation
|
* Decodes an string back to it's initial representation
|
||||||
|
@ -34,5 +32,5 @@ public interface StringEncoder {
|
||||||
* @param string
|
* @param string
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String decode(String string);
|
String decode(String string);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ package org.jivesoftware.smack.util;
|
||||||
import org.jivesoftware.smack.PacketCollector;
|
import org.jivesoftware.smack.PacketCollector;
|
||||||
import org.jivesoftware.smack.SmackConfiguration;
|
import org.jivesoftware.smack.SmackConfiguration;
|
||||||
import org.jivesoftware.smack.Connection;
|
import org.jivesoftware.smack.Connection;
|
||||||
|
import org.jivesoftware.smack.SmackError;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
import org.jivesoftware.smack.filter.PacketFilter;
|
import org.jivesoftware.smack.filter.PacketFilter;
|
||||||
import org.jivesoftware.smack.filter.PacketIDFilter;
|
import org.jivesoftware.smack.filter.PacketIDFilter;
|
||||||
|
@ -47,7 +48,7 @@ final public class SyncPacketSend
|
||||||
response.cancel();
|
response.cancel();
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new XMPPException("No response from server.");
|
throw new XMPPException(SmackError.NO_RESPONSE_FROM_SERVER);
|
||||||
}
|
}
|
||||||
else if (result.getError() != null) {
|
else if (result.getError() != null) {
|
||||||
throw new XMPPException(result.getError());
|
throw new XMPPException(result.getError());
|
||||||
|
|
|
@ -22,18 +22,19 @@ import org.xbill.DNS.Lookup;
|
||||||
import org.xbill.DNS.Record;
|
import org.xbill.DNS.Record;
|
||||||
import org.xbill.DNS.Type;
|
import org.xbill.DNS.Type;
|
||||||
|
|
||||||
public class DNSJavaResolver extends DNSResolver {
|
/**
|
||||||
|
* This implementation uses the <a href="http://www.dnsjava.org/">dnsjava</a> implementation for resolving DNS addresses.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DNSJavaResolver implements DNSResolver {
|
||||||
|
|
||||||
private static DNSJavaResolver instance;
|
private static DNSJavaResolver instance = new DNSJavaResolver();
|
||||||
|
|
||||||
private DNSJavaResolver() {
|
private DNSJavaResolver() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DNSResolver getInstance() {
|
public static DNSResolver getInstance() {
|
||||||
if (instance == null) {
|
|
||||||
instance = new DNSJavaResolver();
|
|
||||||
}
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,17 @@ package org.jivesoftware.smack.util.dns;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class DNSResolver {
|
/**
|
||||||
|
* Implementations of this interface define a class that is capable of resolving DNS addresses.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface DNSResolver {
|
||||||
|
|
||||||
public abstract List<SRVRecord> lookupSRVRecords(String name);
|
/**
|
||||||
|
* Gets a list of service records for the specified service.
|
||||||
|
* @param name The symbolic name of the service.
|
||||||
|
* @return The list of SRV records mapped to the service name.
|
||||||
|
*/
|
||||||
|
List<SRVRecord> lookupSRVRecords(String name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,10 @@ public class HostAddress {
|
||||||
/**
|
/**
|
||||||
* Creates a new HostAddress with the given FQDN. The port will be set to the default XMPP client port: 5222
|
* Creates a new HostAddress with the given FQDN. The port will be set to the default XMPP client port: 5222
|
||||||
*
|
*
|
||||||
* @param fqdn
|
* @param fqdn Fully qualified domain name.
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException If the fqdn is null.
|
||||||
*/
|
*/
|
||||||
public HostAddress(String fqdn) throws IllegalArgumentException {
|
public HostAddress(String fqdn) {
|
||||||
if (fqdn == null)
|
if (fqdn == null)
|
||||||
throw new IllegalArgumentException("FQDN is null");
|
throw new IllegalArgumentException("FQDN is null");
|
||||||
if (fqdn.charAt(fqdn.length() - 1) == '.') {
|
if (fqdn.charAt(fqdn.length() - 1) == '.') {
|
||||||
|
@ -39,7 +39,14 @@ public class HostAddress {
|
||||||
this.port = 5222;
|
this.port = 5222;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HostAddress(String fqdn, int port) throws IllegalArgumentException {
|
/**
|
||||||
|
* Creates a new HostAddress with the given FQDN. The port will be set to the default XMPP client port: 5222
|
||||||
|
*
|
||||||
|
* @param fqdn Fully qualified domain name.
|
||||||
|
* @param port The port to connect on.
|
||||||
|
* @throws IllegalArgumentException If the fqdn is null or port is out of valid range (0 - 65535).
|
||||||
|
*/
|
||||||
|
public HostAddress(String fqdn, int port) {
|
||||||
this(fqdn);
|
this(fqdn);
|
||||||
if (port < 0 || port > 65535)
|
if (port < 0 || port > 65535)
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -60,10 +67,12 @@ public class HostAddress {
|
||||||
this.exception = e;
|
this.exception = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return fqdn + ":" + port;
|
return fqdn + ":" + port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -80,6 +89,13 @@ public class HostAddress {
|
||||||
return port == address.port;
|
return port == address.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 37 * result + fqdn.hashCode();
|
||||||
|
return result * 37 + port;
|
||||||
|
}
|
||||||
|
|
||||||
public String getErrorMessage() {
|
public String getErrorMessage() {
|
||||||
String error;
|
String error;
|
||||||
if (exception == null) {
|
if (exception == null) {
|
||||||
|
|
|
@ -28,12 +28,12 @@ import javax.naming.directory.InitialDirContext;
|
||||||
import org.jivesoftware.smack.util.DNSUtil;
|
import org.jivesoftware.smack.util.DNSUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DNS resolver (mostly for SRV records), which makes use of the API provided in the javax.* namepsace.
|
* A DNS resolver (mostly for SRV records), which makes use of the API provided in the javax.* namespace.
|
||||||
*
|
*
|
||||||
* @author Florian Schmaus
|
* @author Florian Schmaus
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class JavaxResolver extends DNSResolver {
|
public class JavaxResolver implements DNSResolver {
|
||||||
|
|
||||||
private static JavaxResolver instance;
|
private static JavaxResolver instance;
|
||||||
private static DirContext dirContext;
|
private static DirContext dirContext;
|
||||||
|
@ -48,14 +48,14 @@ public class JavaxResolver extends DNSResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to set this DNS resolver as primary one
|
// Try to set this DNS resolver as primary one
|
||||||
DNSUtil.setDNSResolver(maybeGetInstance());
|
DNSUtil.setDNSResolver(getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
private JavaxResolver() {
|
private JavaxResolver() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DNSResolver maybeGetInstance() {
|
public static DNSResolver getInstance() {
|
||||||
if (instance == null && isSupported()) {
|
if (instance == null && isSupported()) {
|
||||||
instance = new JavaxResolver();
|
instance = new JavaxResolver();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,13 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
|
||||||
/**
|
/**
|
||||||
* Create a new SRVRecord
|
* Create a new SRVRecord
|
||||||
*
|
*
|
||||||
* @param fqdn
|
* @param fqdn Fully qualified domain name
|
||||||
* @param port
|
* @param port The connection port
|
||||||
* @param priority
|
* @param priority Priority of the target host
|
||||||
* @param weight
|
* @param weight Relative weight for records with same priority
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException fqdn is null or any other field is not in valid range (0-65535).
|
||||||
*/
|
*/
|
||||||
public SRVRecord(String fqdn, int port, int priority, int weight) throws IllegalArgumentException {
|
public SRVRecord(String fqdn, int port, int priority, int weight) {
|
||||||
super(fqdn, port);
|
super(fqdn, port);
|
||||||
if (weight < 0 || weight > 65535)
|
if (weight < 0 || weight > 65535)
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -60,6 +60,7 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
|
||||||
return weight;
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int compareTo(SRVRecord other) {
|
public int compareTo(SRVRecord other) {
|
||||||
// According to RFC2782,
|
// According to RFC2782,
|
||||||
// "[a] client MUST attempt to contact the target host with the lowest-numbered priority it can reach".
|
// "[a] client MUST attempt to contact the target host with the lowest-numbered priority it can reach".
|
||||||
|
@ -71,6 +72,7 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString() + " prio:" + priority + ":w:" + weight;
|
return super.toString() + " prio:" + priority + ":w:" + weight;
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,24 +299,23 @@ public class FormField {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
return false;
|
return false;
|
||||||
if (obj == this)
|
if (obj == this)
|
||||||
return true;
|
return true;
|
||||||
if (obj.getClass() != getClass())
|
if (!(obj instanceof FormField))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
FormField other = (FormField) obj;
|
FormField other = (FormField) obj;
|
||||||
|
|
||||||
String thisXml = toXML();
|
return toXML().equals(other.toXML());
|
||||||
String otherXml = other.toXML();
|
|
||||||
|
|
||||||
if (thisXml.equals(otherXml)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return toXML().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -356,6 +355,7 @@ public class FormField {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getLabel();
|
return getLabel();
|
||||||
}
|
}
|
||||||
|
@ -375,6 +375,7 @@ public class FormField {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
return false;
|
return false;
|
||||||
|
@ -396,5 +397,13 @@ public class FormField {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 37 * result + value.hashCode();
|
||||||
|
result = 37 * result + (label == null ? 0 : label.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ public interface NodeInformationProvider {
|
||||||
*
|
*
|
||||||
* @return a list of the Items defined in the node.
|
* @return a list of the Items defined in the node.
|
||||||
*/
|
*/
|
||||||
public abstract List<DiscoverItems.Item> getNodeItems();
|
List<DiscoverItems.Item> getNodeItems();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of the features defined in the node. For
|
* Returns a list of the features defined in the node. For
|
||||||
|
@ -55,7 +55,7 @@ public interface NodeInformationProvider {
|
||||||
*
|
*
|
||||||
* @return a list of the feature strings defined in the node.
|
* @return a list of the feature strings defined in the node.
|
||||||
*/
|
*/
|
||||||
public abstract List<String> getNodeFeatures();
|
List<String> getNodeFeatures();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of the indentites defined in the node. For
|
* Returns a list of the indentites defined in the node. For
|
||||||
|
@ -64,12 +64,12 @@ public interface NodeInformationProvider {
|
||||||
*
|
*
|
||||||
* @return a list of the Identities defined in the node.
|
* @return a list of the Identities defined in the node.
|
||||||
*/
|
*/
|
||||||
public abstract List<DiscoverInfo.Identity> getNodeIdentities();
|
List<DiscoverInfo.Identity> getNodeIdentities();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of the packet extensions defined in the node.
|
* Returns a list of the packet extensions defined in the node.
|
||||||
*
|
*
|
||||||
* @return a list of the packet extensions defined in the node.
|
* @return a list of the packet extensions defined in the node.
|
||||||
*/
|
*/
|
||||||
public abstract List<PacketExtension> getNodePacketExtensions();
|
List<PacketExtension> getNodePacketExtensions();
|
||||||
}
|
}
|
||||||
|
|
|
@ -513,7 +513,7 @@ public class ServiceDiscoveryManager {
|
||||||
|
|
||||||
// If the node version is known, store the new entry.
|
// If the node version is known, store the new entry.
|
||||||
if (nvh != null) {
|
if (nvh != null) {
|
||||||
if (EntityCapsManager.verifyDiscvoerInfoVersion(nvh.getVer(), nvh.getHash(), info))
|
if (EntityCapsManager.verifyDiscoverInfoVersion(nvh.getVer(), nvh.getHash(), info))
|
||||||
EntityCapsManager.addDiscoverInfoByNode(nvh.getNodeVer(), info);
|
EntityCapsManager.addDiscoverInfoByNode(nvh.getNodeVer(), info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
* Copyright 2005 Jive Software.
|
||||||
*
|
*
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
|
||||||
*
|
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2013 Georg Lukas
|
|
||||||
*
|
|
||||||
* All rights reserved. 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 org.jivesoftware.smackx.carbons;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Packet;
|
|
||||||
import org.jivesoftware.smack.packet.PacketExtension;
|
|
||||||
import org.jivesoftware.smack.provider.PacketExtensionProvider;
|
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
|
||||||
import org.jivesoftware.smackx.forward.Forwarded;
|
|
||||||
import org.jivesoftware.smackx.packet.DelayInfo;
|
|
||||||
import org.jivesoftware.smackx.provider.DelayInfoProvider;
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packet extension for XEP-0280: Message Carbons. This class implements
|
|
||||||
* the packet extension and a {@link PacketExtensionProvider} to parse
|
|
||||||
* message carbon copies from a packet. The extension
|
|
||||||
* <a href="http://xmpp.org/extensions/xep-0280.html">XEP-0280</a> is
|
|
||||||
* meant to synchronize a message flow to multiple presences of a user.
|
|
||||||
*
|
|
||||||
* <p>The {@link Carbon.Provider} must be registered in the
|
|
||||||
* <b>smack.properties</b> file for the elements <b>sent</b> and
|
|
||||||
* <b>received</b> with namespace <b>urn:xmpp:carbons:2</b></p> to be used.
|
|
||||||
*
|
|
||||||
* @author Georg Lukas
|
|
||||||
*/
|
|
||||||
public class Carbon implements PacketExtension {
|
|
||||||
public static final String NAMESPACE = "urn:xmpp:carbons:2";
|
|
||||||
|
|
||||||
private Direction dir;
|
|
||||||
private Forwarded fwd;
|
|
||||||
|
|
||||||
public Carbon(Direction dir, Forwarded fwd) {
|
|
||||||
this.dir = dir;
|
|
||||||
this.fwd = fwd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the direction (sent or received) of the carbon.
|
|
||||||
*
|
|
||||||
* @return the {@link Direction} of the carbon.
|
|
||||||
*/
|
|
||||||
public Direction getDirection() {
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the forwarded packet.
|
|
||||||
*
|
|
||||||
* @return the {@link Forwarded} message contained in this Carbon.
|
|
||||||
*/
|
|
||||||
public Forwarded getForwarded() {
|
|
||||||
return fwd;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getElementName() {
|
|
||||||
return dir.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getNamespace() {
|
|
||||||
return NAMESPACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toXML() {
|
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
buf.append("<").append(getElementName()).append(" xmlns=\"")
|
|
||||||
.append(getNamespace()).append("\">");
|
|
||||||
|
|
||||||
buf.append(fwd.toXML());
|
|
||||||
|
|
||||||
buf.append("</").append(getElementName()).append(">");
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An enum to display the direction of a {@link Carbon} message.
|
|
||||||
*/
|
|
||||||
public static enum Direction {
|
|
||||||
received,
|
|
||||||
sent
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Provider implements PacketExtensionProvider {
|
|
||||||
|
|
||||||
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
|
|
||||||
Direction dir = Direction.valueOf(parser.getName());
|
|
||||||
Forwarded fwd = null;
|
|
||||||
|
|
||||||
boolean done = false;
|
|
||||||
while (!done) {
|
|
||||||
int eventType = parser.next();
|
|
||||||
if (eventType == XmlPullParser.START_TAG && parser.getName().equals("forwarded")) {
|
|
||||||
fwd = (Forwarded)new Forwarded.Provider().parseExtension(parser);
|
|
||||||
}
|
|
||||||
else if (eventType == XmlPullParser.END_TAG && dir == Direction.valueOf(parser.getName()))
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
if (fwd == null)
|
|
||||||
throw new Exception("sent/received must contain exactly one <forwarded> tag");
|
|
||||||
return new Carbon(dir, fwd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packet extension indicating that a message may not be carbon-copied.
|
|
||||||
*/
|
|
||||||
public static class Private implements PacketExtension {
|
|
||||||
public static final String ELEMENT = "private";
|
|
||||||
|
|
||||||
public String getElementName() {
|
|
||||||
return ELEMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNamespace() {
|
|
||||||
return Carbon.NAMESPACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toXML() {
|
|
||||||
return "<" + ELEMENT + " xmlns=\"" + Carbon.NAMESPACE + "\"/>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,213 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2013 Georg Lukas
|
|
||||||
*
|
|
||||||
* All rights reserved. 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 org.jivesoftware.smackx.carbons;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.Connection;
|
|
||||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
|
||||||
import org.jivesoftware.smack.PacketCollector;
|
|
||||||
import org.jivesoftware.smack.PacketListener;
|
|
||||||
import org.jivesoftware.smack.SmackConfiguration;
|
|
||||||
import org.jivesoftware.smack.XMPPException;
|
|
||||||
import org.jivesoftware.smack.filter.PacketIDFilter;
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
|
||||||
import org.jivesoftware.smack.packet.Message;
|
|
||||||
import org.jivesoftware.smack.packet.Packet;
|
|
||||||
import org.jivesoftware.smackx.ServiceDiscoveryManager;
|
|
||||||
import org.jivesoftware.smackx.packet.DiscoverInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packet extension for XEP-0280: Message Carbons. This class implements
|
|
||||||
* the manager for registering {@link Carbon} support, enabling and disabling
|
|
||||||
* message carbons.
|
|
||||||
*
|
|
||||||
* You should call enableCarbons() before sending your first undirected
|
|
||||||
* presence.
|
|
||||||
*
|
|
||||||
* @author Georg Lukas
|
|
||||||
*/
|
|
||||||
public class CarbonManager {
|
|
||||||
|
|
||||||
private static Map<Connection, CarbonManager> instances =
|
|
||||||
Collections.synchronizedMap(new WeakHashMap<Connection, CarbonManager>());
|
|
||||||
|
|
||||||
static {
|
|
||||||
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
|
|
||||||
public void connectionCreated(Connection connection) {
|
|
||||||
new CarbonManager(connection);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private Connection connection;
|
|
||||||
private volatile boolean enabled_state = false;
|
|
||||||
|
|
||||||
private CarbonManager(Connection connection) {
|
|
||||||
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
|
|
||||||
sdm.addFeature(Carbon.NAMESPACE);
|
|
||||||
this.connection = connection;
|
|
||||||
instances.put(connection, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the CarbonManager responsible for a connection.
|
|
||||||
*
|
|
||||||
* @param connection the connection object.
|
|
||||||
*
|
|
||||||
* @return a CarbonManager instance
|
|
||||||
*/
|
|
||||||
public static CarbonManager getInstanceFor(Connection connection) {
|
|
||||||
CarbonManager carbonManager = instances.get(connection);
|
|
||||||
|
|
||||||
if (carbonManager == null) {
|
|
||||||
carbonManager = new CarbonManager(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
return carbonManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IQ carbonsEnabledIQ(final boolean new_state) {
|
|
||||||
IQ setIQ = new IQ() {
|
|
||||||
public String getChildElementXML() {
|
|
||||||
return "<" + (new_state? "enable" : "disable") + " xmlns='" + Carbon.NAMESPACE + "'/>";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
setIQ.setType(IQ.Type.SET);
|
|
||||||
return setIQ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if XMPP Carbons are supported by the server.
|
|
||||||
*
|
|
||||||
* @return true if supported
|
|
||||||
*/
|
|
||||||
public boolean isSupportedByServer() {
|
|
||||||
try {
|
|
||||||
DiscoverInfo result = ServiceDiscoveryManager
|
|
||||||
.getInstanceFor(connection).discoverInfo(connection.getServiceName());
|
|
||||||
return result.containsFeature(Carbon.NAMESPACE);
|
|
||||||
}
|
|
||||||
catch (XMPPException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify server to change the carbons state. This method returns
|
|
||||||
* immediately and changes the variable when the reply arrives.
|
|
||||||
*
|
|
||||||
* You should first check for support using isSupportedByServer().
|
|
||||||
*
|
|
||||||
* @param new_state whether carbons should be enabled or disabled
|
|
||||||
*/
|
|
||||||
public void sendCarbonsEnabled(final boolean new_state) {
|
|
||||||
IQ setIQ = carbonsEnabledIQ(new_state);
|
|
||||||
|
|
||||||
connection.addPacketListener(new PacketListener() {
|
|
||||||
public void processPacket(Packet packet) {
|
|
||||||
IQ result = (IQ)packet;
|
|
||||||
if (result.getType() == IQ.Type.RESULT) {
|
|
||||||
enabled_state = new_state;
|
|
||||||
}
|
|
||||||
connection.removePacketListener(this);
|
|
||||||
}
|
|
||||||
}, new PacketIDFilter(setIQ.getPacketID()));
|
|
||||||
|
|
||||||
connection.sendPacket(setIQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify server to change the carbons state. This method blocks
|
|
||||||
* some time until the server replies to the IQ and returns true on
|
|
||||||
* success.
|
|
||||||
*
|
|
||||||
* You should first check for support using isSupportedByServer().
|
|
||||||
*
|
|
||||||
* @param new_state whether carbons should be enabled or disabled
|
|
||||||
*
|
|
||||||
* @return true if the operation was successful
|
|
||||||
*/
|
|
||||||
public boolean setCarbonsEnabled(final boolean new_state) {
|
|
||||||
if (enabled_state == new_state)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
IQ setIQ = carbonsEnabledIQ(new_state);
|
|
||||||
|
|
||||||
PacketCollector collector =
|
|
||||||
connection.createPacketCollector(new PacketIDFilter(setIQ.getPacketID()));
|
|
||||||
connection.sendPacket(setIQ);
|
|
||||||
IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
|
||||||
collector.cancel();
|
|
||||||
|
|
||||||
if (result != null && result.getType() == IQ.Type.RESULT) {
|
|
||||||
enabled_state = new_state;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to enable carbons.
|
|
||||||
*
|
|
||||||
* @return true if the operation was successful
|
|
||||||
*/
|
|
||||||
public boolean enableCarbons() {
|
|
||||||
return setCarbonsEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to disable carbons.
|
|
||||||
*
|
|
||||||
* @return true if the operation was successful
|
|
||||||
*/
|
|
||||||
public boolean disableCarbons() {
|
|
||||||
return setCarbonsEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if carbons are enabled on this connection.
|
|
||||||
*/
|
|
||||||
public boolean getCarbonsEnabled() {
|
|
||||||
return this.enabled_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a Carbon from a message, if available.
|
|
||||||
*
|
|
||||||
* @param msg Message object to check for carbons
|
|
||||||
*
|
|
||||||
* @return a Carbon if available, null otherwise.
|
|
||||||
*/
|
|
||||||
public static Carbon getCarbon(Message msg) {
|
|
||||||
Carbon cc = (Carbon)msg.getExtension("received", Carbon.NAMESPACE);
|
|
||||||
if (cc == null)
|
|
||||||
cc = (Carbon)msg.getExtension("sent", Carbon.NAMESPACE);
|
|
||||||
return cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark a message as "private", so it will not be carbon-copied.
|
|
||||||
*
|
|
||||||
* @param msg Message object to mark private
|
|
||||||
*/
|
|
||||||
public static void disableCarbons(Message msg) {
|
|
||||||
msg.addExtension(new Carbon.Private());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
* Copyright 2008 Jive Software.
|
||||||
*
|
*
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -506,7 +506,7 @@ public class EntityCapsManager {
|
||||||
* @param info
|
* @param info
|
||||||
* @return true if it's valid and should be cache, false if not
|
* @return true if it's valid and should be cache, false if not
|
||||||
*/
|
*/
|
||||||
public static boolean verifyDiscvoerInfoVersion(String ver, String hash, DiscoverInfo info) {
|
public static boolean verifyDiscoverInfoVersion(String ver, String hash, DiscoverInfo info) {
|
||||||
// step 3.3 check for duplicate identities
|
// step 3.3 check for duplicate identities
|
||||||
if (info.containsDuplicateIdentities())
|
if (info.containsDuplicateIdentities())
|
||||||
return false;
|
return false;
|
||||||
|
@ -583,7 +583,7 @@ public class EntityCapsManager {
|
||||||
// NAME is not included (in accordance with XEP-0030, the category and
|
// NAME is not included (in accordance with XEP-0030, the category and
|
||||||
// type MUST be included.
|
// type MUST be included.
|
||||||
SortedSet<DiscoverInfo.Identity> sortedIdentities = new TreeSet<DiscoverInfo.Identity>();
|
SortedSet<DiscoverInfo.Identity> sortedIdentities = new TreeSet<DiscoverInfo.Identity>();
|
||||||
;
|
|
||||||
for (Iterator<DiscoverInfo.Identity> it = discoverInfo.getIdentities(); it.hasNext();)
|
for (Iterator<DiscoverInfo.Identity> it = discoverInfo.getIdentities(); it.hasNext();)
|
||||||
sortedIdentities.add(it.next());
|
sortedIdentities.add(it.next());
|
||||||
|
|
||||||
|
@ -616,7 +616,7 @@ public class EntityCapsManager {
|
||||||
// only use the data form for calculation is it has a hidden FORM_TYPE
|
// only use the data form for calculation is it has a hidden FORM_TYPE
|
||||||
// field
|
// field
|
||||||
// see XEP-0115 5.4 step 3.6
|
// see XEP-0115 5.4 step 3.6
|
||||||
if (extendedInfo != null && extendedInfo.hasHiddenFromTypeField()) {
|
if (extendedInfo != null && extendedInfo.hasHiddenFormTypeField()) {
|
||||||
synchronized (extendedInfo) {
|
synchronized (extendedInfo) {
|
||||||
// 6. If the service discovery information response includes
|
// 6. If the service discovery information response includes
|
||||||
// XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e.,
|
// XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e.,
|
||||||
|
|
|
@ -24,15 +24,15 @@ public interface EntityCapsPersistentCache {
|
||||||
* @param node
|
* @param node
|
||||||
* @param info
|
* @param info
|
||||||
*/
|
*/
|
||||||
abstract void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info);
|
void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replay the Caches data into EntityCapsManager
|
* Replay the Caches data into EntityCapsManager
|
||||||
*/
|
*/
|
||||||
abstract void replay() throws IOException;
|
void replay() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empty the Cache
|
* Empty the Cache
|
||||||
*/
|
*/
|
||||||
abstract void emptyCache();
|
void emptyCache();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.io.StringReader;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.provider.IQProvider;
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
import org.jivesoftware.smack.util.Base64Encoder;
|
import org.jivesoftware.smack.util.Base32Encoder;
|
||||||
import org.jivesoftware.smack.util.StringEncoder;
|
import org.jivesoftware.smack.util.StringEncoder;
|
||||||
import org.jivesoftware.smackx.entitycaps.EntityCapsManager;
|
import org.jivesoftware.smackx.entitycaps.EntityCapsManager;
|
||||||
import org.jivesoftware.smackx.packet.DiscoverInfo;
|
import org.jivesoftware.smackx.packet.DiscoverInfo;
|
||||||
|
@ -47,19 +47,20 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||||
public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache {
|
public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache {
|
||||||
|
|
||||||
private File cacheDir;
|
private File cacheDir;
|
||||||
private StringEncoder stringEncoder;
|
private StringEncoder filenameEncoder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new SimpleDirectoryPersistentCache Object. Make sure that the
|
* Creates a new SimpleDirectoryPersistentCache Object. Make sure that the
|
||||||
* cacheDir exists and that it's an directory.
|
* cacheDir exists and that it's an directory.
|
||||||
*
|
* <p>
|
||||||
* If your cacheDir is case insensitive then make sure to set the
|
* Default filename encoder {@link Base32Encoder}, as this will work on all
|
||||||
* StringEncoder to Base32.
|
* filesystems, both case sensitive and case insensitive. It does however
|
||||||
|
* produce longer filenames.
|
||||||
*
|
*
|
||||||
* @param cacheDir
|
* @param cacheDir
|
||||||
*/
|
*/
|
||||||
public SimpleDirectoryPersistentCache(File cacheDir) {
|
public SimpleDirectoryPersistentCache(File cacheDir) {
|
||||||
this(cacheDir, Base64Encoder.getInstance());
|
this(cacheDir, Base32Encoder.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,26 +68,25 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
|
||||||
* cacheDir exists and that it's an directory.
|
* cacheDir exists and that it's an directory.
|
||||||
*
|
*
|
||||||
* If your cacheDir is case insensitive then make sure to set the
|
* If your cacheDir is case insensitive then make sure to set the
|
||||||
* StringEncoder to Base32.
|
* StringEncoder to {@link Base32Encoder} (which is the default).
|
||||||
*
|
*
|
||||||
* @param cacheDir
|
* @param cacheDir The directory where the cache will be stored.
|
||||||
* @param stringEncoder
|
* @param filenameEncoder Encodes the node string into a filename.
|
||||||
*/
|
*/
|
||||||
public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder stringEncoder) {
|
public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder filenameEncoder) {
|
||||||
if (!cacheDir.exists())
|
if (!cacheDir.exists())
|
||||||
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" does not exist");
|
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" does not exist");
|
||||||
if (!cacheDir.isDirectory())
|
if (!cacheDir.isDirectory())
|
||||||
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" is not a directory");
|
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" is not a directory");
|
||||||
|
|
||||||
this.cacheDir = cacheDir;
|
this.cacheDir = cacheDir;
|
||||||
this.stringEncoder = stringEncoder;
|
this.filenameEncoder = filenameEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info) {
|
public void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info) {
|
||||||
String filename = stringEncoder.encode(node);
|
String filename = filenameEncoder.encode(node);
|
||||||
File nodeFile = new File(cacheDir, filename);
|
File nodeFile = new File(cacheDir, filename);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (nodeFile.createNewFile())
|
if (nodeFile.createNewFile())
|
||||||
writeInfoToFile(nodeFile, info);
|
writeInfoToFile(nodeFile, info);
|
||||||
|
@ -99,7 +99,7 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
|
||||||
public void replay() throws IOException {
|
public void replay() throws IOException {
|
||||||
File[] files = cacheDir.listFiles();
|
File[] files = cacheDir.listFiles();
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
String node = stringEncoder.decode(f.getName());
|
String node = filenameEncoder.decode(f.getName());
|
||||||
DiscoverInfo info = restoreInfoFromFile(f);
|
DiscoverInfo info = restoreInfoFromFile(f);
|
||||||
if (info == null)
|
if (info == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/**
|
||||||
* Copyright 2009 Jonas Ådahl.
|
* Copyright 2009 Jonas Ådahl.
|
||||||
* Copyright 2011-2013 Florian Schmaus
|
* Copyright 2011-2013 Florian Schmaus
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,125 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2013 Georg Lukas
|
|
||||||
*
|
|
||||||
* All rights reserved. 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 org.jivesoftware.smackx.forward;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.Packet;
|
|
||||||
import org.jivesoftware.smack.packet.PacketExtension;
|
|
||||||
import org.jivesoftware.smack.provider.PacketExtensionProvider;
|
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
|
||||||
import org.jivesoftware.smackx.packet.DelayInfo;
|
|
||||||
import org.jivesoftware.smackx.provider.DelayInfoProvider;
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packet extension for XEP-0297: Stanza Forwarding. This class implements
|
|
||||||
* the packet extension and a {@link PacketExtensionProvider} to parse
|
|
||||||
* forwarded messages from a packet. The extension
|
|
||||||
* <a href="http://xmpp.org/extensions/xep-0297.html">XEP-0297</a> is
|
|
||||||
* a prerequisite for XEP-0280 (Message Carbons).
|
|
||||||
*
|
|
||||||
* <p>The {@link Forwarded.Provider} must be registered in the
|
|
||||||
* <b>smack.properties</b> file for the element <b>forwarded</b> with
|
|
||||||
* namespace <b>urn:xmpp:forwarded:0</b></p> to be used.
|
|
||||||
*
|
|
||||||
* @author Georg Lukas
|
|
||||||
*/
|
|
||||||
public class Forwarded implements PacketExtension {
|
|
||||||
public static final String NAMESPACE = "urn:xmpp:forward:0";
|
|
||||||
public static final String ELEMENT_NAME = "forwarded";
|
|
||||||
|
|
||||||
private DelayInfo delay;
|
|
||||||
private Packet forwardedPacket;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Forwarded packet extension.
|
|
||||||
*
|
|
||||||
* @param delay an optional {@link DelayInfo} timestamp of the packet.
|
|
||||||
* @param fwdPacket the packet that is forwarded (required).
|
|
||||||
*/
|
|
||||||
public Forwarded(DelayInfo delay, Packet fwdPacket) {
|
|
||||||
this.delay = delay;
|
|
||||||
this.forwardedPacket = fwdPacket;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getElementName() {
|
|
||||||
return ELEMENT_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getNamespace() {
|
|
||||||
return NAMESPACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toXML() {
|
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
buf.append("<").append(getElementName()).append(" xmlns=\"")
|
|
||||||
.append(getNamespace()).append("\">");
|
|
||||||
|
|
||||||
if (delay != null)
|
|
||||||
buf.append(delay.toXML());
|
|
||||||
buf.append(forwardedPacket.toXML());
|
|
||||||
|
|
||||||
buf.append("</").append(getElementName()).append(">");
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the packet forwarded by this stanza.
|
|
||||||
*
|
|
||||||
* @return the {@link Packet} instance (typically a message) that was forwarded.
|
|
||||||
*/
|
|
||||||
public Packet getForwardedPacket() {
|
|
||||||
return forwardedPacket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the timestamp of the forwarded packet.
|
|
||||||
*
|
|
||||||
* @return the {@link DelayInfo} representing the time when the original packet was sent. May be null.
|
|
||||||
*/
|
|
||||||
public DelayInfo getDelayInfo() {
|
|
||||||
return delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Provider implements PacketExtensionProvider {
|
|
||||||
DelayInfoProvider dip = new DelayInfoProvider();
|
|
||||||
|
|
||||||
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
|
|
||||||
DelayInfo di = null;
|
|
||||||
Packet packet = null;
|
|
||||||
|
|
||||||
boolean done = false;
|
|
||||||
while (!done) {
|
|
||||||
int eventType = parser.next();
|
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
|
||||||
if (parser.getName().equals("delay"))
|
|
||||||
di = (DelayInfo)dip.parseExtension(parser);
|
|
||||||
else if (parser.getName().equals("message"))
|
|
||||||
packet = PacketParserUtils.parseMessage(parser);
|
|
||||||
else throw new Exception("Unsupported forwarded packet type: " + parser.getName());
|
|
||||||
}
|
|
||||||
else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(ELEMENT_NAME))
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
if (packet == null)
|
|
||||||
throw new Exception("forwarded extension must contain a packet");
|
|
||||||
return new Forwarded(di, packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -202,7 +202,7 @@ public class DataForm implements PacketExtension {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasHiddenFromTypeField() {
|
public boolean hasHiddenFormTypeField() {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (FormField f : fields) {
|
for (FormField f : fields) {
|
||||||
if (f.getVariable().equals("FORM_TYPE") && f.getType() != null && f.getType().equals("hidden"))
|
if (f.getVariable().equals("FORM_TYPE") && f.getType() != null && f.getType().equals("hidden"))
|
||||||
|
|
|
@ -257,13 +257,25 @@ public class DiscoverInfo extends IQ {
|
||||||
* attributes.
|
* attributes.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static class Identity implements Comparable<Object> {
|
public static class Identity implements Comparable<Identity> {
|
||||||
|
|
||||||
private String category;
|
private String category;
|
||||||
private String name;
|
private String name;
|
||||||
private String type;
|
private String type;
|
||||||
private String lang; // 'xml:lang;
|
private String lang; // 'xml:lang;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new identity for an XMPP entity.
|
||||||
|
*
|
||||||
|
* @param category the entity's category.
|
||||||
|
* @param name the entity's name.
|
||||||
|
* @deprecated As per the spec, the type field is mandatory and the 3 argument constructor should be used instead.
|
||||||
|
*/
|
||||||
|
public Identity(String category, String name) {
|
||||||
|
this.category = category;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new identity for an XMPP entity.
|
* Creates a new identity for an XMPP entity.
|
||||||
* 'category' and 'type' are required by
|
* 'category' and 'type' are required by
|
||||||
|
@ -274,6 +286,9 @@ public class DiscoverInfo extends IQ {
|
||||||
* @param type the entity's type (required as per XEP-30).
|
* @param type the entity's type (required as per XEP-30).
|
||||||
*/
|
*/
|
||||||
public Identity(String category, String name, String type) {
|
public Identity(String category, String name, String type) {
|
||||||
|
if ((category == null) || (type == null))
|
||||||
|
throw new IllegalArgumentException("category and type cannot be null");
|
||||||
|
|
||||||
this.category = category;
|
this.category = category;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -313,6 +328,7 @@ public class DiscoverInfo extends IQ {
|
||||||
* 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
|
* 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
|
||||||
*
|
*
|
||||||
* @param type the identity's type.
|
* @param type the identity's type.
|
||||||
|
* @deprecated As per the spec, this field is mandatory and the 3 argument constructor should be used instead.
|
||||||
*/
|
*/
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -374,12 +390,15 @@ public class DiscoverInfo extends IQ {
|
||||||
|
|
||||||
String otherLang = other.lang == null ? "" : other.lang;
|
String otherLang = other.lang == null ? "" : other.lang;
|
||||||
String thisLang = lang == null ? "" : lang;
|
String thisLang = lang == null ? "" : lang;
|
||||||
|
|
||||||
if (!other.type.equals(type))
|
|
||||||
return false;
|
|
||||||
if (!otherLang.equals(thisLang))
|
if (!otherLang.equals(thisLang))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// This safeguard can be removed once the deprecated constructor is removed.
|
||||||
|
String otherType = other.type == null ? "" : other.type;
|
||||||
|
String thisType = type == null ? "" : type;
|
||||||
|
if (!otherType.equals(thisType))
|
||||||
|
return false;
|
||||||
|
|
||||||
String otherName = other.name == null ? "" : other.name;
|
String otherName = other.name == null ? "" : other.name;
|
||||||
String thisName = name == null ? "" : other.name;
|
String thisName = name == null ? "" : other.name;
|
||||||
if (!thisName.equals(otherName))
|
if (!thisName.equals(otherName))
|
||||||
|
@ -388,22 +407,34 @@ public class DiscoverInfo extends IQ {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 37 * result + category.hashCode();
|
||||||
|
result = 37 * result + (lang == null ? 0 : lang.hashCode());
|
||||||
|
result = 37 * result + (type == null ? 0 : type.hashCode());
|
||||||
|
result = 37 * result + (name == null ? 0 : name.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares and identity with another object. The comparison order is:
|
* Compares this identity with another one. The comparison order is:
|
||||||
* Category, Type, Lang. If all three are identical the other Identity is considered equal.
|
* Category, Type, Lang. If all three are identical the other Identity is considered equal.
|
||||||
* Name is not used for comparision, as defined by XEP-0115
|
* Name is not used for comparision, as defined by XEP-0115
|
||||||
*
|
*
|
||||||
* @param obj
|
* @param obj
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public int compareTo(Object obj) {
|
public int compareTo(DiscoverInfo.Identity other) {
|
||||||
|
|
||||||
DiscoverInfo.Identity other = (DiscoverInfo.Identity) obj;
|
|
||||||
String otherLang = other.lang == null ? "" : other.lang;
|
String otherLang = other.lang == null ? "" : other.lang;
|
||||||
String thisLang = lang == null ? "" : lang;
|
String thisLang = lang == null ? "" : lang;
|
||||||
|
|
||||||
|
// This can be removed once the deprecated constructor is removed.
|
||||||
|
String otherType = other.type == null ? "" : other.type;
|
||||||
|
String thisType = type == null ? "" : type;
|
||||||
|
|
||||||
if (category.equals(other.category)) {
|
if (category.equals(other.category)) {
|
||||||
if (type.equals(other.type)) {
|
if (thisType.equals(otherType)) {
|
||||||
if (thisLang.equals(otherLang)) {
|
if (thisLang.equals(otherLang)) {
|
||||||
// Don't compare on name, XEP-30 says that name SHOULD
|
// Don't compare on name, XEP-30 says that name SHOULD
|
||||||
// be equals for all identities of an entity
|
// be equals for all identities of an entity
|
||||||
|
@ -412,7 +443,7 @@ public class DiscoverInfo extends IQ {
|
||||||
return thisLang.compareTo(otherLang);
|
return thisLang.compareTo(otherLang);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return type.compareTo(other.type);
|
return thisType.compareTo(otherType);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return category.compareTo(other.category);
|
return category.compareTo(other.category);
|
||||||
|
@ -436,6 +467,8 @@ public class DiscoverInfo extends IQ {
|
||||||
* @param variable the feature's variable.
|
* @param variable the feature's variable.
|
||||||
*/
|
*/
|
||||||
public Feature(String variable) {
|
public Feature(String variable) {
|
||||||
|
if (variable == null)
|
||||||
|
throw new IllegalArgumentException("variable cannot be null");
|
||||||
this.variable = variable;
|
this.variable = variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,5 +498,10 @@ public class DiscoverInfo extends IQ {
|
||||||
DiscoverInfo.Feature other = (DiscoverInfo.Feature) obj;
|
DiscoverInfo.Feature other = (DiscoverInfo.Feature) obj;
|
||||||
return variable.equals(other.variable);
|
return variable.equals(other.variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return 37 * variable.hashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
* Copyright 2005 Jive Software.
|
||||||
*
|
*
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -85,6 +85,7 @@ import org.jivesoftware.smack.util.StringUtils;
|
||||||
* @author Kirill Maximov (kir@maxkir.com)
|
* @author Kirill Maximov (kir@maxkir.com)
|
||||||
*/
|
*/
|
||||||
public class VCard extends IQ {
|
public class VCard extends IQ {
|
||||||
|
private static final String DEFAULT_MIME_TYPE = "image/jpeg";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Phone types:
|
* Phone types:
|
||||||
|
@ -93,7 +94,6 @@ public class VCard extends IQ {
|
||||||
private Map<String, String> homePhones = new HashMap<String, String>();
|
private Map<String, String> homePhones = new HashMap<String, String>();
|
||||||
private Map<String, String> workPhones = new HashMap<String, String>();
|
private Map<String, String> workPhones = new HashMap<String, String>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address types:
|
* Address types:
|
||||||
* POSTAL?, PARCEL?, (DOM | INTL)?, PREF?, POBOX?, EXTADR?, STREET?, LOCALITY?,
|
* POSTAL?, PARCEL?, (DOM | INTL)?, PREF?, POBOX?, EXTADR?, STREET?, LOCALITY?,
|
||||||
|
@ -357,7 +357,7 @@ public class VCard extends IQ {
|
||||||
* @param bytes the bytes of the avatar, or null to remove the avatar data
|
* @param bytes the bytes of the avatar, or null to remove the avatar data
|
||||||
*/
|
*/
|
||||||
public void setAvatar(byte[] bytes) {
|
public void setAvatar(byte[] bytes) {
|
||||||
setAvatar(bytes, "image/jpeg");
|
setAvatar(bytes, DEFAULT_MIME_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -390,6 +390,16 @@ public class VCard extends IQ {
|
||||||
photoMimeType = mimeType;
|
photoMimeType = mimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the encoded avatar string. This is used by the provider.
|
||||||
|
*
|
||||||
|
* @param encodedAvatar the encoded avatar string.
|
||||||
|
* @deprecated Use {@link #setAvatar(String, String)} instead.
|
||||||
|
*/
|
||||||
|
public void setEncodedImage(String encodedAvatar) {
|
||||||
|
setAvatar(encodedAvatar, DEFAULT_MIME_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the byte representation of the avatar(if one exists), otherwise returns null if
|
* Return the byte representation of the avatar(if one exists), otherwise returns null if
|
||||||
* no avatar could be found.
|
* no avatar could be found.
|
||||||
|
|
|
@ -17,51 +17,46 @@
|
||||||
package org.jivesoftware.smackx.ping;
|
package org.jivesoftware.smackx.ping;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.Connection;
|
import org.jivesoftware.smack.Connection;
|
||||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
import org.jivesoftware.smack.ConnectionListener;
|
|
||||||
import org.jivesoftware.smack.PacketCollector;
|
|
||||||
import org.jivesoftware.smack.PacketListener;
|
import org.jivesoftware.smack.PacketListener;
|
||||||
import org.jivesoftware.smack.SmackConfiguration;
|
import org.jivesoftware.smack.SmackConfiguration;
|
||||||
|
import org.jivesoftware.smack.SmackError;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.filter.AndFilter;
|
||||||
|
import org.jivesoftware.smack.filter.IQTypeFilter;
|
||||||
import org.jivesoftware.smack.filter.PacketFilter;
|
import org.jivesoftware.smack.filter.PacketFilter;
|
||||||
import org.jivesoftware.smack.filter.PacketIDFilter;
|
|
||||||
import org.jivesoftware.smack.filter.PacketTypeFilter;
|
import org.jivesoftware.smack.filter.PacketTypeFilter;
|
||||||
|
import org.jivesoftware.smack.keepalive.KeepAliveManager;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.Packet;
|
import org.jivesoftware.smack.packet.Packet;
|
||||||
|
import org.jivesoftware.smack.packet.IQ.Type;
|
||||||
|
import org.jivesoftware.smack.ping.packet.Ping;
|
||||||
|
import org.jivesoftware.smack.util.SyncPacketSend;
|
||||||
import org.jivesoftware.smackx.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.packet.DiscoverInfo;
|
import org.jivesoftware.smackx.packet.DiscoverInfo;
|
||||||
import org.jivesoftware.smackx.ping.packet.Ping;
|
|
||||||
import org.jivesoftware.smackx.ping.packet.Pong;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the XMPP Ping as defined by XEP-0199. This protocol offers an
|
* Implements the XMPP Ping as defined by XEP-0199. The XMPP Ping protocol
|
||||||
* alternative to the traditional 'white space ping' approach of determining the
|
* allows one entity to 'ping' any other entity by simply sending a ping to
|
||||||
* availability of an entity. The XMPP Ping protocol allows ping messages to be
|
* the appropriate JID.
|
||||||
* send in a more XML-friendly approach, which can be used over more than one
|
* <p>
|
||||||
* hop in the communication path.
|
* NOTE: The {@link KeepAliveManager} already provides a keepalive functionality
|
||||||
|
* for regularly pinging the server to keep the underlying transport connection
|
||||||
|
* alive. This class is specifically intended to do manual pings of other
|
||||||
|
* entities.
|
||||||
*
|
*
|
||||||
* @author Florian Schmaus
|
* @author Florian Schmaus
|
||||||
* @see <a href="http://www.xmpp.org/extensions/xep-0199.html">XEP-0199:XMPP
|
* @see <a href="http://www.xmpp.org/extensions/xep-0199.html">XEP-0199:XMPP
|
||||||
* Ping</a>
|
* Ping</a>
|
||||||
*/
|
*/
|
||||||
public class PingManager {
|
public class PingManager {
|
||||||
|
private static Map<Connection, PingManager> instances = Collections
|
||||||
public static final String NAMESPACE = "urn:xmpp:ping";
|
.synchronizedMap(new WeakHashMap<Connection, PingManager>());
|
||||||
public static final String ELEMENT = "ping";
|
|
||||||
|
|
||||||
|
|
||||||
private static Map<Connection, PingManager> instances =
|
|
||||||
Collections.synchronizedMap(new WeakHashMap<Connection, PingManager>());
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
|
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
|
@ -71,273 +66,106 @@ public class PingManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledExecutorService periodicPingExecutorService;
|
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
private int pingInterval = SmackConfiguration.getDefaultPingInterval();
|
|
||||||
private Set<PingFailedListener> pingFailedListeners = Collections
|
|
||||||
.synchronizedSet(new HashSet<PingFailedListener>());
|
|
||||||
private ScheduledFuture<?> periodicPingTask;
|
|
||||||
protected volatile long lastSuccessfulPingByTask = -1;
|
|
||||||
|
|
||||||
|
|
||||||
// Ping Flood protection
|
|
||||||
private long pingMinDelta = 100;
|
|
||||||
private long lastPingStamp = 0; // timestamp of the last received ping
|
|
||||||
|
|
||||||
// Timestamp of the last pong received, either from the server or another entity
|
|
||||||
// Note, no need to synchronize this value, it will only increase over time
|
|
||||||
private long lastSuccessfulManualPing = -1;
|
|
||||||
|
|
||||||
private PingManager(Connection connection) {
|
|
||||||
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
|
|
||||||
sdm.addFeature(NAMESPACE);
|
|
||||||
this.connection = connection;
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init() {
|
|
||||||
periodicPingExecutorService = new ScheduledThreadPoolExecutor(1);
|
|
||||||
PacketFilter pingPacketFilter = new PacketTypeFilter(Ping.class);
|
|
||||||
connection.addPacketListener(new PacketListener() {
|
|
||||||
/**
|
/**
|
||||||
* Sends a Pong for every Ping
|
* Retrieves a {@link PingManager} for the specified {@link Connection}, creating one if it doesn't already
|
||||||
|
* exist.
|
||||||
|
*
|
||||||
|
* @param connection
|
||||||
|
* The connection the manager is attached to.
|
||||||
|
* @return The new or existing manager.
|
||||||
*/
|
*/
|
||||||
public void processPacket(Packet packet) {
|
public synchronized static PingManager getInstanceFor(Connection connection) {
|
||||||
if (pingMinDelta > 0) {
|
|
||||||
// Ping flood protection enabled
|
|
||||||
long currentMillies = System.currentTimeMillis();
|
|
||||||
long delta = currentMillies - lastPingStamp;
|
|
||||||
lastPingStamp = currentMillies;
|
|
||||||
if (delta < pingMinDelta) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Pong pong = new Pong((Ping)packet);
|
|
||||||
connection.sendPacket(pong);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
, pingPacketFilter);
|
|
||||||
connection.addConnectionListener(new ConnectionListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connectionClosed() {
|
|
||||||
maybeStopPingServerTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connectionClosedOnError(Exception arg0) {
|
|
||||||
maybeStopPingServerTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reconnectionSuccessful() {
|
|
||||||
maybeSchedulePingServerTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reconnectingIn(int seconds) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reconnectionFailed(Exception e) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
instances.put(connection, this);
|
|
||||||
maybeSchedulePingServerTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PingManager getInstanceFor(Connection connection) {
|
|
||||||
PingManager pingManager = instances.get(connection);
|
PingManager pingManager = instances.get(connection);
|
||||||
|
|
||||||
if (pingManager == null) {
|
if (pingManager == null) {
|
||||||
pingManager = new PingManager(connection);
|
pingManager = new PingManager(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pingManager;
|
return pingManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPingIntervall(int pingIntervall) {
|
private PingManager(Connection con) {
|
||||||
this.pingInterval = pingIntervall;
|
this.connection = con;
|
||||||
}
|
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
|
|
||||||
public int getPingIntervall() {
|
// The ServiceDiscoveryManager was not pre-initialized
|
||||||
return pingInterval;
|
if (sdm == null)
|
||||||
}
|
sdm = new ServiceDiscoveryManager(connection);
|
||||||
|
|
||||||
public void registerPingFailedListener(PingFailedListener listener) {
|
sdm.addFeature(Ping.NAMESPACE);
|
||||||
pingFailedListeners.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregisterPingFailedListener(PingFailedListener listener) {
|
PacketFilter pingPacketFilter = new AndFilter(new PacketTypeFilter(Ping.class), new IQTypeFilter(Type.GET));
|
||||||
pingFailedListeners.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disablePingFloodProtection() {
|
connection.addPacketListener(new PacketListener() {
|
||||||
setPingMinimumInterval(-1);
|
/**
|
||||||
|
* Sends a Pong for every Ping
|
||||||
|
*/
|
||||||
|
public void processPacket(Packet packet) {
|
||||||
|
IQ pong = IQ.createResultIQ((Ping) packet);
|
||||||
|
connection.sendPacket(pong);
|
||||||
}
|
}
|
||||||
|
}, pingPacketFilter);
|
||||||
public void setPingMinimumInterval(long ms) {
|
|
||||||
this.pingMinDelta = ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getPingMinimumInterval() {
|
|
||||||
return this.pingMinDelta;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pings the given jid and returns the IQ response which is either of
|
* Pings the given jid. This method will return false if an error occurs. The exception
|
||||||
* IQ.Type.ERROR or IQ.Type.RESULT. If we are not connected or if there was
|
* to this, is a server ping, which will always return true if the server is reachable,
|
||||||
* no reply, null is returned.
|
* event if there is an error on the ping itself (i.e. ping not supported).
|
||||||
|
* <p>
|
||||||
|
* Use {@link #isPingSupported(String)} to determine if XMPP Ping is supported
|
||||||
|
* by the entity.
|
||||||
*
|
*
|
||||||
* You should use isPingSupported(jid) to determine if XMPP Ping is
|
* @param jid The id of the entity the ping is being sent to
|
||||||
* supported by the user.
|
* @param pingTimeout The time to wait for a reply
|
||||||
*
|
* @return true if a reply was received from the entity, false otherwise.
|
||||||
* @param jid
|
|
||||||
* @param pingTimeout
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public IQ ping(String jid, long pingTimeout) {
|
public boolean ping(String jid, long pingTimeout) {
|
||||||
// Make sure we actually connected to the server
|
Ping ping = new Ping(jid);
|
||||||
if (!connection.isAuthenticated())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Ping ping = new Ping(connection.getUser(), jid);
|
try {
|
||||||
|
SyncPacketSend.getReply(connection, ping);
|
||||||
|
}
|
||||||
|
catch (XMPPException exc) {
|
||||||
|
|
||||||
PacketCollector collector =
|
return (jid.equals(connection.getServiceName()) && (exc.getSmackError() != SmackError.NO_RESPONSE_FROM_SERVER));
|
||||||
connection.createPacketCollector(new PacketIDFilter(ping.getPacketID()));
|
}
|
||||||
|
return true;
|
||||||
connection.sendPacket(ping);
|
|
||||||
|
|
||||||
IQ result = (IQ) collector.nextResult(pingTimeout);
|
|
||||||
|
|
||||||
collector.cancel();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pings the given jid and returns the IQ response with the default
|
* Same as calling {@link #ping(String, long)} with the defaultpacket reply
|
||||||
* packet reply timeout
|
* timeout.
|
||||||
*
|
*
|
||||||
* @param jid
|
* @param jid The id of the entity the ping is being sent to
|
||||||
* @return
|
* @return true if a reply was received from the entity, false otherwise.
|
||||||
*/
|
*/
|
||||||
public IQ ping(String jid) {
|
public boolean ping(String jid) {
|
||||||
return ping(jid, SmackConfiguration.getPacketReplyTimeout());
|
return ping(jid, SmackConfiguration.getPacketReplyTimeout());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pings the given Entity.
|
* Query the specified entity to see if it supports the Ping protocol (XEP-0199)
|
||||||
*
|
*
|
||||||
* Note that XEP-199 shows that if we receive a error response
|
* @param jid The id of the entity the query is being sent to
|
||||||
* service-unavailable there is no way to determine if the response was send
|
* @return true if it supports ping, false otherwise.
|
||||||
* by the entity (e.g. a user JID) or from a server in between. This is
|
* @throws XMPPException An XMPP related error occurred during the request
|
||||||
* intended behavior to avoid presence leaks.
|
|
||||||
*
|
|
||||||
* Always use isPingSupported(jid) to determine if XMPP Ping is supported
|
|
||||||
* by the entity.
|
|
||||||
*
|
|
||||||
* @param jid
|
|
||||||
* @return True if a pong was received, otherwise false
|
|
||||||
*/
|
*/
|
||||||
public boolean pingEntity(String jid, long pingTimeout) {
|
public boolean isPingSupported(String jid) throws XMPPException {
|
||||||
IQ result = ping(jid, pingTimeout);
|
DiscoverInfo result = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
|
||||||
|
return result.containsFeature(Ping.NAMESPACE);
|
||||||
if (result == null || result.getType() == IQ.Type.ERROR) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pongReceived();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean pingEntity(String jid) {
|
|
||||||
return pingEntity(jid, SmackConfiguration.getPacketReplyTimeout());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pings the user's server. Will notify the registered
|
* Pings the server. This method will return true if the server is reachable. It
|
||||||
* pingFailedListeners in case of error.
|
* is the equivalent of calling <code>ping</code> with the XMPP domain.
|
||||||
|
* <p>
|
||||||
|
* Unlike the {@link #ping(String)} case, this method will return true even if
|
||||||
|
* {@link #isPingSupported(String)} is false.
|
||||||
*
|
*
|
||||||
* If we receive as response, we can be sure that it came from the server.
|
* @return true if a reply was received from the server, false otherwise.
|
||||||
*
|
|
||||||
* @return true if successful, otherwise false
|
|
||||||
*/
|
|
||||||
public boolean pingMyServer(long pingTimeout) {
|
|
||||||
IQ result = ping(connection.getServiceName(), pingTimeout);
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
for (PingFailedListener l : pingFailedListeners) {
|
|
||||||
l.pingFailed();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Maybe not really a pong, but an answer is an answer
|
|
||||||
pongReceived();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pings the user's server with the PacketReplyTimeout as defined
|
|
||||||
* in SmackConfiguration.
|
|
||||||
*
|
|
||||||
* @return true if successful, otherwise false
|
|
||||||
*/
|
*/
|
||||||
public boolean pingMyServer() {
|
public boolean pingMyServer() {
|
||||||
return pingMyServer(SmackConfiguration.getPacketReplyTimeout());
|
return ping(connection.getServiceName());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if XMPP Ping is supported by a given JID
|
|
||||||
*
|
|
||||||
* @param jid
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isPingSupported(String jid) {
|
|
||||||
try {
|
|
||||||
DiscoverInfo result =
|
|
||||||
ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
|
|
||||||
return result.containsFeature(NAMESPACE);
|
|
||||||
}
|
|
||||||
catch (XMPPException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the time of the last successful Ping Pong with the
|
|
||||||
* users server. If there was no successful Ping (e.g. because this
|
|
||||||
* feature is disabled) -1 will be returned.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public long getLastSuccessfulPing() {
|
|
||||||
return Math.max(lastSuccessfulPingByTask, lastSuccessfulManualPing);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Set<PingFailedListener> getPingFailedListeners() {
|
|
||||||
return pingFailedListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels any existing periodic ping task if there is one and schedules a new ping task if pingInterval is greater
|
|
||||||
* then zero.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected synchronized void maybeSchedulePingServerTask() {
|
|
||||||
maybeStopPingServerTask();
|
|
||||||
if (pingInterval > 0) {
|
|
||||||
periodicPingTask = periodicPingExecutorService.schedule(new ServerPingTask(connection), pingInterval,
|
|
||||||
TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeStopPingServerTask() {
|
|
||||||
if (periodicPingTask != null) {
|
|
||||||
periodicPingTask.cancel(true);
|
|
||||||
periodicPingTask = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void pongReceived() {
|
|
||||||
lastSuccessfulManualPing = System.currentTimeMillis();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2012-2013 Florian Schmaus
|
|
||||||
*
|
|
||||||
* All rights reserved. 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 org.jivesoftware.smackx.ping;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.Connection;
|
|
||||||
|
|
||||||
class ServerPingTask implements Runnable {
|
|
||||||
|
|
||||||
// This has to be a weak reference because IIRC all threads are roots
|
|
||||||
// for objects and we have a new thread here that should hold a strong
|
|
||||||
// reference to connection so that it can be GCed.
|
|
||||||
private WeakReference<Connection> weakConnection;
|
|
||||||
|
|
||||||
private int delta = 1000; // 1 seconds
|
|
||||||
private int tries = 3; // 3 tries
|
|
||||||
|
|
||||||
protected ServerPingTask(Connection connection) {
|
|
||||||
this.weakConnection = new WeakReference<Connection>(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
Connection connection = weakConnection.get();
|
|
||||||
if (connection == null) {
|
|
||||||
// connection has been collected by GC
|
|
||||||
// which means we can stop the thread by breaking the loop
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (connection.isAuthenticated()) {
|
|
||||||
PingManager pingManager = PingManager.getInstanceFor(connection);
|
|
||||||
boolean res = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < tries; i++) {
|
|
||||||
if (i != 0) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(delta);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// We received an interrupt
|
|
||||||
// This only happens if we should stop pinging
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res = pingManager.pingMyServer();
|
|
||||||
// stop when we receive a pong back
|
|
||||||
if (res) {
|
|
||||||
pingManager.lastSuccessfulPingByTask = System.currentTimeMillis();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!res) {
|
|
||||||
Set<PingFailedListener> pingFailedListeners = pingManager.getPingFailedListeners();
|
|
||||||
for (PingFailedListener l : pingFailedListeners) {
|
|
||||||
l.pingFailed();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Ping was successful, wind-up the periodic task again
|
|
||||||
pingManager.maybeSchedulePingServerTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2012 Florian Schmaus
|
|
||||||
*
|
|
||||||
* All rights reserved. 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 org.jivesoftware.smackx.ping.packet;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
|
||||||
|
|
||||||
public class Pong extends IQ {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Composes a Pong packet from a received ping packet. This basically swaps
|
|
||||||
* the 'from' and 'to' attributes. And sets the IQ type to result.
|
|
||||||
*
|
|
||||||
* @param ping
|
|
||||||
*/
|
|
||||||
public Pong(Ping ping) {
|
|
||||||
setType(IQ.Type.RESULT);
|
|
||||||
setFrom(ping.getTo());
|
|
||||||
setTo(ping.getFrom());
|
|
||||||
setPacketID(ping.getPacketID());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the child element of the Pong reply, which is non-existent. This
|
|
||||||
* is why we return 'null' here. See e.g. Example 11 from
|
|
||||||
* http://xmpp.org/extensions/xep-0199.html#e2e
|
|
||||||
*/
|
|
||||||
public String getChildElementXML() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
* Copyright 2009 Robin Collier.
|
||||||
*
|
*
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,9 +17,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
* Created on 2009-07-13
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.pubsub;
|
package org.jivesoftware.smackx.pubsub;
|
||||||
|
|
||||||
import org.jivesoftware.smack.Connection;
|
import org.jivesoftware.smack.Connection;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* $Revision$
|
* $Revision$
|
||||||
* $Date$
|
* $Date$
|
||||||
*
|
*
|
||||||
* Copyright 2003-2007 Jive Software.
|
* Copyright 2009 Robin Collier.
|
||||||
*
|
*
|
||||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,9 +17,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
* Created on 2009-07-09
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.pubsub;
|
package org.jivesoftware.smackx.pubsub;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue