1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-26 16:22:06 +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:
rcollier 2013-05-18 16:56:52 +00:00
commit dac68c64a9
163 changed files with 2304 additions and 2366 deletions

View file

@ -28,7 +28,7 @@
<property name="version.major" value="3" />
<property name="version.minor" value="3" />
<property name="version.revision" value="0" />
<property name="version.extra" value="SNAPSHOT" />
<property name="version.extra" value="" />
<if>
<equals arg1="${version.extra}" arg2=""/>

File diff suppressed because one or more lines are too long

View file

@ -2,21 +2,6 @@
<!-- Smack configuration file. -->
<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 -->
<packetReplyTimeout>5000</packetReplyTimeout>
@ -32,10 +17,24 @@
<!-- Port of the local Socks5 proxy -->
<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 -->
<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>

View file

@ -241,7 +241,7 @@
<iqProvider>
<elementName>ping</elementName>
<namespace>urn:xmpp:ping</namespace>
<className>org.jivesoftware.smackx.ping.provider.PingProvider</className>
<className>org.jivesoftware.smack.ping.provider.PingProvider</className>
</iqProvider>
<extensionProvider>
@ -641,32 +641,6 @@
<className>org.jivesoftware.smackx.packet.AttentionExtension$Provider</className>
</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 -->
<extensionProvider>
<elementName>received</elementName>

View file

@ -203,6 +203,36 @@ last release.
to use these icons outside of Smack.</li>
<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>
</div>

View file

@ -141,9 +141,61 @@ hr {
<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&#39;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&#39;t work.</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-394'>SMACK-394</a>] - Erroneous cast in IBBInputStream&#39;s read() method</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-395'>SMACK-395</a>] - Socks5BytestreamManager&#39;s establishConnection() should still try to use the local streamhost proxy if the server doesn&#39;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>
<h3>Bug</h3>
<h3>Bug Fixes</h3>
<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-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>
</ul>
<h3>Improvement</h3>
<h3>Improvements</h3>
<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-354'>SMACK-354</a>] - Provide milliseconds in timestamp colum debugwindow</li>
</ul>
<h2>3.2.1 -- <span style="font-weight: normal;">July 4, 2011</span></h2>
<h3>Bug</h3>
<h3>Bug Fixes</h3>
<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-230'>SMACK-230</a>] - Disconnect Can Cause Null Pointer Exception</li>
@ -176,14 +227,14 @@ hr {
</ul>
<h2>3.2.0 -- <span style="font-weight: normal;">May 3, 2011</span></h2>
<h3>New Feature</h3>
<h3>New Features</h3>
<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-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>
</ul>
<h3>Improvement</h3>
<h3>Improvements</h3>
<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-156'>SMACK-156</a>] - Add the ability to register for roster events before logging in</li>
@ -208,9 +259,9 @@ hr {
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-310'>SMACK-310</a>] - Add Support for Localized Message Subjects</li>
</ul>
<h3>Bug</h3>
<h3>Bug Fixes</h3>
<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-225'>SMACK-225</a>] - Improper handeling of DNS SRV records</li>
<li>[<a href='http://issues.igniterealtime.org/browse/SMACK-232'>SMACK-232</a>] - Better handling of Roster error</li>

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -178,12 +178,12 @@ public abstract class Connection {
protected SmackDebugger debugger = null;
/**
* The Reader which is used for the {@see debugger}.
* The Reader which is used for the debugger.
*/
protected Reader reader;
/**
* The Writer which is used for the {@see debugger}.
* The Writer which is used for the debugger.
*/
protected Writer writer;

View file

@ -40,18 +40,11 @@ import java.util.concurrent.BlockingQueue;
class PacketWriter {
private Thread writerThread;
private Thread keepAliveThread;
private Writer writer;
private XMPPConnection connection;
private final BlockingQueue<Packet> queue;
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.
*
@ -117,25 +110,6 @@ class PacketWriter {
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) {
this.writer = writer;
}
@ -149,9 +123,6 @@ class PacketWriter {
synchronized (queue) {
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)) {
Packet packet = nextPacket();
if (packet != null) {
synchronized (writer) {
writer.write(packet.toXML());
if (queue.isEmpty()) {
writer.flush();
// Keep track of the last time a stanza was sent to the server
lastActive = System.currentTimeMillis();
}
writer.write(packet.toXML());
if (queue.isEmpty()) {
writer.flush();
}
}
}
@ -205,13 +173,11 @@ class PacketWriter {
// we won't have time to entirely flush it before the socket is forced closed
// by the shutdown process.
try {
synchronized (writer) {
while (!queue.isEmpty()) {
Packet packet = queue.remove();
writer.write(packet.toXML());
}
writer.flush();
while (!queue.isEmpty()) {
Packet packet = queue.remove();
writer.write(packet.toXML());
}
writer.flush();
}
catch (Exception e) {
e.printStackTrace();
@ -268,54 +234,4 @@ class PacketWriter {
writer.write(stream.toString());
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
}
}
}
}
}

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -316,7 +316,12 @@ public class SASLAuthentication implements UserAuthentication {
// Trigger SASL authentication with the selected mechanism. We use
// connection.getHost() since GSAPI requires the FQDN of the server, which
// 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
synchronized (this) {
@ -383,7 +388,7 @@ public class SASLAuthentication implements UserAuthentication {
public String authenticateAnonymously() throws XMPPException {
try {
currentMechanism = new SASLAnonymous(this);
currentMechanism.authenticate(null,null,"");
currentMechanism.authenticate(null,null,null,"");
// Wait until SASL negotiation finishes
synchronized (this) {

View file

@ -48,7 +48,7 @@ import org.xmlpull.v1.XmlPullParser;
*/
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 keepAliveInterval = 30000;
@ -58,11 +58,6 @@ public final class SmackConfiguration {
private static int localSocks5ProxyPort = 7777;
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
*/
@ -117,8 +112,8 @@ public final class SmackConfiguration {
else if (parser.getName().equals("packetCollectorSize")) {
packetCollectorSize = parseIntProperty(parser, packetCollectorSize);
}
else if (parser.getName().equals("defaultPingInterval")) {
defaultPingInterval = parseIntProperty(parser, defaultPingInterval);
else if (parser.getName().equals("autoEnableEntityCaps")) {
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
}
else if (parser.getName().equals("autoEnableEntityCaps")) {
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() {
return defaultPingInterval;
}
/**
* 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;
public static void setAutoEnableEntityCaps(boolean b) {
autoEnableEntityCaps = b;
}
/**
@ -345,15 +331,6 @@ public final class SmackConfiguration {
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 {
String className = parser.nextText();
// Attempt to load the class so that the class can get initialized

View 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;
}
}

View file

@ -650,10 +650,6 @@ public class XMPPConnection extends Connection {
// Make note of the fact that we're now connected.
connected = true;
// Start keep alive process (after TLS was negotiated - if available)
packetWriter.startKeepAliveProcess();
if (isFirstInitialization) {
// Notify listeners that a new connection has been established
for (ConnectionCreationListener listener : getConnectionCreationListeners()) {

View file

@ -41,10 +41,12 @@ import java.io.PrintWriter;
* @author Matt Tucker
*/
public class XMPPException extends Exception {
private static final long serialVersionUID = 6881651633890968625L;
private StreamError streamError = null;
private XMPPError error = null;
private Throwable wrappedThrowable = null;
private SmackError smackError = null;
/**
* Creates a new XMPPException.
@ -62,6 +64,16 @@ public class XMPPException extends Exception {
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
* 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
* TCP connection will be closed by the server.
*
@ -144,6 +156,16 @@ public class XMPPException extends Exception {
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
* isn't one. The underlying TCP connection is closed by the server after sending the

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2003 Jive Software.
*
* 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.

View 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;
}
}
}

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -14,8 +14,14 @@
* 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 {
/**
* Called when the server ping fails.
*/
void pingFailed();
}

View file

@ -14,25 +14,26 @@
* 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.smackx.ping.PingManager;
public class Ping extends IQ {
public static final String NAMESPACE = "urn:xmpp:ping";
public static final String ELEMENT = "ping";
public Ping() {
}
public Ping(String from, String to) {
public Ping(String to) {
setTo(to);
setFrom(from);
setType(IQ.Type.GET);
setPacketID(getPacketID());
}
@Override
public String getChildElementXML() {
return "<" + PingManager.ELEMENT + " xmlns=\'" + PingManager.NAMESPACE + "\' />";
return "<" + ELEMENT + " xmlns=\'" + NAMESPACE + "\' />";
}
}

View file

@ -14,11 +14,11 @@
* 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.ping.packet.Ping;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smackx.ping.packet.Ping;
import org.xmlpull.v1.XmlPullParser;
public class PingProvider implements IQProvider {

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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
@ -92,8 +90,7 @@ class HTTPProxySocketFactory
else
{
String password = proxy.getProxyPassword();
proxyLine = "\r\nProxy-Authorization: Basic "
+ new String(StringUtils.encodeBase64(username + ":" + password));
proxyLine = "\r\nProxy-Authorization: Basic " + StringUtils.encodeBase64(username + ":" + password);
}
socket.getOutputStream().write((hostport + " HTTP/1.1\r\nHost: "
+ hostport + proxyLine + "\r\n\r\n").getBytes("UTF-8"));

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -51,6 +51,30 @@ import javax.security.sasl.SaslException;
* using the CallbackHandler method.</li>
* <li>{@link #challengeReceived(String)} -- Handle a challenge from the server.</li>
* </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
*/
@ -62,23 +86,58 @@ public abstract class SASLMechanism implements CallbackHandler {
protected String password;
protected String hostname;
public SASLMechanism(SASLAuthentication saslAuthentication) {
this.saslAuthentication = saslAuthentication;
}
/**
* Builds and sends the <tt>auth</tt> stanza to the server. Note that this method of
* 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.
*
* 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 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.
* @throws IOException If a network error occurs while authenticating.
* @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
//information
@ -89,10 +148,26 @@ public abstract class SASLMechanism implements CallbackHandler {
String[] mechanisms = { getName() };
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();
}
/**
* 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
* 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());
} else if(callbacks[i] instanceof RealmCallback) {
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){
//unused
//RealmChoiceCallback rccb = (RealmChoiceCallback)callbacks[i];

View file

@ -29,7 +29,7 @@ import java.io.IOException;
*/
public class Base32Encoder implements StringEncoder {
private static Base32Encoder instance;
private static Base32Encoder instance = new Base32Encoder();
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ2345678";
private Base32Encoder() {
@ -37,9 +37,6 @@ public class Base32Encoder implements StringEncoder {
}
public static Base32Encoder getInstance() {
if (instance == null) {
instance = new Base32Encoder();
}
return instance;
}

View file

@ -8,65 +8,8 @@ package org.jivesoftware.smack.util;
/**
* <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 rob@iharder.net
@ -368,33 +311,6 @@ public class Base64
/** Defeats instantiation. */
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.
*

View file

@ -16,20 +16,18 @@ package org.jivesoftware.smack.util;
/**
* A Base 64 encoding implementation.
* @author Florian Schmaus
*/
public class Base64Encoder implements StringEncoder {
private static Base64Encoder instance;
private static Base64Encoder instance = new Base64Encoder();
private Base64Encoder() {
// Use getInstance()
}
public static Base64Encoder getInstance() {
if (instance == null) {
instance = new Base64Encoder();
}
return instance;
}

View 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));
}
}

View file

@ -81,7 +81,12 @@ public class DNSUtil {
* @return List of HostAddress, which encompasses the hostname and port that the
* 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');
}
@ -102,7 +107,12 @@ public class DNSUtil {
* @return List of HostAddress, which encompasses the hostname and port that the
* 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');
}
@ -117,9 +127,6 @@ public class DNSUtil {
}
}
if (dnsResolver == null)
throw new IllegalStateException("No DNS resolver active.");
List<HostAddress> addresses = new ArrayList<HostAddress>();
// Step one: Do SRV lookups

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2013 Robin Collier.
*
* 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.
@ -23,42 +23,43 @@ import java.text.SimpleDateFormat;
/**
* Defines the various date and time profiles used in XMPP along with their associated formats.
*
* @author Robin Collier
*
*/
public enum DateFormatType
{
XEP_0082_DATE_PROFILE("yyyy-MM-dd"),
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_TIME_PROFILE("hh:mm:ss"),
XEP_0082_TIME_ZONE_PROFILE("hh:mm:ssZ"),
XEP_0082_TIME_MILLIS_PROFILE("hh:mm:ss.SSS"),
XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSSZ"),
XEP_0091_DATETIME("yyyyMMdd'T'HH:mm:ss");
public enum DateFormatType {
// @formatter:off
XEP_0082_DATE_PROFILE("yyyy-MM-dd"),
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_TIME_PROFILE("hh:mm:ss"),
XEP_0082_TIME_ZONE_PROFILE("hh:mm:ssZ"),
XEP_0082_TIME_MILLIS_PROFILE("hh:mm:ss.SSS"),
XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSSZ"),
XEP_0091_DATETIME("yyyyMMdd'T'HH:mm:ss");
// @formatter:on
private String formatString;
private String formatString;
private DateFormatType(String dateFormat)
{
formatString = dateFormat;
}
private DateFormatType(String dateFormat) {
formatString = dateFormat;
}
/**
* Get the format string as defined in either XEP-0082 or XEP-0091.
* @return The defined string format for the date.
*/
public String getFormatString()
{
return formatString;
}
/**
* Get the format string as defined in either XEP-0082 or XEP-0091.
*
* @return The defined string format for the date.
*/
public String getFormatString() {
return formatString;
}
/**
* Create a {@link SimpleDateFormat} object with the format defined by {@link #getFormatString()}.
* @return A new date formatter.
*/
public SimpleDateFormat createFormatter()
{
return new SimpleDateFormat(getFormatString());
}
/**
* Create a {@link SimpleDateFormat} object with the format defined by {@link #getFormatString()}.
*
* @return A new date formatter.
*/
public SimpleDateFormat createFormatter() {
return new SimpleDateFormat(getFormatString());
}
}

View file

@ -17,8 +17,6 @@
*/
package org.jivesoftware.smack.util;
// TODO move StringEncoder, Base64Encoder and Base32Encoder to smack.util
public interface StringEncoder {
/**
* Encodes an string to another representation
@ -26,7 +24,7 @@ public interface StringEncoder {
* @param string
* @return
*/
public String encode(String string);
String encode(String string);
/**
* Decodes an string back to it's initial representation
@ -34,5 +32,5 @@ public interface StringEncoder {
* @param string
* @return
*/
public String decode(String string);
String decode(String string);
}

View file

@ -16,6 +16,7 @@ package org.jivesoftware.smack.util;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.SmackError;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
@ -47,7 +48,7 @@ final public class SyncPacketSend
response.cancel();
if (result == null) {
throw new XMPPException("No response from server.");
throw new XMPPException(SmackError.NO_RESPONSE_FROM_SERVER);
}
else if (result.getError() != null) {
throw new XMPPException(result.getError());

View file

@ -22,18 +22,19 @@ import org.xbill.DNS.Lookup;
import org.xbill.DNS.Record;
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() {
}
public static DNSResolver getInstance() {
if (instance == null) {
instance = new DNSJavaResolver();
}
return instance;
}

View file

@ -17,8 +17,17 @@ package org.jivesoftware.smack.util.dns;
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);
}

View file

@ -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
*
* @param fqdn
* @throws IllegalArgumentException
* @param fqdn Fully qualified domain name.
* @throws IllegalArgumentException If the fqdn is null.
*/
public HostAddress(String fqdn) throws IllegalArgumentException {
public HostAddress(String fqdn) {
if (fqdn == null)
throw new IllegalArgumentException("FQDN is null");
if (fqdn.charAt(fqdn.length() - 1) == '.') {
@ -39,7 +39,14 @@ public class HostAddress {
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);
if (port < 0 || port > 65535)
throw new IllegalArgumentException(
@ -60,10 +67,12 @@ public class HostAddress {
this.exception = e;
}
@Override
public String toString() {
return fqdn + ":" + port;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
@ -80,6 +89,13 @@ public class HostAddress {
return port == address.port;
}
@Override
public int hashCode() {
int result = 1;
result = 37 * result + fqdn.hashCode();
return result * 37 + port;
}
public String getErrorMessage() {
String error;
if (exception == null) {

View file

@ -28,12 +28,12 @@ import javax.naming.directory.InitialDirContext;
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
*
*/
public class JavaxResolver extends DNSResolver {
public class JavaxResolver implements DNSResolver {
private static JavaxResolver instance;
private static DirContext dirContext;
@ -48,14 +48,14 @@ public class JavaxResolver extends DNSResolver {
}
// Try to set this DNS resolver as primary one
DNSUtil.setDNSResolver(maybeGetInstance());
DNSUtil.setDNSResolver(getInstance());
}
private JavaxResolver() {
}
public static DNSResolver maybeGetInstance() {
public static DNSResolver getInstance() {
if (instance == null && isSupported()) {
instance = new JavaxResolver();
}

View file

@ -29,13 +29,13 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
/**
* Create a new SRVRecord
*
* @param fqdn
* @param port
* @param priority
* @param weight
* @throws IllegalArgumentException
* @param fqdn Fully qualified domain name
* @param port The connection port
* @param priority Priority of the target host
* @param weight Relative weight for records with same priority
* @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);
if (weight < 0 || weight > 65535)
throw new IllegalArgumentException(
@ -60,6 +60,7 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
return weight;
}
@Override
public int compareTo(SRVRecord other) {
// According to RFC2782,
// "[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;
}
@Override
public String toString() {
return super.toString() + " prio:" + priority + ":w:" + weight;
}

View file

@ -299,24 +299,23 @@ public class FormField {
return buf.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (obj.getClass() != getClass())
if (!(obj instanceof FormField))
return false;
FormField other = (FormField) obj;
String thisXml = toXML();
String otherXml = other.toXML();
return toXML().equals(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;
}
@Override
public String toString() {
return getLabel();
}
@ -375,6 +375,7 @@ public class FormField {
return buf.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
@ -396,5 +397,13 @@ public class FormField {
return true;
}
@Override
public int hashCode() {
int result = 1;
result = 37 * result + value.hashCode();
result = 37 * result + (label == null ? 0 : label.hashCode());
return result;
}
}
}

View file

@ -45,7 +45,7 @@ public interface NodeInformationProvider {
*
* @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
@ -55,7 +55,7 @@ public interface NodeInformationProvider {
*
* @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
@ -64,12 +64,12 @@ public interface NodeInformationProvider {
*
* @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.
*
* @return a list of the packet extensions defined in the node.
*/
public abstract List<PacketExtension> getNodePacketExtensions();
List<PacketExtension> getNodePacketExtensions();
}

View file

@ -513,7 +513,7 @@ public class ServiceDiscoveryManager {
// If the node version is known, store the new entry.
if (nvh != null) {
if (EntityCapsManager.verifyDiscvoerInfoVersion(nvh.getVer(), nvh.getHash(), info))
if (EntityCapsManager.verifyDiscoverInfoVersion(nvh.getVer(), nvh.getHash(), info))
EntityCapsManager.addDiscoverInfoByNode(nvh.getNodeVer(), info);
}

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2005 Jive Software.
*
* 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.

View file

@ -3,8 +3,6 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
*
* 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

View file

@ -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 + "\"/>";
}
}
}

View file

@ -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());
}
}

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2008 Jive Software.
*
* 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.

View file

@ -506,7 +506,7 @@ public class EntityCapsManager {
* @param info
* @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
if (info.containsDuplicateIdentities())
return false;
@ -583,7 +583,7 @@ public class EntityCapsManager {
// NAME is not included (in accordance with XEP-0030, the category and
// type MUST be included.
SortedSet<DiscoverInfo.Identity> sortedIdentities = new TreeSet<DiscoverInfo.Identity>();
;
for (Iterator<DiscoverInfo.Identity> it = discoverInfo.getIdentities(); it.hasNext();)
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
// field
// see XEP-0115 5.4 step 3.6
if (extendedInfo != null && extendedInfo.hasHiddenFromTypeField()) {
if (extendedInfo != null && extendedInfo.hasHiddenFormTypeField()) {
synchronized (extendedInfo) {
// 6. If the service discovery information response includes
// XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e.,

View file

@ -24,15 +24,15 @@ public interface EntityCapsPersistentCache {
* @param node
* @param info
*/
abstract void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info);
void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info);
/**
* Replay the Caches data into EntityCapsManager
*/
abstract void replay() throws IOException;
void replay() throws IOException;
/**
* Empty the Cache
*/
abstract void emptyCache();
void emptyCache();
}

View file

@ -27,7 +27,7 @@ import java.io.StringReader;
import org.jivesoftware.smack.packet.IQ;
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.smackx.entitycaps.EntityCapsManager;
import org.jivesoftware.smackx.packet.DiscoverInfo;
@ -47,19 +47,20 @@ import org.xmlpull.v1.XmlPullParserException;
public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache {
private File cacheDir;
private StringEncoder stringEncoder;
private StringEncoder filenameEncoder;
/**
* Creates a new SimpleDirectoryPersistentCache Object. Make sure that the
* cacheDir exists and that it's an directory.
*
* If your cacheDir is case insensitive then make sure to set the
* StringEncoder to Base32.
* <p>
* Default filename encoder {@link Base32Encoder}, as this will work on all
* filesystems, both case sensitive and case insensitive. It does however
* produce longer filenames.
*
* @param 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.
*
* 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 stringEncoder
* @param cacheDir The directory where the cache will be stored.
* @param filenameEncoder Encodes the node string into a filename.
*/
public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder stringEncoder) {
public SimpleDirectoryPersistentCache(File cacheDir, StringEncoder filenameEncoder) {
if (!cacheDir.exists())
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" does not exist");
if (!cacheDir.isDirectory())
throw new IllegalStateException("Cache directory \"" + cacheDir + "\" is not a directory");
this.cacheDir = cacheDir;
this.stringEncoder = stringEncoder;
this.filenameEncoder = filenameEncoder;
}
@Override
public void addDiscoverInfoByNodePersistent(String node, DiscoverInfo info) {
String filename = stringEncoder.encode(node);
String filename = filenameEncoder.encode(node);
File nodeFile = new File(cacheDir, filename);
try {
if (nodeFile.createNewFile())
writeInfoToFile(nodeFile, info);
@ -99,7 +99,7 @@ public class SimpleDirectoryPersistentCache implements EntityCapsPersistentCache
public void replay() throws IOException {
File[] files = cacheDir.listFiles();
for (File f : files) {
String node = stringEncoder.decode(f.getName());
String node = filenameEncoder.decode(f.getName());
DiscoverInfo info = restoreInfoFromFile(f);
if (info == null)
continue;

View file

@ -1,4 +1,4 @@
/*
/**
* Copyright 2009 Jonas Ådahl.
* Copyright 2011-2013 Florian Schmaus
*

View file

@ -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);
}
}
}

View file

@ -202,7 +202,7 @@ public class DataForm implements PacketExtension {
*
* @return
*/
public boolean hasHiddenFromTypeField() {
public boolean hasHiddenFormTypeField() {
boolean found = false;
for (FormField f : fields) {
if (f.getVariable().equals("FORM_TYPE") && f.getType() != null && f.getType().equals("hidden"))

View file

@ -257,13 +257,25 @@ public class DiscoverInfo extends IQ {
* attributes.
*
*/
public static class Identity implements Comparable<Object> {
public static class Identity implements Comparable<Identity> {
private String category;
private String name;
private String type;
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.
* '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).
*/
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.name = name;
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>
*
* @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) {
this.type = type;
@ -374,12 +390,15 @@ public class DiscoverInfo extends IQ {
String otherLang = other.lang == null ? "" : other.lang;
String thisLang = lang == null ? "" : lang;
if (!other.type.equals(type))
return false;
if (!otherLang.equals(thisLang))
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 thisName = name == null ? "" : other.name;
if (!thisName.equals(otherName))
@ -388,22 +407,34 @@ public class DiscoverInfo extends IQ {
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.
* Name is not used for comparision, as defined by XEP-0115
*
* @param obj
* @return
*/
public int compareTo(Object obj) {
DiscoverInfo.Identity other = (DiscoverInfo.Identity) obj;
public int compareTo(DiscoverInfo.Identity other) {
String otherLang = other.lang == null ? "" : other.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 (type.equals(other.type)) {
if (thisType.equals(otherType)) {
if (thisLang.equals(otherLang)) {
// Don't compare on name, XEP-30 says that name SHOULD
// be equals for all identities of an entity
@ -412,7 +443,7 @@ public class DiscoverInfo extends IQ {
return thisLang.compareTo(otherLang);
}
} else {
return type.compareTo(other.type);
return thisType.compareTo(otherType);
}
} else {
return category.compareTo(other.category);
@ -436,6 +467,8 @@ public class DiscoverInfo extends IQ {
* @param variable the feature's variable.
*/
public Feature(String variable) {
if (variable == null)
throw new IllegalArgumentException("variable cannot be null");
this.variable = variable;
}
@ -465,5 +498,10 @@ public class DiscoverInfo extends IQ {
DiscoverInfo.Feature other = (DiscoverInfo.Feature) obj;
return variable.equals(other.variable);
}
@Override
public int hashCode() {
return 37 * variable.hashCode();
}
}
}

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2005 Jive Software.
*
* 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.

View file

@ -85,6 +85,7 @@ import org.jivesoftware.smack.util.StringUtils;
* @author Kirill Maximov (kir@maxkir.com)
*/
public class VCard extends IQ {
private static final String DEFAULT_MIME_TYPE = "image/jpeg";
/**
* Phone types:
@ -93,7 +94,6 @@ public class VCard extends IQ {
private Map<String, String> homePhones = new HashMap<String, String>();
private Map<String, String> workPhones = new HashMap<String, String>();
/**
* Address types:
* 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
*/
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;
}
/**
* 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
* no avatar could be found.

View file

@ -17,51 +17,46 @@
package org.jivesoftware.smackx.ping;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
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.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.SmackError;
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.PacketIDFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.keepalive.KeepAliveManager;
import org.jivesoftware.smack.packet.IQ;
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.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
* alternative to the traditional 'white space ping' approach of determining the
* availability of an entity. The XMPP Ping protocol allows ping messages to be
* send in a more XML-friendly approach, which can be used over more than one
* hop in the communication path.
* Implements the XMPP Ping as defined by XEP-0199. The XMPP Ping protocol
* allows one entity to 'ping' any other entity by simply sending a ping to
* the appropriate JID.
* <p>
* 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
* @see <a href="http://www.xmpp.org/extensions/xep-0199.html">XEP-0199:XMPP
* Ping</a>
*/
public class PingManager {
public static final String NAMESPACE = "urn:xmpp:ping";
public static final String ELEMENT = "ping";
private static Map<Connection, PingManager> instances =
Collections.synchronizedMap(new WeakHashMap<Connection, PingManager>());
private static Map<Connection, PingManager> instances = Collections
.synchronizedMap(new WeakHashMap<Connection, PingManager>());
static {
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
@ -71,273 +66,106 @@ public class PingManager {
});
}
private ScheduledExecutorService periodicPingExecutorService;
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
*/
public void processPacket(Packet packet) {
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) {
/**
* 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 synchronized static PingManager getInstanceFor(Connection connection) {
PingManager pingManager = instances.get(connection);
if (pingManager == null) {
pingManager = new PingManager(connection);
}
return pingManager;
}
public void setPingIntervall(int pingIntervall) {
this.pingInterval = pingIntervall;
}
private PingManager(Connection con) {
this.connection = con;
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
public int getPingIntervall() {
return pingInterval;
}
// The ServiceDiscoveryManager was not pre-initialized
if (sdm == null)
sdm = new ServiceDiscoveryManager(connection);
public void registerPingFailedListener(PingFailedListener listener) {
pingFailedListeners.add(listener);
}
sdm.addFeature(Ping.NAMESPACE);
public void unregisterPingFailedListener(PingFailedListener listener) {
pingFailedListeners.remove(listener);
}
PacketFilter pingPacketFilter = new AndFilter(new PacketTypeFilter(Ping.class), new IQTypeFilter(Type.GET));
public void disablePingFloodProtection() {
setPingMinimumInterval(-1);
}
public void setPingMinimumInterval(long ms) {
this.pingMinDelta = ms;
}
public long getPingMinimumInterval() {
return this.pingMinDelta;
connection.addPacketListener(new PacketListener() {
/**
* Sends a Pong for every Ping
*/
public void processPacket(Packet packet) {
IQ pong = IQ.createResultIQ((Ping) packet);
connection.sendPacket(pong);
}
}, pingPacketFilter);
}
/**
* Pings the given jid and returns the IQ response which is either of
* IQ.Type.ERROR or IQ.Type.RESULT. If we are not connected or if there was
* no reply, null is returned.
* Pings the given jid. This method will return false if an error occurs. The exception
* to this, is a server ping, which will always return true if the server is reachable,
* 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
* supported by the user.
*
* @param jid
* @param pingTimeout
* @return
* @param jid The id of the entity the ping is being sent to
* @param pingTimeout The time to wait for a reply
* @return true if a reply was received from the entity, false otherwise.
*/
public IQ ping(String jid, long pingTimeout) {
// Make sure we actually connected to the server
if (!connection.isAuthenticated())
return null;
public boolean ping(String jid, long pingTimeout) {
Ping ping = new Ping(jid);
Ping ping = new Ping(connection.getUser(), jid);
try {
SyncPacketSend.getReply(connection, ping);
}
catch (XMPPException exc) {
PacketCollector collector =
connection.createPacketCollector(new PacketIDFilter(ping.getPacketID()));
connection.sendPacket(ping);
IQ result = (IQ) collector.nextResult(pingTimeout);
collector.cancel();
return result;
return (jid.equals(connection.getServiceName()) && (exc.getSmackError() != SmackError.NO_RESPONSE_FROM_SERVER));
}
return true;
}
/**
* Pings the given jid and returns the IQ response with the default
* packet reply timeout
* Same as calling {@link #ping(String, long)} with the defaultpacket reply
* timeout.
*
* @param jid
* @return
* @param jid The id of the entity the ping is being sent to
* @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());
}
/**
* 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
* service-unavailable there is no way to determine if the response was send
* by the entity (e.g. a user JID) or from a server in between. This is
* 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
* @param jid The id of the entity the query is being sent to
* @return true if it supports ping, false otherwise.
* @throws XMPPException An XMPP related error occurred during the request
*/
public boolean pingEntity(String jid, long pingTimeout) {
IQ result = ping(jid, pingTimeout);
if (result == null || result.getType() == IQ.Type.ERROR) {
return false;
}
pongReceived();
return true;
}
public boolean pingEntity(String jid) {
return pingEntity(jid, SmackConfiguration.getPacketReplyTimeout());
public boolean isPingSupported(String jid) throws XMPPException {
DiscoverInfo result = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
return result.containsFeature(Ping.NAMESPACE);
}
/**
* Pings the user's server. Will notify the registered
* pingFailedListeners in case of error.
* Pings the server. This method will return true if the server is reachable. It
* 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 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
* @return true if a reply was received from the server, false otherwise.
*/
public boolean pingMyServer() {
return pingMyServer(SmackConfiguration.getPacketReplyTimeout());
}
/**
* 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();
return ping(connection.getServiceName());
}
}

View file

@ -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();
}
}
}
}

View file

@ -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;
}
}

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2009 Robin Collier.
*
* 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.
@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on 2009-07-13
*/
package org.jivesoftware.smackx.pubsub;
import org.jivesoftware.smack.Connection;

View file

@ -3,7 +3,7 @@
* $Revision$
* $Date$
*
* Copyright 2003-2007 Jive Software.
* Copyright 2009 Robin Collier.
*
* 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.
@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on 2009-07-09
*/
package org.jivesoftware.smackx.pubsub;
import java.util.ArrayList;

Some files were not shown because too many files have changed in this diff Show more