Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Alexander Kuppe2013-10-21 14:28:32 +0000
committerMarkus Alexander Kuppe2013-10-21 14:28:32 +0000
commit1c721d9715664b587b0c3f9173d397bbc53617d1 (patch)
tree1866290c5f9a021ec7174ad376d0764fa3f15595 /protocols
parenta693df6386107b7b2d069fd65a78f5772f00b745 (diff)
parent3f59c78d45fb4856da8390f2ff21e106f3787e01 (diff)
downloadorg.eclipse.ecf-1c721d9715664b587b0c3f9173d397bbc53617d1.tar.gz
org.eclipse.ecf-1c721d9715664b587b0c3f9173d397bbc53617d1.tar.xz
org.eclipse.ecf-1c721d9715664b587b0c3f9173d397bbc53617d1.zip
Merge branch 'master' of ssh://git.eclipse.org:29418/ecf/org.eclipse.ecf
Diffstat (limited to 'protocols')
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/AbstractConnectionListener.java92
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/NonSASLAuthentication.java286
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/OpenTrustManager.java96
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PacketInterceptor.java98
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyList.java114
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListListener.java100
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListManager.java932
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/ReconnectionManager.java406
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SASLAuthentication.java1180
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SmackError.java48
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/UserAuthentication.java158
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/filter/IQTypeFilter.java96
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Bind.java142
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Privacy.java644
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/PrivacyItem.java890
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Session.java90
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/StreamError.java212
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java218
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/PrivacyProvider.java268
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLAnonymous.java124
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLCramMD5Mechanism.java76
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLDigestMD5Mechanism.java76
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLExternalMechanism.java118
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java178
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLMechanism.java808
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLPlainMechanism.java68
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/Base64.java3364
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/SyncPacketSend.java128
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/LastActivityManager.java460
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/SharedGroupManager.java106
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamListener.java94
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamManager.java228
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java118
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamSession.java162
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java150
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java146
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java92
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java1092
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamRequest.java184
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamSession.java1590
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java254
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java130
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Data.java128
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java298
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java252
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/CloseIQProvider.java66
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/DataPacketProvider.java90
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/OpenIQProvider.java90
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/InitiationListener.java238
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamListener.java86
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java1536
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamRequest.java632
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamSession.java162
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java408
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java234
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java846
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java146
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java948
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/provider/BytestreamsProvider.java164
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommand.java898
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandManager.java1498
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandNote.java170
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/LocalCommand.java336
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransfer.java760
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferListener.java72
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferManager.java364
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java970
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferRequest.java276
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IBBTransferNegotiator.java304
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java430
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java898
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java328
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java334
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AdHocCommandData.java556
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AttentionExtension.java200
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/ChatStateExtension.java146
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/DelayInfo.java210
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Header.java118
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/HeadersExtension.java138
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Nick.java224
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/SharedGroupsInfo.java146
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/StreamInitiation.java838
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/AdHocCommandDataProvider.java310
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/DelayInfoProvider.java84
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/EmbeddedExtensionProvider.java222
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeaderProvider.java88
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeadersProvider.java74
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/StreamInitiationProvider.java248
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AccessModel.java76
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Affiliation.java180
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java138
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ChildrenAssociationPolicy.java64
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/CollectionNode.java24
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigurationEvent.java112
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureForm.java1418
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureNodeFields.java436
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EmbeddedPacketExtension.java90
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElement.java148
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElementType.java82
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNode.java198
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNodeType.java100
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormType.java50
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/GetItemsRequest.java170
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Item.java264
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemDeleteEvent.java124
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java246
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemReply.java58
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemsExtension.java392
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/LeafNode.java704
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Node.java1044
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeEvent.java32
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeExtension.java170
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeType.java50
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/OptionsExtension.java144
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PayloadItem.java274
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PresenceState.java50
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubElementType.java160
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubManager.java658
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishItem.java140
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishModel.java64
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/RetractItem.java118
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SimplePayload.java130
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeExtension.java120
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeForm.java482
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeOptionFields.java198
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Subscription.java320
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionEvent.java150
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionsExtension.java192
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/UnsubscribeExtension.java146
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemDeleteListener.java82
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemEventListener.java72
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/NodeConfigListener.java70
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSub.java212
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSubNamespace.java126
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/SyncPacketSend.java126
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java74
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java76
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ConfigEventProvider.java84
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/EventProvider.java76
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java78
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java218
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemsProvider.java76
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java124
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/RetractEventProvider.java76
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SimpleNodeProvider.java74
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionProvider.java104
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionsProvider.java76
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/NodeUtils.java86
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/XmlUtils.java134
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceipt.java154
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java108
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/ReceiptReceivedListener.java50
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/MetaData.java134
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/QueueUser.java170
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitation.java268
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitationListener.java78
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Agent.java276
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java770
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRosterListener.java70
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentSession.java2368
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/InvitationRequest.java124
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Offer.java444
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmation.java228
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmationListener.java64
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferContent.java110
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferListener.java98
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/QueueUsersListener.java118
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/RevokedOffer.java194
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptManager.java200
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptSearchManager.java222
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TransferRequest.java124
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/UserRequest.java94
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/WorkgroupQueue.java446
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/forms/WorkgroupForm.java164
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java310
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatSession.java186
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/ChatMetadata.java232
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macro.java136
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/MacroGroup.java286
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macros.java394
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/notes/ChatNotes.java310
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentInfo.java264
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatus.java530
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatusRequest.java324
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentWorkgroups.java258
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/DepartQueuePacket.java148
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/MetaDataProvider.java96
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OccupantsInfo.java346
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRequestProvider.java422
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRevokeProvider.java224
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java396
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java318
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueUpdate.java242
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomInvitation.java354
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomTransfer.java354
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/SessionID.java154
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcript.java196
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptProvider.java132
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptSearch.java174
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcripts.java494
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptsProvider.java296
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/UserID.java154
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/WorkgroupInformation.java170
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSetting.java112
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSettings.java358
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/OfflineSettings.java310
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/SearchSettings.java224
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/QueueListener.java110
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/Workgroup.java1734
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ListenerEventDispatcher.java262
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java206
-rw-r--r--protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ModelUtil.java642
212 files changed, 32037 insertions, 32037 deletions
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/AbstractConnectionListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/AbstractConnectionListener.java
index 69acf9012..132da681e 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/AbstractConnectionListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/AbstractConnectionListener.java
@@ -1,46 +1,46 @@
-/**
- * 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;
-
-/**
- * The AbstractConnectionListener class provides an empty implementation for all
- * methods defined by the {@link ConnectionListener} interface. This is a
- * convenience class which should be used in case you do not need to implement
- * all methods.
- *
- * @author Henning Staib
- */
-public class AbstractConnectionListener implements ConnectionListener {
-
- public void connectionClosed() {
- // do nothing
- }
-
- public void connectionClosedOnError(Exception e) {
- // do nothing
- }
-
- public void reconnectingIn(int seconds) {
- // do nothing
- }
-
- public void reconnectionFailed(Exception e) {
- // do nothing
- }
-
- public void reconnectionSuccessful() {
- // do nothing
- }
-
-}
+/**
+ * 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;
+
+/**
+ * The AbstractConnectionListener class provides an empty implementation for all
+ * methods defined by the {@link ConnectionListener} interface. This is a
+ * convenience class which should be used in case you do not need to implement
+ * all methods.
+ *
+ * @author Henning Staib
+ */
+public class AbstractConnectionListener implements ConnectionListener {
+
+ public void connectionClosed() {
+ // do nothing
+ }
+
+ public void connectionClosedOnError(Exception e) {
+ // do nothing
+ }
+
+ public void reconnectingIn(int seconds) {
+ // do nothing
+ }
+
+ public void reconnectionFailed(Exception e) {
+ // do nothing
+ }
+
+ public void reconnectionSuccessful() {
+ // do nothing
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/NonSASLAuthentication.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/NonSASLAuthentication.java
index d7a479d1e..93511b731 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/NonSASLAuthentication.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/NonSASLAuthentication.java
@@ -1,143 +1,143 @@
-/**
- * $RCSfile$
- * $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
- *
- * 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;
-
-import org.jivesoftware.smack.filter.PacketIDFilter;
-import org.jivesoftware.smack.packet.Authentication;
-import org.jivesoftware.smack.packet.IQ;
-
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.Callback;
-
-/**
- * Implementation of JEP-0078: Non-SASL Authentication. Follow the following
- * <a href=http://www.jabber.org/jeps/jep-0078.html>link</a> to obtain more
- * information about the JEP.
- *
- * @author Gaston Dombiak
- */
-class NonSASLAuthentication implements UserAuthentication {
-
- private Connection connection;
-
- public NonSASLAuthentication(Connection connection) {
- super();
- this.connection = connection;
- }
-
- public String authenticate(String username, String resource, CallbackHandler cbh) throws XMPPException {
- //Use the callback handler to determine the password, and continue on.
- PasswordCallback pcb = new PasswordCallback("Password: ",false);
- try {
- cbh.handle(new Callback[]{pcb});
- return authenticate(username, String.valueOf(pcb.getPassword()),resource);
- } catch (Exception e) {
- throw new XMPPException("Unable to determine password.",e);
- }
- }
-
- public String authenticate(String username, String password, String resource) throws
- XMPPException {
- // If we send an authentication packet in "get" mode with just the username,
- // the server will return the list of authentication protocols it supports.
- Authentication discoveryAuth = new Authentication();
- discoveryAuth.setType(IQ.Type.GET);
- discoveryAuth.setUsername(username);
-
- PacketCollector collector =
- connection.createPacketCollector(new PacketIDFilter(discoveryAuth.getPacketID()));
- // Send the packet
- connection.sendPacket(discoveryAuth);
- // Wait up to a certain number of seconds for a response from the server.
- IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- if (response == null) {
- throw new XMPPException("No response from the server.");
- }
- // If the server replied with an error, throw an exception.
- else if (response.getType() == IQ.Type.ERROR) {
- throw new XMPPException(response.getError());
- }
- // Otherwise, no error so continue processing.
- Authentication authTypes = (Authentication) response;
- collector.cancel();
-
- // Now, create the authentication packet we'll send to the server.
- Authentication auth = new Authentication();
- auth.setUsername(username);
-
- // Figure out if we should use digest or plain text authentication.
- if (authTypes.getDigest() != null) {
- auth.setDigest(connection.getConnectionID(), password);
- }
- else if (authTypes.getPassword() != null) {
- auth.setPassword(password);
- }
- else {
- throw new XMPPException("Server does not support compatible authentication mechanism.");
- }
-
- auth.setResource(resource);
-
- collector = connection.createPacketCollector(new PacketIDFilter(auth.getPacketID()));
- // Send the packet.
- connection.sendPacket(auth);
- // Wait up to a certain number of seconds for a response from the server.
- response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- if (response == null) {
- throw new XMPPException("Authentication failed.");
- }
- else if (response.getType() == IQ.Type.ERROR) {
- throw new XMPPException(response.getError());
- }
- // We're done with the collector, so explicitly cancel it.
- collector.cancel();
-
- return response.getTo();
- }
-
- public String authenticateAnonymously() throws XMPPException {
- // Create the authentication packet we'll send to the server.
- Authentication auth = new Authentication();
-
- PacketCollector collector =
- connection.createPacketCollector(new PacketIDFilter(auth.getPacketID()));
- // Send the packet.
- connection.sendPacket(auth);
- // Wait up to a certain number of seconds for a response from the server.
- IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- if (response == null) {
- throw new XMPPException("Anonymous login failed.");
- }
- else if (response.getType() == IQ.Type.ERROR) {
- throw new XMPPException(response.getError());
- }
- // We're done with the collector, so explicitly cancel it.
- collector.cancel();
-
- if (response.getTo() != null) {
- return response.getTo();
- }
- else {
- return connection.getServiceName() + "/" + ((Authentication) response).getResource();
- }
- }
-}
+/**
+ * $RCSfile$
+ * $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
+ *
+ * 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;
+
+import org.jivesoftware.smack.filter.PacketIDFilter;
+import org.jivesoftware.smack.packet.Authentication;
+import org.jivesoftware.smack.packet.IQ;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.Callback;
+
+/**
+ * Implementation of JEP-0078: Non-SASL Authentication. Follow the following
+ * <a href=http://www.jabber.org/jeps/jep-0078.html>link</a> to obtain more
+ * information about the JEP.
+ *
+ * @author Gaston Dombiak
+ */
+class NonSASLAuthentication implements UserAuthentication {
+
+ private Connection connection;
+
+ public NonSASLAuthentication(Connection connection) {
+ super();
+ this.connection = connection;
+ }
+
+ public String authenticate(String username, String resource, CallbackHandler cbh) throws XMPPException {
+ //Use the callback handler to determine the password, and continue on.
+ PasswordCallback pcb = new PasswordCallback("Password: ",false);
+ try {
+ cbh.handle(new Callback[]{pcb});
+ return authenticate(username, String.valueOf(pcb.getPassword()),resource);
+ } catch (Exception e) {
+ throw new XMPPException("Unable to determine password.",e);
+ }
+ }
+
+ public String authenticate(String username, String password, String resource) throws
+ XMPPException {
+ // If we send an authentication packet in "get" mode with just the username,
+ // the server will return the list of authentication protocols it supports.
+ Authentication discoveryAuth = new Authentication();
+ discoveryAuth.setType(IQ.Type.GET);
+ discoveryAuth.setUsername(username);
+
+ PacketCollector collector =
+ connection.createPacketCollector(new PacketIDFilter(discoveryAuth.getPacketID()));
+ // Send the packet
+ connection.sendPacket(discoveryAuth);
+ // Wait up to a certain number of seconds for a response from the server.
+ IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ if (response == null) {
+ throw new XMPPException("No response from the server.");
+ }
+ // If the server replied with an error, throw an exception.
+ else if (response.getType() == IQ.Type.ERROR) {
+ throw new XMPPException(response.getError());
+ }
+ // Otherwise, no error so continue processing.
+ Authentication authTypes = (Authentication) response;
+ collector.cancel();
+
+ // Now, create the authentication packet we'll send to the server.
+ Authentication auth = new Authentication();
+ auth.setUsername(username);
+
+ // Figure out if we should use digest or plain text authentication.
+ if (authTypes.getDigest() != null) {
+ auth.setDigest(connection.getConnectionID(), password);
+ }
+ else if (authTypes.getPassword() != null) {
+ auth.setPassword(password);
+ }
+ else {
+ throw new XMPPException("Server does not support compatible authentication mechanism.");
+ }
+
+ auth.setResource(resource);
+
+ collector = connection.createPacketCollector(new PacketIDFilter(auth.getPacketID()));
+ // Send the packet.
+ connection.sendPacket(auth);
+ // Wait up to a certain number of seconds for a response from the server.
+ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ if (response == null) {
+ throw new XMPPException("Authentication failed.");
+ }
+ else if (response.getType() == IQ.Type.ERROR) {
+ throw new XMPPException(response.getError());
+ }
+ // We're done with the collector, so explicitly cancel it.
+ collector.cancel();
+
+ return response.getTo();
+ }
+
+ public String authenticateAnonymously() throws XMPPException {
+ // Create the authentication packet we'll send to the server.
+ Authentication auth = new Authentication();
+
+ PacketCollector collector =
+ connection.createPacketCollector(new PacketIDFilter(auth.getPacketID()));
+ // Send the packet.
+ connection.sendPacket(auth);
+ // Wait up to a certain number of seconds for a response from the server.
+ IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ if (response == null) {
+ throw new XMPPException("Anonymous login failed.");
+ }
+ else if (response.getType() == IQ.Type.ERROR) {
+ throw new XMPPException(response.getError());
+ }
+ // We're done with the collector, so explicitly cancel it.
+ collector.cancel();
+
+ if (response.getTo() != null) {
+ return response.getTo();
+ }
+ else {
+ return connection.getServiceName() + "/" + ((Authentication) response).getResource();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/OpenTrustManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/OpenTrustManager.java
index 61ed8c62a..2e47b1f16 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/OpenTrustManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/OpenTrustManager.java
@@ -1,49 +1,49 @@
-/**
- * $RCSfile$
- * $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
- *
- * 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;
-
-import javax.net.ssl.X509TrustManager;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-/**
- * Dummy trust manager that trust all certificates presented by the server. This class
- * is used during old SSL connections.
- *
- * @author Gaston Dombiak
- */
-class OpenTrustManager implements X509TrustManager {
-
- public OpenTrustManager() {
- }
-
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
-
- public void checkClientTrusted(X509Certificate[] arg0, String arg1)
- throws CertificateException {
- }
-
- public void checkServerTrusted(X509Certificate[] arg0, String arg1)
- throws CertificateException {
- }
+/**
+ * $RCSfile$
+ * $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
+ *
+ * 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;
+
+import javax.net.ssl.X509TrustManager;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * Dummy trust manager that trust all certificates presented by the server. This class
+ * is used during old SSL connections.
+ *
+ * @author Gaston Dombiak
+ */
+class OpenTrustManager implements X509TrustManager {
+
+ public OpenTrustManager() {
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+
+ public void checkClientTrusted(X509Certificate[] arg0, String arg1)
+ throws CertificateException {
+ }
+
+ public void checkServerTrusted(X509Certificate[] arg0, String arg1)
+ throws CertificateException {
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PacketInterceptor.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PacketInterceptor.java
index bd89031ec..af5632638 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PacketInterceptor.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PacketInterceptor.java
@@ -1,49 +1,49 @@
-/**
- * $Revision: 2408 $
- * $Date: 2004-11-02 20:53:30 -0300 (Tue, 02 Nov 2004) $
- *
- * Copyright 2003-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.
- * 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;
-
-import org.jivesoftware.smack.packet.Packet;
-
-/**
- * Provides a mechanism to intercept and modify packets that are going to be
- * sent to the server. PacketInterceptors are added to the {@link Connection}
- * together with a {@link org.jivesoftware.smack.filter.PacketFilter} so that only
- * certain packets are intercepted and processed by the interceptor.<p>
- *
- * This allows event-style programming -- every time a new packet is found,
- * the {@link #interceptPacket(Packet)} method will be called.
- *
- * @see Connection#addPacketInterceptor(PacketInterceptor, org.jivesoftware.smack.filter.PacketFilter)
- * @author Gaston Dombiak
- */
-public interface PacketInterceptor {
-
- /**
- * Process the packet that is about to be sent to the server. The intercepted
- * packet can be modified by the interceptor.<p>
- *
- * Interceptors are invoked using the same thread that requested the packet
- * to be sent, so it's very important that implementations of this method
- * not block for any extended period of time.
- *
- * @param packet the packet to is going to be sent to the server.
- */
- public void interceptPacket(Packet packet);
-}
+/**
+ * $Revision: 2408 $
+ * $Date: 2004-11-02 20:53:30 -0300 (Tue, 02 Nov 2004) $
+ *
+ * Copyright 2003-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.
+ * 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;
+
+import org.jivesoftware.smack.packet.Packet;
+
+/**
+ * Provides a mechanism to intercept and modify packets that are going to be
+ * sent to the server. PacketInterceptors are added to the {@link Connection}
+ * together with a {@link org.jivesoftware.smack.filter.PacketFilter} so that only
+ * certain packets are intercepted and processed by the interceptor.<p>
+ *
+ * This allows event-style programming -- every time a new packet is found,
+ * the {@link #interceptPacket(Packet)} method will be called.
+ *
+ * @see Connection#addPacketInterceptor(PacketInterceptor, org.jivesoftware.smack.filter.PacketFilter)
+ * @author Gaston Dombiak
+ */
+public interface PacketInterceptor {
+
+ /**
+ * Process the packet that is about to be sent to the server. The intercepted
+ * packet can be modified by the interceptor.<p>
+ *
+ * Interceptors are invoked using the same thread that requested the packet
+ * to be sent, so it's very important that implementations of this method
+ * not block for any extended period of time.
+ *
+ * @param packet the packet to is going to be sent to the server.
+ */
+ public void interceptPacket(Packet packet);
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyList.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyList.java
index 67d731db7..e2d9f5e0b 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyList.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyList.java
@@ -15,60 +15,60 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smack;
-
-import org.jivesoftware.smack.packet.PrivacyItem;
-
-import java.util.List;
-
-/**
- * A privacy list represents a list of contacts that is a read only class used to represent a set of allowed or blocked communications.
- * Basically it can:<ul>
- *
- * <li>Handle many {@link org.jivesoftware.smack.packet.PrivacyItem}.</li>
- * <li>Answer if it is the default list.</li>
- * <li>Answer if it is the active list.</li>
- * </ul>
- *
- * {@link PrivacyItem Privacy Items} can handle different kind of blocking communications based on JID, group,
- * subscription type or globally.
- *
- * @author Francisco Vives
- */
-public class PrivacyList {
-
- /** Holds if it is an active list or not **/
- private boolean isActiveList;
- /** Holds if it is an default list or not **/
- private boolean isDefaultList;
- /** Holds the list name used to print **/
- private String listName;
- /** Holds the list of {@see PrivacyItem} **/
- private List<PrivacyItem> items;
-
- protected PrivacyList(boolean isActiveList, boolean isDefaultList,
- String listName, List<PrivacyItem> privacyItems) {
- super();
- this.isActiveList = isActiveList;
- this.isDefaultList = isDefaultList;
- this.listName = listName;
- this.items = privacyItems;
- }
-
- public boolean isActiveList() {
- return isActiveList;
- }
-
- public boolean isDefaultList() {
- return isDefaultList;
- }
-
- public List<PrivacyItem> getItems() {
- return items;
- }
-
- public String toString() {
- return listName;
- }
-
-}
+package org.jivesoftware.smack;
+
+import org.jivesoftware.smack.packet.PrivacyItem;
+
+import java.util.List;
+
+/**
+ * A privacy list represents a list of contacts that is a read only class used to represent a set of allowed or blocked communications.
+ * Basically it can:<ul>
+ *
+ * <li>Handle many {@link org.jivesoftware.smack.packet.PrivacyItem}.</li>
+ * <li>Answer if it is the default list.</li>
+ * <li>Answer if it is the active list.</li>
+ * </ul>
+ *
+ * {@link PrivacyItem Privacy Items} can handle different kind of blocking communications based on JID, group,
+ * subscription type or globally.
+ *
+ * @author Francisco Vives
+ */
+public class PrivacyList {
+
+ /** Holds if it is an active list or not **/
+ private boolean isActiveList;
+ /** Holds if it is an default list or not **/
+ private boolean isDefaultList;
+ /** Holds the list name used to print **/
+ private String listName;
+ /** Holds the list of {@see PrivacyItem} **/
+ private List<PrivacyItem> items;
+
+ protected PrivacyList(boolean isActiveList, boolean isDefaultList,
+ String listName, List<PrivacyItem> privacyItems) {
+ super();
+ this.isActiveList = isActiveList;
+ this.isDefaultList = isDefaultList;
+ this.listName = listName;
+ this.items = privacyItems;
+ }
+
+ public boolean isActiveList() {
+ return isActiveList;
+ }
+
+ public boolean isDefaultList() {
+ return isDefaultList;
+ }
+
+ public List<PrivacyItem> getItems() {
+ return items;
+ }
+
+ public String toString() {
+ return listName;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListListener.java
index 5644ed7e2..20683f8a7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListListener.java
@@ -1,51 +1,51 @@
-/**
- * $Revision$
- * $Date$
- *
- * Copyright 2006-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
- *
- * 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;
-
-import org.jivesoftware.smack.packet.PrivacyItem;
-
-import java.util.List;
-
-/**
- * Interface to implement classes to listen for server events about privacy communication.
- * Listeners are registered with the {@link PrivacyListManager}.
- *
- * @see PrivacyListManager#addListener
- *
- * @author Francisco Vives
- */
-public interface PrivacyListListener {
-
- /**
- * Set or update a privacy list with PrivacyItem.
- *
- * @param listName the name of the new or updated privacy list.
- * @param listItem the PrivacyItems that rules the list.
- */
- public void setPrivacyList(String listName, List<PrivacyItem> listItem);
-
- /**
- * A privacy list has been modified by another. It gets notified.
- *
- * @param listName the name of the updated privacy list.
- */
- public void updatedPrivacyList(String listName);
-
+/**
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2006-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
+ *
+ * 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;
+
+import org.jivesoftware.smack.packet.PrivacyItem;
+
+import java.util.List;
+
+/**
+ * Interface to implement classes to listen for server events about privacy communication.
+ * Listeners are registered with the {@link PrivacyListManager}.
+ *
+ * @see PrivacyListManager#addListener
+ *
+ * @author Francisco Vives
+ */
+public interface PrivacyListListener {
+
+ /**
+ * Set or update a privacy list with PrivacyItem.
+ *
+ * @param listName the name of the new or updated privacy list.
+ * @param listItem the PrivacyItems that rules the list.
+ */
+ public void setPrivacyList(String listName, List<PrivacyItem> listItem);
+
+ /**
+ * A privacy list has been modified by another. It gets notified.
+ *
+ * @param listName the name of the updated privacy list.
+ */
+ public void updatedPrivacyList(String listName);
+
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListManager.java
index eb1d231d2..77b066a50 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/PrivacyListManager.java
@@ -1,466 +1,466 @@
-/**
- * $Revision$
- * $Date$
- *
- * Copyright 2006-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
- *
- * 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;
-
-import org.jivesoftware.smack.filter.*;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.Privacy;
-import org.jivesoftware.smack.packet.PrivacyItem;
-
-import java.util.*;
-
-/**
- * A PrivacyListManager is used by XMPP clients to block or allow communications from other
- * users. Use the manager to: <ul>
- * <li>Retrieve privacy lists.
- * <li>Add, remove, and edit privacy lists.
- * <li>Set, change, or decline active lists.
- * <li>Set, change, or decline the default list (i.e., the list that is active by default).
- * </ul>
- * Privacy Items can handle different kind of permission communications based on JID, group,
- * subscription type or globally (@see PrivacyItem).
- *
- * @author Francisco Vives
- */
-public class PrivacyListManager {
-
- // Keep the list of instances of this class.
- private static Map<Connection, PrivacyListManager> instances = new Hashtable<Connection, PrivacyListManager>();
-
- private Connection connection;
- private final List<PrivacyListListener> listeners = new ArrayList<PrivacyListListener>();
- PacketFilter packetFilter = new AndFilter(new IQTypeFilter(IQ.Type.SET),
- new PacketExtensionFilter("query", "jabber:iq:privacy"));
-
- static {
- // Create a new PrivacyListManager on every established connection. In the init()
- // method of PrivacyListManager, we'll add a listener that will delete the
- // instance when the connection is closed.
- Connection.addConnectionCreationListener(new ConnectionCreationListener() {
- public void connectionCreated(Connection connection) {
- new PrivacyListManager(connection);
- }
- });
- }
- /**
- * Creates a new privacy manager to maintain the communication privacy. Note: no
- * information is sent to or received from the server until you attempt to
- * get or set the privacy communication.<p>
- *
- * @param connection the XMPP connection.
- */
- private PrivacyListManager(Connection connection) {
- this.connection = connection;
- this.init();
- }
-
- /** Answer the connection userJID that owns the privacy.
- * @return the userJID that owns the privacy
- */
- private String getUser() {
- return connection.getUser();
- }
-
- /**
- * Initializes the packet listeners of the connection that will notify for any set privacy
- * package.
- */
- private void init() {
- // Register the new instance and associate it with the connection
- instances.put(connection, this);
- // Add a listener to the connection that removes the registered instance when
- // the connection is closed
- connection.addConnectionListener(new ConnectionListener() {
- public void connectionClosed() {
- // Unregister this instance since the connection has been closed
- instances.remove(connection);
- }
-
- public void connectionClosedOnError(Exception e) {
- // ignore
- }
-
- public void reconnectionFailed(Exception e) {
- // ignore
- }
-
- public void reconnectingIn(int seconds) {
- // ignore
- }
-
- public void reconnectionSuccessful() {
- // ignore
- }
- });
-
- connection.addPacketListener(new PacketListener() {
- public void processPacket(Packet packet) {
-
- if (packet == null || packet.getError() != null) {
- return;
- }
- // The packet is correct.
- Privacy privacy = (Privacy) packet;
-
- // Notifies the event to the listeners.
- synchronized (listeners) {
- for (PrivacyListListener listener : listeners) {
- // Notifies the created or updated privacy lists
- for (Map.Entry<String,List<PrivacyItem>> entry : privacy.getItemLists().entrySet()) {
- String listName = entry.getKey();
- List<PrivacyItem> items = entry.getValue();
- if (items.isEmpty()) {
- listener.updatedPrivacyList(listName);
- } else {
- listener.setPrivacyList(listName, items);
- }
- }
- }
- }
-
- // Send a result package acknowledging the reception of a privacy package.
-
- // Prepare the IQ packet to send
- IQ iq = new IQ() {
- public String getChildElementXML() {
- return "";
- }
- };
- iq.setType(IQ.Type.RESULT);
- iq.setFrom(packet.getFrom());
- iq.setPacketID(packet.getPacketID());
-
- // Send create & join packet.
- connection.sendPacket(iq);
- }
- }, packetFilter);
- }
-
- /**
- * Returns the PrivacyListManager instance associated with a given Connection.
- *
- * @param connection the connection used to look for the proper PrivacyListManager.
- * @return the PrivacyListManager associated with a given Connection.
- */
- public static PrivacyListManager getInstanceFor(Connection connection) {
- return instances.get(connection);
- }
-
- /**
- * Send the {@link Privacy} packet to the server in order to know some privacy content and then
- * waits for the answer.
- *
- * @param requestPrivacy is the {@link Privacy} packet configured properly whose XML
- * will be sent to the server.
- * @return a new {@link Privacy} with the data received from the server.
- * @exception XMPPException if the request or the answer failed, it raises an exception.
- */
- private Privacy getRequest(Privacy requestPrivacy) throws XMPPException {
- // The request is a get iq type
- requestPrivacy.setType(Privacy.Type.GET);
- requestPrivacy.setFrom(this.getUser());
-
- // Filter packets looking for an answer from the server.
- PacketFilter responseFilter = new PacketIDFilter(requestPrivacy.getPacketID());
- PacketCollector response = connection.createPacketCollector(responseFilter);
-
- // Send create & join packet.
- connection.sendPacket(requestPrivacy);
-
- // Wait up to a certain number of seconds for a reply.
- Privacy privacyAnswer =
- (Privacy) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Stop queuing results
- response.cancel();
-
- // Interprete the result and answer the privacy only if it is valid
- if (privacyAnswer == null) {
- throw new XMPPException("No response from server.");
- }
- else if (privacyAnswer.getError() != null) {
- throw new XMPPException(privacyAnswer.getError());
- }
- return privacyAnswer;
- }
-
- /**
- * Send the {@link Privacy} packet to the server in order to modify the server privacy and
- * waits for the answer.
- *
- * @param requestPrivacy is the {@link Privacy} packet configured properly whose xml will be sent
- * to the server.
- * @return a new {@link Privacy} with the data received from the server.
- * @exception XMPPException if the request or the answer failed, it raises an exception.
- */
- private Packet setRequest(Privacy requestPrivacy) throws XMPPException {
-
- // The request is a get iq type
- requestPrivacy.setType(Privacy.Type.SET);
- requestPrivacy.setFrom(this.getUser());
-
- // Filter packets looking for an answer from the server.
- PacketFilter responseFilter = new PacketIDFilter(requestPrivacy.getPacketID());
- PacketCollector response = connection.createPacketCollector(responseFilter);
-
- // Send create & join packet.
- connection.sendPacket(requestPrivacy);
-
- // Wait up to a certain number of seconds for a reply.
- Packet privacyAnswer = response.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Stop queuing results
- response.cancel();
-
- // Interprete the result and answer the privacy only if it is valid
- if (privacyAnswer == null) {
- throw new XMPPException("No response from server.");
- } else if (privacyAnswer.getError() != null) {
- throw new XMPPException(privacyAnswer.getError());
- }
- return privacyAnswer;
- }
-
- /**
- * Answer a privacy containing the list structre without {@link PrivacyItem}.
- *
- * @return a Privacy with the list names.
- * @throws XMPPException if an error occurs.
- */
- private Privacy getPrivacyWithListNames() throws XMPPException {
-
- // The request of the list is an empty privacy message
- Privacy request = new Privacy();
-
- // Send the package to the server and get the answer
- return getRequest(request);
- }
-
- /**
- * Answer the active privacy list.
- *
- * @return the privacy list of the active list.
- * @throws XMPPException if an error occurs.
- */
- public PrivacyList getActiveList() throws XMPPException {
- Privacy privacyAnswer = this.getPrivacyWithListNames();
- String listName = privacyAnswer.getActiveName();
- boolean isDefaultAndActive = privacyAnswer.getActiveName() != null
- && privacyAnswer.getDefaultName() != null
- && privacyAnswer.getActiveName().equals(
- privacyAnswer.getDefaultName());
- return new PrivacyList(true, isDefaultAndActive, listName, getPrivacyListItems(listName));
- }
-
- /**
- * Answer the default privacy list.
- *
- * @return the privacy list of the default list.
- * @throws XMPPException if an error occurs.
- */
- public PrivacyList getDefaultList() throws XMPPException {
- Privacy privacyAnswer = this.getPrivacyWithListNames();
- String listName = privacyAnswer.getDefaultName();
- boolean isDefaultAndActive = privacyAnswer.getActiveName() != null
- && privacyAnswer.getDefaultName() != null
- && privacyAnswer.getActiveName().equals(
- privacyAnswer.getDefaultName());
- return new PrivacyList(isDefaultAndActive, true, listName, getPrivacyListItems(listName));
- }
-
- /**
- * Answer the privacy list items under listName with the allowed and blocked permissions.
- *
- * @param listName the name of the list to get the allowed and blocked permissions.
- * @return a list of privacy items under the list listName.
- * @throws XMPPException if an error occurs.
- */
- private List<PrivacyItem> getPrivacyListItems(String listName) throws XMPPException {
-
- // The request of the list is an privacy message with an empty list
- Privacy request = new Privacy();
- request.setPrivacyList(listName, new ArrayList<PrivacyItem>());
-
- // Send the package to the server and get the answer
- Privacy privacyAnswer = getRequest(request);
-
- return privacyAnswer.getPrivacyList(listName);
- }
-
- /**
- * Answer the privacy list items under listName with the allowed and blocked permissions.
- *
- * @param listName the name of the list to get the allowed and blocked permissions.
- * @return a privacy list under the list listName.
- * @throws XMPPException if an error occurs.
- */
- public PrivacyList getPrivacyList(String listName) throws XMPPException {
-
- return new PrivacyList(false, false, listName, getPrivacyListItems(listName));
- }
-
- /**
- * Answer every privacy list with the allowed and blocked permissions.
- *
- * @return an array of privacy lists.
- * @throws XMPPException if an error occurs.
- */
- public PrivacyList[] getPrivacyLists() throws XMPPException {
- Privacy privacyAnswer = this.getPrivacyWithListNames();
- Set<String> names = privacyAnswer.getPrivacyListNames();
- PrivacyList[] lists = new PrivacyList[names.size()];
- boolean isActiveList;
- boolean isDefaultList;
- int index=0;
- for (String listName : names) {
- isActiveList = listName.equals(privacyAnswer.getActiveName());
- isDefaultList = listName.equals(privacyAnswer.getDefaultName());
- lists[index] = new PrivacyList(isActiveList, isDefaultList,
- listName, getPrivacyListItems(listName));
- index = index + 1;
- }
- return lists;
- }
-
-
- /**
- * Set or change the active list to listName.
- *
- * @param listName the list name to set as the active one.
- * @exception XMPPException if the request or the answer failed, it raises an exception.
- */
- public void setActiveListName(String listName) throws XMPPException {
-
- // The request of the list is an privacy message with an empty list
- Privacy request = new Privacy();
- request.setActiveName(listName);
-
- // Send the package to the server
- setRequest(request);
- }
-
- /**
- * Client declines the use of active lists.
- *
- * @throws XMPPException if an error occurs.
- */
- public void declineActiveList() throws XMPPException {
-
- // The request of the list is an privacy message with an empty list
- Privacy request = new Privacy();
- request.setDeclineActiveList(true);
-
- // Send the package to the server
- setRequest(request);
- }
-
- /**
- * Set or change the default list to listName.
- *
- * @param listName the list name to set as the default one.
- * @exception XMPPException if the request or the answer failed, it raises an exception.
- */
- public void setDefaultListName(String listName) throws XMPPException {
-
- // The request of the list is an privacy message with an empty list
- Privacy request = new Privacy();
- request.setDefaultName(listName);
-
- // Send the package to the server
- setRequest(request);
- }
-
- /**
- * Client declines the use of default lists.
- *
- * @throws XMPPException if an error occurs.
- */
- public void declineDefaultList() throws XMPPException {
-
- // The request of the list is an privacy message with an empty list
- Privacy request = new Privacy();
- request.setDeclineDefaultList(true);
-
- // Send the package to the server
- setRequest(request);
- }
-
- /**
- * The client has created a new list. It send the new one to the server.
- *
- * @param listName the list that has changed its content.
- * @param privacyItems a List with every privacy item in the list.
- * @throws XMPPException if an error occurs.
- */
- public void createPrivacyList(String listName, List<PrivacyItem> privacyItems) throws XMPPException {
-
- this.updatePrivacyList(listName, privacyItems);
- }
-
- /**
- * The client has edited an existing list. It updates the server content with the resulting
- * list of privacy items. The {@link PrivacyItem} list MUST contain all elements in the
- * list (not the "delta").
- *
- * @param listName the list that has changed its content.
- * @param privacyItems a List with every privacy item in the list.
- * @throws XMPPException if an error occurs.
- */
- public void updatePrivacyList(String listName, List<PrivacyItem> privacyItems) throws XMPPException {
-
- // Build the privacy package to add or update the new list
- Privacy request = new Privacy();
- request.setPrivacyList(listName, privacyItems);
-
- // Send the package to the server
- setRequest(request);
- }
-
- /**
- * Remove a privacy list.
- *
- * @param listName the list that has changed its content.
- * @throws XMPPException if an error occurs.
- */
- public void deletePrivacyList(String listName) throws XMPPException {
-
- // The request of the list is an privacy message with an empty list
- Privacy request = new Privacy();
- request.setPrivacyList(listName, new ArrayList<PrivacyItem>());
-
- // Send the package to the server
- setRequest(request);
- }
-
- /**
- * Adds a packet listener that will be notified of any new update in the user
- * privacy communication.
- *
- * @param listener a packet listener.
- */
- public void addListener(PrivacyListListener listener) {
- // Keep track of the listener so that we can manually deliver extra
- // messages to it later if needed.
- synchronized (listeners) {
- listeners.add(listener);
- }
- }
-}
+/**
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2006-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
+ *
+ * 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;
+
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.Privacy;
+import org.jivesoftware.smack.packet.PrivacyItem;
+
+import java.util.*;
+
+/**
+ * A PrivacyListManager is used by XMPP clients to block or allow communications from other
+ * users. Use the manager to: <ul>
+ * <li>Retrieve privacy lists.
+ * <li>Add, remove, and edit privacy lists.
+ * <li>Set, change, or decline active lists.
+ * <li>Set, change, or decline the default list (i.e., the list that is active by default).
+ * </ul>
+ * Privacy Items can handle different kind of permission communications based on JID, group,
+ * subscription type or globally (@see PrivacyItem).
+ *
+ * @author Francisco Vives
+ */
+public class PrivacyListManager {
+
+ // Keep the list of instances of this class.
+ private static Map<Connection, PrivacyListManager> instances = new Hashtable<Connection, PrivacyListManager>();
+
+ private Connection connection;
+ private final List<PrivacyListListener> listeners = new ArrayList<PrivacyListListener>();
+ PacketFilter packetFilter = new AndFilter(new IQTypeFilter(IQ.Type.SET),
+ new PacketExtensionFilter("query", "jabber:iq:privacy"));
+
+ static {
+ // Create a new PrivacyListManager on every established connection. In the init()
+ // method of PrivacyListManager, we'll add a listener that will delete the
+ // instance when the connection is closed.
+ Connection.addConnectionCreationListener(new ConnectionCreationListener() {
+ public void connectionCreated(Connection connection) {
+ new PrivacyListManager(connection);
+ }
+ });
+ }
+ /**
+ * Creates a new privacy manager to maintain the communication privacy. Note: no
+ * information is sent to or received from the server until you attempt to
+ * get or set the privacy communication.<p>
+ *
+ * @param connection the XMPP connection.
+ */
+ private PrivacyListManager(Connection connection) {
+ this.connection = connection;
+ this.init();
+ }
+
+ /** Answer the connection userJID that owns the privacy.
+ * @return the userJID that owns the privacy
+ */
+ private String getUser() {
+ return connection.getUser();
+ }
+
+ /**
+ * Initializes the packet listeners of the connection that will notify for any set privacy
+ * package.
+ */
+ private void init() {
+ // Register the new instance and associate it with the connection
+ instances.put(connection, this);
+ // Add a listener to the connection that removes the registered instance when
+ // the connection is closed
+ connection.addConnectionListener(new ConnectionListener() {
+ public void connectionClosed() {
+ // Unregister this instance since the connection has been closed
+ instances.remove(connection);
+ }
+
+ public void connectionClosedOnError(Exception e) {
+ // ignore
+ }
+
+ public void reconnectionFailed(Exception e) {
+ // ignore
+ }
+
+ public void reconnectingIn(int seconds) {
+ // ignore
+ }
+
+ public void reconnectionSuccessful() {
+ // ignore
+ }
+ });
+
+ connection.addPacketListener(new PacketListener() {
+ public void processPacket(Packet packet) {
+
+ if (packet == null || packet.getError() != null) {
+ return;
+ }
+ // The packet is correct.
+ Privacy privacy = (Privacy) packet;
+
+ // Notifies the event to the listeners.
+ synchronized (listeners) {
+ for (PrivacyListListener listener : listeners) {
+ // Notifies the created or updated privacy lists
+ for (Map.Entry<String,List<PrivacyItem>> entry : privacy.getItemLists().entrySet()) {
+ String listName = entry.getKey();
+ List<PrivacyItem> items = entry.getValue();
+ if (items.isEmpty()) {
+ listener.updatedPrivacyList(listName);
+ } else {
+ listener.setPrivacyList(listName, items);
+ }
+ }
+ }
+ }
+
+ // Send a result package acknowledging the reception of a privacy package.
+
+ // Prepare the IQ packet to send
+ IQ iq = new IQ() {
+ public String getChildElementXML() {
+ return "";
+ }
+ };
+ iq.setType(IQ.Type.RESULT);
+ iq.setFrom(packet.getFrom());
+ iq.setPacketID(packet.getPacketID());
+
+ // Send create & join packet.
+ connection.sendPacket(iq);
+ }
+ }, packetFilter);
+ }
+
+ /**
+ * Returns the PrivacyListManager instance associated with a given Connection.
+ *
+ * @param connection the connection used to look for the proper PrivacyListManager.
+ * @return the PrivacyListManager associated with a given Connection.
+ */
+ public static PrivacyListManager getInstanceFor(Connection connection) {
+ return instances.get(connection);
+ }
+
+ /**
+ * Send the {@link Privacy} packet to the server in order to know some privacy content and then
+ * waits for the answer.
+ *
+ * @param requestPrivacy is the {@link Privacy} packet configured properly whose XML
+ * will be sent to the server.
+ * @return a new {@link Privacy} with the data received from the server.
+ * @exception XMPPException if the request or the answer failed, it raises an exception.
+ */
+ private Privacy getRequest(Privacy requestPrivacy) throws XMPPException {
+ // The request is a get iq type
+ requestPrivacy.setType(Privacy.Type.GET);
+ requestPrivacy.setFrom(this.getUser());
+
+ // Filter packets looking for an answer from the server.
+ PacketFilter responseFilter = new PacketIDFilter(requestPrivacy.getPacketID());
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+
+ // Send create & join packet.
+ connection.sendPacket(requestPrivacy);
+
+ // Wait up to a certain number of seconds for a reply.
+ Privacy privacyAnswer =
+ (Privacy) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Stop queuing results
+ response.cancel();
+
+ // Interprete the result and answer the privacy only if it is valid
+ if (privacyAnswer == null) {
+ throw new XMPPException("No response from server.");
+ }
+ else if (privacyAnswer.getError() != null) {
+ throw new XMPPException(privacyAnswer.getError());
+ }
+ return privacyAnswer;
+ }
+
+ /**
+ * Send the {@link Privacy} packet to the server in order to modify the server privacy and
+ * waits for the answer.
+ *
+ * @param requestPrivacy is the {@link Privacy} packet configured properly whose xml will be sent
+ * to the server.
+ * @return a new {@link Privacy} with the data received from the server.
+ * @exception XMPPException if the request or the answer failed, it raises an exception.
+ */
+ private Packet setRequest(Privacy requestPrivacy) throws XMPPException {
+
+ // The request is a get iq type
+ requestPrivacy.setType(Privacy.Type.SET);
+ requestPrivacy.setFrom(this.getUser());
+
+ // Filter packets looking for an answer from the server.
+ PacketFilter responseFilter = new PacketIDFilter(requestPrivacy.getPacketID());
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+
+ // Send create & join packet.
+ connection.sendPacket(requestPrivacy);
+
+ // Wait up to a certain number of seconds for a reply.
+ Packet privacyAnswer = response.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Stop queuing results
+ response.cancel();
+
+ // Interprete the result and answer the privacy only if it is valid
+ if (privacyAnswer == null) {
+ throw new XMPPException("No response from server.");
+ } else if (privacyAnswer.getError() != null) {
+ throw new XMPPException(privacyAnswer.getError());
+ }
+ return privacyAnswer;
+ }
+
+ /**
+ * Answer a privacy containing the list structre without {@link PrivacyItem}.
+ *
+ * @return a Privacy with the list names.
+ * @throws XMPPException if an error occurs.
+ */
+ private Privacy getPrivacyWithListNames() throws XMPPException {
+
+ // The request of the list is an empty privacy message
+ Privacy request = new Privacy();
+
+ // Send the package to the server and get the answer
+ return getRequest(request);
+ }
+
+ /**
+ * Answer the active privacy list.
+ *
+ * @return the privacy list of the active list.
+ * @throws XMPPException if an error occurs.
+ */
+ public PrivacyList getActiveList() throws XMPPException {
+ Privacy privacyAnswer = this.getPrivacyWithListNames();
+ String listName = privacyAnswer.getActiveName();
+ boolean isDefaultAndActive = privacyAnswer.getActiveName() != null
+ && privacyAnswer.getDefaultName() != null
+ && privacyAnswer.getActiveName().equals(
+ privacyAnswer.getDefaultName());
+ return new PrivacyList(true, isDefaultAndActive, listName, getPrivacyListItems(listName));
+ }
+
+ /**
+ * Answer the default privacy list.
+ *
+ * @return the privacy list of the default list.
+ * @throws XMPPException if an error occurs.
+ */
+ public PrivacyList getDefaultList() throws XMPPException {
+ Privacy privacyAnswer = this.getPrivacyWithListNames();
+ String listName = privacyAnswer.getDefaultName();
+ boolean isDefaultAndActive = privacyAnswer.getActiveName() != null
+ && privacyAnswer.getDefaultName() != null
+ && privacyAnswer.getActiveName().equals(
+ privacyAnswer.getDefaultName());
+ return new PrivacyList(isDefaultAndActive, true, listName, getPrivacyListItems(listName));
+ }
+
+ /**
+ * Answer the privacy list items under listName with the allowed and blocked permissions.
+ *
+ * @param listName the name of the list to get the allowed and blocked permissions.
+ * @return a list of privacy items under the list listName.
+ * @throws XMPPException if an error occurs.
+ */
+ private List<PrivacyItem> getPrivacyListItems(String listName) throws XMPPException {
+
+ // The request of the list is an privacy message with an empty list
+ Privacy request = new Privacy();
+ request.setPrivacyList(listName, new ArrayList<PrivacyItem>());
+
+ // Send the package to the server and get the answer
+ Privacy privacyAnswer = getRequest(request);
+
+ return privacyAnswer.getPrivacyList(listName);
+ }
+
+ /**
+ * Answer the privacy list items under listName with the allowed and blocked permissions.
+ *
+ * @param listName the name of the list to get the allowed and blocked permissions.
+ * @return a privacy list under the list listName.
+ * @throws XMPPException if an error occurs.
+ */
+ public PrivacyList getPrivacyList(String listName) throws XMPPException {
+
+ return new PrivacyList(false, false, listName, getPrivacyListItems(listName));
+ }
+
+ /**
+ * Answer every privacy list with the allowed and blocked permissions.
+ *
+ * @return an array of privacy lists.
+ * @throws XMPPException if an error occurs.
+ */
+ public PrivacyList[] getPrivacyLists() throws XMPPException {
+ Privacy privacyAnswer = this.getPrivacyWithListNames();
+ Set<String> names = privacyAnswer.getPrivacyListNames();
+ PrivacyList[] lists = new PrivacyList[names.size()];
+ boolean isActiveList;
+ boolean isDefaultList;
+ int index=0;
+ for (String listName : names) {
+ isActiveList = listName.equals(privacyAnswer.getActiveName());
+ isDefaultList = listName.equals(privacyAnswer.getDefaultName());
+ lists[index] = new PrivacyList(isActiveList, isDefaultList,
+ listName, getPrivacyListItems(listName));
+ index = index + 1;
+ }
+ return lists;
+ }
+
+
+ /**
+ * Set or change the active list to listName.
+ *
+ * @param listName the list name to set as the active one.
+ * @exception XMPPException if the request or the answer failed, it raises an exception.
+ */
+ public void setActiveListName(String listName) throws XMPPException {
+
+ // The request of the list is an privacy message with an empty list
+ Privacy request = new Privacy();
+ request.setActiveName(listName);
+
+ // Send the package to the server
+ setRequest(request);
+ }
+
+ /**
+ * Client declines the use of active lists.
+ *
+ * @throws XMPPException if an error occurs.
+ */
+ public void declineActiveList() throws XMPPException {
+
+ // The request of the list is an privacy message with an empty list
+ Privacy request = new Privacy();
+ request.setDeclineActiveList(true);
+
+ // Send the package to the server
+ setRequest(request);
+ }
+
+ /**
+ * Set or change the default list to listName.
+ *
+ * @param listName the list name to set as the default one.
+ * @exception XMPPException if the request or the answer failed, it raises an exception.
+ */
+ public void setDefaultListName(String listName) throws XMPPException {
+
+ // The request of the list is an privacy message with an empty list
+ Privacy request = new Privacy();
+ request.setDefaultName(listName);
+
+ // Send the package to the server
+ setRequest(request);
+ }
+
+ /**
+ * Client declines the use of default lists.
+ *
+ * @throws XMPPException if an error occurs.
+ */
+ public void declineDefaultList() throws XMPPException {
+
+ // The request of the list is an privacy message with an empty list
+ Privacy request = new Privacy();
+ request.setDeclineDefaultList(true);
+
+ // Send the package to the server
+ setRequest(request);
+ }
+
+ /**
+ * The client has created a new list. It send the new one to the server.
+ *
+ * @param listName the list that has changed its content.
+ * @param privacyItems a List with every privacy item in the list.
+ * @throws XMPPException if an error occurs.
+ */
+ public void createPrivacyList(String listName, List<PrivacyItem> privacyItems) throws XMPPException {
+
+ this.updatePrivacyList(listName, privacyItems);
+ }
+
+ /**
+ * The client has edited an existing list. It updates the server content with the resulting
+ * list of privacy items. The {@link PrivacyItem} list MUST contain all elements in the
+ * list (not the "delta").
+ *
+ * @param listName the list that has changed its content.
+ * @param privacyItems a List with every privacy item in the list.
+ * @throws XMPPException if an error occurs.
+ */
+ public void updatePrivacyList(String listName, List<PrivacyItem> privacyItems) throws XMPPException {
+
+ // Build the privacy package to add or update the new list
+ Privacy request = new Privacy();
+ request.setPrivacyList(listName, privacyItems);
+
+ // Send the package to the server
+ setRequest(request);
+ }
+
+ /**
+ * Remove a privacy list.
+ *
+ * @param listName the list that has changed its content.
+ * @throws XMPPException if an error occurs.
+ */
+ public void deletePrivacyList(String listName) throws XMPPException {
+
+ // The request of the list is an privacy message with an empty list
+ Privacy request = new Privacy();
+ request.setPrivacyList(listName, new ArrayList<PrivacyItem>());
+
+ // Send the package to the server
+ setRequest(request);
+ }
+
+ /**
+ * Adds a packet listener that will be notified of any new update in the user
+ * privacy communication.
+ *
+ * @param listener a packet listener.
+ */
+ public void addListener(PrivacyListListener listener) {
+ // Keep track of the listener so that we can manually deliver extra
+ // messages to it later if needed.
+ synchronized (listeners) {
+ listeners.add(listener);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/ReconnectionManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/ReconnectionManager.java
index cc3e3af19..7e3c1dea3 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/ReconnectionManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/ReconnectionManager.java
@@ -15,213 +15,213 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smack;
-
-import org.jivesoftware.smack.packet.StreamError;
-import java.util.Random;
-/**
- * Handles the automatic reconnection process. Every time a connection is dropped without
- * the application explictly closing it, the manager automatically tries to reconnect to
- * the server.<p>
- *
- * The reconnection mechanism will try to reconnect periodically:
- * <ol>
- * <li>For the first minute it will attempt to connect once every ten seconds.
- * <li>For the next five minutes it will attempt to connect once a minute.
- * <li>If that fails it will indefinitely try to connect once every five minutes.
- * </ol>
- *
- * @author Francisco Vives
- */
-public class ReconnectionManager implements ConnectionListener {
-
- // Holds the connection to the server
- private Connection connection;
- private Thread reconnectionThread;
- private int randomBase = new Random().nextInt(11) + 5; // between 5 and 15 seconds
-
- // Holds the state of the reconnection
- boolean done = false;
-
- static {
- // Create a new PrivacyListManager on every established connection. In the init()
- // method of PrivacyListManager, we'll add a listener that will delete the
- // instance when the connection is closed.
- Connection.addConnectionCreationListener(new ConnectionCreationListener() {
- public void connectionCreated(Connection connection) {
- connection.addConnectionListener(new ReconnectionManager(connection));
- }
- });
- }
-
- private ReconnectionManager(Connection connection) {
- this.connection = connection;
- }
-
-
- /**
- * Returns true if the reconnection mechanism is enabled.
- *
- * @return true if automatic reconnections are allowed.
- */
- private boolean isReconnectionAllowed() {
+package org.jivesoftware.smack;
+
+import org.jivesoftware.smack.packet.StreamError;
+import java.util.Random;
+/**
+ * Handles the automatic reconnection process. Every time a connection is dropped without
+ * the application explictly closing it, the manager automatically tries to reconnect to
+ * the server.<p>
+ *
+ * The reconnection mechanism will try to reconnect periodically:
+ * <ol>
+ * <li>For the first minute it will attempt to connect once every ten seconds.
+ * <li>For the next five minutes it will attempt to connect once a minute.
+ * <li>If that fails it will indefinitely try to connect once every five minutes.
+ * </ol>
+ *
+ * @author Francisco Vives
+ */
+public class ReconnectionManager implements ConnectionListener {
+
+ // Holds the connection to the server
+ private Connection connection;
+ private Thread reconnectionThread;
+ private int randomBase = new Random().nextInt(11) + 5; // between 5 and 15 seconds
+
+ // Holds the state of the reconnection
+ boolean done = false;
+
+ static {
+ // Create a new PrivacyListManager on every established connection. In the init()
+ // method of PrivacyListManager, we'll add a listener that will delete the
+ // instance when the connection is closed.
+ Connection.addConnectionCreationListener(new ConnectionCreationListener() {
+ public void connectionCreated(Connection connection) {
+ connection.addConnectionListener(new ReconnectionManager(connection));
+ }
+ });
+ }
+
+ private ReconnectionManager(Connection connection) {
+ this.connection = connection;
+ }
+
+
+ /**
+ * Returns true if the reconnection mechanism is enabled.
+ *
+ * @return true if automatic reconnections are allowed.
+ */
+ private boolean isReconnectionAllowed() {
return !done && !connection.isConnected()
&& connection.isReconnectionAllowed();
- }
-
- /**
- * Starts a reconnection mechanism if it was configured to do that.
- * The algorithm is been executed when the first connection error is detected.
- * <p/>
- * The reconnection mechanism will try to reconnect periodically in this way:
- * <ol>
- * <li>First it will try 6 times every 10 seconds.
- * <li>Then it will try 10 times every 1 minute.
- * <li>Finally it will try indefinitely every 5 minutes.
- * </ol>
- */
- synchronized protected void reconnect() {
- if (this.isReconnectionAllowed()) {
- // Since there is no thread running, creates a new one to attempt
- // the reconnection.
- // avoid to run duplicated reconnectionThread -- fd: 16/09/2010
- if (reconnectionThread!=null && reconnectionThread.isAlive()) return;
-
- reconnectionThread = new Thread() {
-
- /**
- * Holds the current number of reconnection attempts
- */
- private int attempts = 0;
-
- /**
- * Returns the number of seconds until the next reconnection attempt.
- *
- * @return the number of seconds until the next reconnection attempt.
- */
- private int timeDelay() {
- attempts++;
- if (attempts > 13) {
- return randomBase*6*5; // between 2.5 and 7.5 minutes (~5 minutes)
- }
- if (attempts > 7) {
- return randomBase*6; // between 30 and 90 seconds (~1 minutes)
- }
- return randomBase; // 10 seconds
- }
-
- /**
- * The process will try the reconnection until the connection succeed or the user
- * cancell it
- */
- public void run() {
- // The process will try to reconnect until the connection is established or
- // the user cancel the reconnection process {@link Connection#disconnect()}
- while (ReconnectionManager.this.isReconnectionAllowed()) {
- // Find how much time we should wait until the next reconnection
- int remainingSeconds = timeDelay();
- // Sleep until we're ready for the next reconnection attempt. Notify
- // listeners once per second about how much time remains before the next
- // reconnection attempt.
- while (ReconnectionManager.this.isReconnectionAllowed() &&
- remainingSeconds > 0)
- {
- try {
- Thread.sleep(1000);
- remainingSeconds--;
- ReconnectionManager.this
- .notifyAttemptToReconnectIn(remainingSeconds);
- }
- catch (InterruptedException e1) {
- e1.printStackTrace();
- // Notify the reconnection has failed
- ReconnectionManager.this.notifyReconnectionFailed(e1);
- }
- }
-
- // Makes a reconnection attempt
- try {
- if (ReconnectionManager.this.isReconnectionAllowed()) {
- connection.connect();
- }
- }
- catch (XMPPException e) {
- // Fires the failed reconnection notification
- ReconnectionManager.this.notifyReconnectionFailed(e);
- }
- }
- }
- };
- reconnectionThread.setName("Smack Reconnection Manager");
- reconnectionThread.setDaemon(true);
- reconnectionThread.start();
- }
- }
-
- /**
- * Fires listeners when a reconnection attempt has failed.
- *
- * @param exception the exception that occured.
- */
- protected void notifyReconnectionFailed(Exception exception) {
+ }
+
+ /**
+ * Starts a reconnection mechanism if it was configured to do that.
+ * The algorithm is been executed when the first connection error is detected.
+ * <p/>
+ * The reconnection mechanism will try to reconnect periodically in this way:
+ * <ol>
+ * <li>First it will try 6 times every 10 seconds.
+ * <li>Then it will try 10 times every 1 minute.
+ * <li>Finally it will try indefinitely every 5 minutes.
+ * </ol>
+ */
+ synchronized protected void reconnect() {
+ if (this.isReconnectionAllowed()) {
+ // Since there is no thread running, creates a new one to attempt
+ // the reconnection.
+ // avoid to run duplicated reconnectionThread -- fd: 16/09/2010
+ if (reconnectionThread!=null && reconnectionThread.isAlive()) return;
+
+ reconnectionThread = new Thread() {
+
+ /**
+ * Holds the current number of reconnection attempts
+ */
+ private int attempts = 0;
+
+ /**
+ * Returns the number of seconds until the next reconnection attempt.
+ *
+ * @return the number of seconds until the next reconnection attempt.
+ */
+ private int timeDelay() {
+ attempts++;
+ if (attempts > 13) {
+ return randomBase*6*5; // between 2.5 and 7.5 minutes (~5 minutes)
+ }
+ if (attempts > 7) {
+ return randomBase*6; // between 30 and 90 seconds (~1 minutes)
+ }
+ return randomBase; // 10 seconds
+ }
+
+ /**
+ * The process will try the reconnection until the connection succeed or the user
+ * cancell it
+ */
+ public void run() {
+ // The process will try to reconnect until the connection is established or
+ // the user cancel the reconnection process {@link Connection#disconnect()}
+ while (ReconnectionManager.this.isReconnectionAllowed()) {
+ // Find how much time we should wait until the next reconnection
+ int remainingSeconds = timeDelay();
+ // Sleep until we're ready for the next reconnection attempt. Notify
+ // listeners once per second about how much time remains before the next
+ // reconnection attempt.
+ while (ReconnectionManager.this.isReconnectionAllowed() &&
+ remainingSeconds > 0)
+ {
+ try {
+ Thread.sleep(1000);
+ remainingSeconds--;
+ ReconnectionManager.this
+ .notifyAttemptToReconnectIn(remainingSeconds);
+ }
+ catch (InterruptedException e1) {
+ e1.printStackTrace();
+ // Notify the reconnection has failed
+ ReconnectionManager.this.notifyReconnectionFailed(e1);
+ }
+ }
+
+ // Makes a reconnection attempt
+ try {
+ if (ReconnectionManager.this.isReconnectionAllowed()) {
+ connection.connect();
+ }
+ }
+ catch (XMPPException e) {
+ // Fires the failed reconnection notification
+ ReconnectionManager.this.notifyReconnectionFailed(e);
+ }
+ }
+ }
+ };
+ reconnectionThread.setName("Smack Reconnection Manager");
+ reconnectionThread.setDaemon(true);
+ reconnectionThread.start();
+ }
+ }
+
+ /**
+ * Fires listeners when a reconnection attempt has failed.
+ *
+ * @param exception the exception that occured.
+ */
+ protected void notifyReconnectionFailed(Exception exception) {
if (isReconnectionAllowed()) {
for (ConnectionListener listener : connection.connectionListeners) {
- listener.reconnectionFailed(exception);
- }
- }
- }
-
- /**
- * Fires listeners when The Connection will retry a reconnection. Expressed in seconds.
- *
- * @param seconds the number of seconds that a reconnection will be attempted in.
- */
- protected void notifyAttemptToReconnectIn(int seconds) {
+ listener.reconnectionFailed(exception);
+ }
+ }
+ }
+
+ /**
+ * Fires listeners when The Connection will retry a reconnection. Expressed in seconds.
+ *
+ * @param seconds the number of seconds that a reconnection will be attempted in.
+ */
+ protected void notifyAttemptToReconnectIn(int seconds) {
if (isReconnectionAllowed()) {
for (ConnectionListener listener : connection.connectionListeners) {
- listener.reconnectingIn(seconds);
- }
- }
- }
-
- public void connectionClosed() {
- done = true;
- }
-
- public void connectionClosedOnError(Exception e) {
- done = false;
- if (e instanceof XMPPException) {
- XMPPException xmppEx = (XMPPException) e;
- StreamError error = xmppEx.getStreamError();
-
- // Make sure the error is not null
- if (error != null) {
- String reason = error.getCode();
-
- if ("conflict".equals(reason)) {
- return;
- }
- }
- }
-
- if (this.isReconnectionAllowed()) {
- this.reconnect();
- }
- }
-
- public void reconnectingIn(int seconds) {
- // ignore
- }
-
- public void reconnectionFailed(Exception e) {
- // ignore
- }
-
- /**
- * The connection has successfull gotten connected.
- */
- public void reconnectionSuccessful() {
- // ignore
- }
-
+ listener.reconnectingIn(seconds);
+ }
+ }
+ }
+
+ public void connectionClosed() {
+ done = true;
+ }
+
+ public void connectionClosedOnError(Exception e) {
+ done = false;
+ if (e instanceof XMPPException) {
+ XMPPException xmppEx = (XMPPException) e;
+ StreamError error = xmppEx.getStreamError();
+
+ // Make sure the error is not null
+ if (error != null) {
+ String reason = error.getCode();
+
+ if ("conflict".equals(reason)) {
+ return;
+ }
+ }
+ }
+
+ if (this.isReconnectionAllowed()) {
+ this.reconnect();
+ }
+ }
+
+ public void reconnectingIn(int seconds) {
+ // ignore
+ }
+
+ public void reconnectionFailed(Exception e) {
+ // ignore
+ }
+
+ /**
+ * The connection has successfull gotten connected.
+ */
+ public void reconnectionSuccessful() {
+ // ignore
+ }
+
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SASLAuthentication.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SASLAuthentication.java
index 6f8b5bf1e..abf08c8a8 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SASLAuthentication.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SASLAuthentication.java
@@ -1,591 +1,591 @@
-/**
- * $RCSfile$
- * $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
- *
- * 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;
-
-import org.jivesoftware.smack.filter.PacketIDFilter;
-import org.jivesoftware.smack.packet.Bind;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.Session;
-import org.jivesoftware.smack.sasl.*;
-
-import javax.security.auth.callback.CallbackHandler;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.util.*;
-
-/**
- * <p>This class is responsible authenticating the user using SASL, binding the resource
- * to the connection and establishing a session with the server.</p>
- *
- * <p>Once TLS has been negotiated (i.e. the connection has been secured) it is possible to
- * register with the server, authenticate using Non-SASL or authenticate using SASL. If the
- * server supports SASL then Smack will first try to authenticate using SASL. But if that
- * fails then Non-SASL will be tried.</p>
- *
- * <p>The server may support many SASL mechanisms to use for authenticating. Out of the box
- * Smack provides several SASL mechanisms, but it is possible to register new SASL Mechanisms. Use
- * {@link #registerSASLMechanism(String, Class)} to register a new mechanisms. A registered
- * mechanism wont be used until {@link #supportSASLMechanism(String, int)} is called. By default,
- * the list of supported SASL mechanisms is determined from the {@link SmackConfiguration}. </p>
- *
- * <p>Once the user has been authenticated with SASL, it is necessary to bind a resource for
- * the connection. If no resource is passed in {@link #authenticate(String, String, String)}
- * then the server will assign a resource for the connection. In case a resource is passed
- * then the server will receive the desired resource but may assign a modified resource for
- * the connection.</p>
- *
- * <p>Once a resource has been binded and if the server supports sessions then Smack will establish
- * a session so that instant messaging and presence functionalities may be used.</p>
- *
- * @see org.jivesoftware.smack.sasl.SASLMechanism
- *
- * @author Gaston Dombiak
- * @author Jay Kline
- */
-public class SASLAuthentication implements UserAuthentication {
-
- private static Map<String, Class<? extends SASLMechanism>> implementedMechanisms = new HashMap<String, Class<? extends SASLMechanism>>();
- private static List<String> mechanismsPreferences = new ArrayList<String>();
-
- private Connection connection;
- private Collection<String> serverMechanisms = new ArrayList<String>();
- private SASLMechanism currentMechanism = null;
- /**
- * Boolean indicating if SASL negotiation has finished and was successful.
- */
- private boolean saslNegotiated;
- /**
- * Boolean indication if SASL authentication has failed. When failed the server may end
- * the connection.
- */
- private boolean saslFailed;
- private boolean resourceBinded;
- private boolean sessionSupported;
- /**
- * The SASL related error condition if there was one provided by the server.
- */
- private String errorCondition;
-
- static {
-
- // Register SASL mechanisms supported by Smack
- registerSASLMechanism("EXTERNAL", SASLExternalMechanism.class);
- registerSASLMechanism("GSSAPI", SASLGSSAPIMechanism.class);
- registerSASLMechanism("DIGEST-MD5", SASLDigestMD5Mechanism.class);
- registerSASLMechanism("CRAM-MD5", SASLCramMD5Mechanism.class);
- registerSASLMechanism("PLAIN", SASLPlainMechanism.class);
- registerSASLMechanism("ANONYMOUS", SASLAnonymous.class);
-
- supportSASLMechanism("GSSAPI",0);
- supportSASLMechanism("DIGEST-MD5",1);
- supportSASLMechanism("CRAM-MD5",2);
- supportSASLMechanism("PLAIN",3);
- supportSASLMechanism("ANONYMOUS",4);
-
- }
-
- /**
- * Registers a new SASL mechanism
- *
- * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
- * @param mClass a SASLMechanism subclass.
- */
- public static void registerSASLMechanism(String name, Class<? extends SASLMechanism> mClass) {
- implementedMechanisms.put(name, mClass);
- }
-
- /**
- * Unregisters an existing SASL mechanism. Once the mechanism has been unregistered it won't
- * be possible to authenticate users using the removed SASL mechanism. It also removes the
- * mechanism from the supported list.
- *
- * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
- */
- public static void unregisterSASLMechanism(String name) {
- implementedMechanisms.remove(name);
- mechanismsPreferences.remove(name);
- }
-
-
- /**
- * Registers a new SASL mechanism in the specified preference position. The client will try
- * to authenticate using the most prefered SASL mechanism that is also supported by the server.
- * The SASL mechanism must be registered via {@link #registerSASLMechanism(String, Class)}
- *
- * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
- */
- public static void supportSASLMechanism(String name) {
- mechanismsPreferences.add(0, name);
- }
-
- /**
- * Registers a new SASL mechanism in the specified preference position. The client will try
- * to authenticate using the most prefered SASL mechanism that is also supported by the server.
- * Use the <tt>index</tt> parameter to set the level of preference of the new SASL mechanism.
- * A value of 0 means that the mechanism is the most prefered one. The SASL mechanism must be
- * registered via {@link #registerSASLMechanism(String, Class)}
- *
- * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
- * @param index preference position amongst all the implemented SASL mechanism. Starts with 0.
- */
- public static void supportSASLMechanism(String name, int index) {
- mechanismsPreferences.add(index, name);
- }
-
- /**
- * Un-supports an existing SASL mechanism. Once the mechanism has been unregistered it won't
- * be possible to authenticate users using the removed SASL mechanism. Note that the mechanism
- * is still registered, but will just not be used.
- *
- * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
- */
- public static void unsupportSASLMechanism(String name) {
- mechanismsPreferences.remove(name);
- }
-
- /**
- * Returns the registerd SASLMechanism classes sorted by the level of preference.
- *
- * @return the registerd SASLMechanism classes sorted by the level of preference.
- */
- public static List<Class<? extends SASLMechanism>> getRegisterSASLMechanisms() {
- List<Class<? extends SASLMechanism>> answer = new ArrayList<Class<? extends SASLMechanism>>();
- for (String mechanismsPreference : mechanismsPreferences) {
- answer.add(implementedMechanisms.get(mechanismsPreference));
- }
- return answer;
- }
-
- SASLAuthentication(Connection connection) {
- super();
- this.connection = connection;
- this.init();
- }
-
- /**
- * Returns true if the server offered ANONYMOUS SASL as a way to authenticate users.
- *
- * @return true if the server offered ANONYMOUS SASL as a way to authenticate users.
- */
- public boolean hasAnonymousAuthentication() {
- return serverMechanisms.contains("ANONYMOUS");
- }
-
- /**
- * Returns true if the server offered SASL authentication besides ANONYMOUS SASL.
- *
- * @return true if the server offered SASL authentication besides ANONYMOUS SASL.
- */
- public boolean hasNonAnonymousAuthentication() {
- return !serverMechanisms.isEmpty() && (serverMechanisms.size() != 1 || !hasAnonymousAuthentication());
- }
-
- /**
- * Performs SASL authentication of the specified user. If SASL authentication was successful
- * then resource binding and session establishment will be performed. This method will return
- * the full JID provided by the server while binding a resource to the connection.<p>
- *
- * The server may assign a full JID with a username or resource different than the requested
- * by this method.
- *
- * @param username the username that is authenticating with the server.
- * @param resource the desired resource.
- * @param cbh the CallbackHandler used to get information from the user
- * @return the full JID provided by the server while binding a resource to the connection.
- * @throws XMPPException if an error occures while authenticating.
- */
- public String authenticate(String username, String resource, CallbackHandler cbh)
- throws XMPPException {
- // Locate the SASLMechanism to use
- String selectedMechanism = null;
- for (String mechanism : mechanismsPreferences) {
- if (implementedMechanisms.containsKey(mechanism) &&
- serverMechanisms.contains(mechanism)) {
- selectedMechanism = mechanism;
- break;
- }
- }
- if (selectedMechanism != null) {
- // A SASL mechanism was found. Authenticate using the selected mechanism and then
- // proceed to bind a resource
- try {
- Class<? extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism);
- Constructor<? extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class);
- currentMechanism = constructor.newInstance(this);
- // 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.getHost(), cbh);
-
- // Wait until SASL negotiation finishes
- synchronized (this) {
- if (!saslNegotiated && !saslFailed) {
- try {
- wait(30000);
- }
- catch (InterruptedException e) {
- // Ignore
- }
- }
- }
-
- if (saslFailed) {
- // SASL authentication failed and the server may have closed the connection
- // so throw an exception
- if (errorCondition != null) {
- throw new XMPPException("SASL authentication " +
- selectedMechanism + " failed: " + errorCondition);
- }
- else {
- throw new XMPPException("SASL authentication failed using mechanism " +
- selectedMechanism);
- }
- }
-
- if (saslNegotiated) {
- // Bind a resource for this connection and
- return bindResourceAndEstablishSession(resource);
- } else {
- // SASL authentication failed
- }
- }
- catch (XMPPException e) {
- throw e;
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- else {
- throw new XMPPException("SASL Authentication failed. No known authentication mechanisims.");
- }
- throw new XMPPException("SASL authentication failed");
- }
-
- /**
- * Performs SASL authentication of the specified user. If SASL authentication was successful
- * then resource binding and session establishment will be performed. This method will return
- * the full JID provided by the server while binding a resource to the connection.<p>
- *
- * The server may assign a full JID with a username or resource different than the requested
- * by this method.
- *
- * @param username the username that is authenticating with the server.
- * @param password the password to send to the server.
- * @param resource the desired resource.
- * @return the full JID provided by the server while binding a resource to the connection.
- * @throws XMPPException if an error occures while authenticating.
- */
- public String authenticate(String username, String password, String resource)
- throws XMPPException {
- // Locate the SASLMechanism to use
- String selectedMechanism = null;
- for (String mechanism : mechanismsPreferences) {
- if (implementedMechanisms.containsKey(mechanism) &&
- serverMechanisms.contains(mechanism)) {
- selectedMechanism = mechanism;
- break;
- }
- }
- if (selectedMechanism != null) {
- // A SASL mechanism was found. Authenticate using the selected mechanism and then
- // proceed to bind a resource
- try {
- Class<? extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism);
- Constructor<? extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class);
- currentMechanism = constructor.newInstance(this);
- // 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.
-
- //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) {
- if (!saslNegotiated && !saslFailed) {
- try {
- wait(30000);
- }
- catch (InterruptedException e) {
- // Ignore
- }
- }
- }
-
- if (saslFailed) {
- // SASL authentication failed and the server may have closed the connection
- // so throw an exception
- if (errorCondition != null) {
- throw new XMPPException("SASL authentication " +
- selectedMechanism + " failed: " + errorCondition);
- }
- else {
- throw new XMPPException("SASL authentication failed using mechanism " +
- selectedMechanism);
- }
- }
-
- if (saslNegotiated) {
- // Bind a resource for this connection and
- return bindResourceAndEstablishSession(resource);
- }
- else {
- // SASL authentication failed so try a Non-SASL authentication
- return new NonSASLAuthentication(connection)
- .authenticate(username, password, resource);
- }
- }
- catch (XMPPException e) {
- throw e;
- }
- catch (Exception e) {
- e.printStackTrace();
- // SASL authentication failed so try a Non-SASL authentication
- return new NonSASLAuthentication(connection)
- .authenticate(username, password, resource);
- }
- }
- else {
- // No SASL method was found so try a Non-SASL authentication
- return new NonSASLAuthentication(connection).authenticate(username, password, resource);
- }
- }
-
- /**
- * Performs ANONYMOUS SASL authentication. If SASL authentication was successful
- * then resource binding and session establishment will be performed. This method will return
- * the full JID provided by the server while binding a resource to the connection.<p>
- *
- * The server will assign a full JID with a randomly generated resource and possibly with
- * no username.
- *
- * @return the full JID provided by the server while binding a resource to the connection.
- * @throws XMPPException if an error occures while authenticating.
- */
- public String authenticateAnonymously() throws XMPPException {
- try {
- currentMechanism = new SASLAnonymous(this);
- currentMechanism.authenticate(null,null,null,"");
-
- // Wait until SASL negotiation finishes
- synchronized (this) {
- if (!saslNegotiated && !saslFailed) {
- try {
- wait(5000);
- }
- catch (InterruptedException e) {
- // Ignore
- }
- }
- }
-
- if (saslFailed) {
- // SASL authentication failed and the server may have closed the connection
- // so throw an exception
- if (errorCondition != null) {
- throw new XMPPException("SASL authentication failed: " + errorCondition);
- }
- else {
- throw new XMPPException("SASL authentication failed");
- }
- }
-
- if (saslNegotiated) {
- // Bind a resource for this connection and
- return bindResourceAndEstablishSession(null);
- }
- else {
- return new NonSASLAuthentication(connection).authenticateAnonymously();
- }
- } catch (IOException e) {
- return new NonSASLAuthentication(connection).authenticateAnonymously();
- }
- }
-
- private String bindResourceAndEstablishSession(String resource) throws XMPPException {
- // Wait until server sends response containing the <bind> element
- synchronized (this) {
- if (!resourceBinded) {
- try {
- wait(30000);
- }
- catch (InterruptedException e) {
- // Ignore
- }
- }
- }
-
- if (!resourceBinded) {
- // Server never offered resource binding
- throw new XMPPException("Resource binding not offered by server");
- }
-
- Bind bindResource = new Bind();
- bindResource.setResource(resource);
-
- PacketCollector collector = connection
- .createPacketCollector(new PacketIDFilter(bindResource.getPacketID()));
- // Send the packet
- connection.sendPacket(bindResource);
- // Wait up to a certain number of seconds for a response from the server.
- Bind response = (Bind) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from the server.");
- }
- // If the server replied with an error, throw an exception.
- else if (response.getType() == IQ.Type.ERROR) {
- throw new XMPPException(response.getError());
- }
- String userJID = response.getJid();
-
- if (sessionSupported) {
- Session session = new Session();
- collector = connection.createPacketCollector(new PacketIDFilter(session.getPacketID()));
- // Send the packet
- connection.sendPacket(session);
- // Wait up to a certain number of seconds for a response from the server.
- IQ ack = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- collector.cancel();
- if (ack == null) {
- throw new XMPPException("No response from the server.");
- }
- // If the server replied with an error, throw an exception.
- else if (ack.getType() == IQ.Type.ERROR) {
- throw new XMPPException(ack.getError());
- }
- }
- return userJID;
- }
-
- /**
- * Sets the available SASL mechanism reported by the server. The server will report the
- * available SASL mechanism once the TLS negotiation was successful. This information is
- * stored and will be used when doing the authentication for logging in the user.
- *
- * @param mechanisms collection of strings with the available SASL mechanism reported
- * by the server.
- */
- void setAvailableSASLMethods(Collection<String> mechanisms) {
- this.serverMechanisms = mechanisms;
- }
-
- /**
- * Returns true if the user was able to authenticate with the server usins SASL.
- *
- * @return true if the user was able to authenticate with the server usins SASL.
- */
- public boolean isAuthenticated() {
- return saslNegotiated;
- }
-
- /**
- * The server is challenging the SASL authentication we just sent. Forward the challenge
- * to the current SASLMechanism we are using. The SASLMechanism will send a response to
- * the server. The length of the challenge-response sequence varies according to the
- * SASLMechanism in use.
- *
- * @param challenge a base64 encoded string representing the challenge.
- * @throws IOException If a network error occures while authenticating.
- */
- void challengeReceived(String challenge) throws IOException {
- currentMechanism.challengeReceived(challenge);
- }
-
- /**
- * Notification message saying that SASL authentication was successful. The next step
- * would be to bind the resource.
- */
- void authenticated() {
- synchronized (this) {
- saslNegotiated = true;
- // Wake up the thread that is waiting in the #authenticate method
- notify();
- }
- }
-
- /**
- * Notification message saying that SASL authentication has failed. The server may have
- * closed the connection depending on the number of possible retries.
- *
- * @deprecated replaced by {@see #authenticationFailed(String)}.
- */
- void authenticationFailed() {
- authenticationFailed(null);
- }
-
- /**
- * Notification message saying that SASL authentication has failed. The server may have
- * closed the connection depending on the number of possible retries.
- *
- * @param condition the error condition provided by the server.
- */
- void authenticationFailed(String condition) {
- synchronized (this) {
- saslFailed = true;
- errorCondition = condition;
- // Wake up the thread that is waiting in the #authenticate method
- notify();
- }
- }
-
- /**
- * Notification message saying that the server requires the client to bind a
- * resource to the stream.
- */
- void bindingRequired() {
- synchronized (this) {
- resourceBinded = true;
- // Wake up the thread that is waiting in the #authenticate method
- notify();
- }
- }
-
- public void send(Packet stanza) {
- connection.sendPacket(stanza);
- }
-
- /**
- * Notification message saying that the server supports sessions. When a server supports
- * sessions the client needs to send a Session packet after successfully binding a resource
- * for the session.
- */
- void sessionsSupported() {
- sessionSupported = true;
- }
-
- /**
- * Initializes the internal state in order to be able to be reused. The authentication
- * is used by the connection at the first login and then reused after the connection
- * is disconnected and then reconnected.
- */
- protected void init() {
- saslNegotiated = false;
- saslFailed = false;
- resourceBinded = false;
- sessionSupported = false;
- }
+/**
+ * $RCSfile$
+ * $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
+ *
+ * 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;
+
+import org.jivesoftware.smack.filter.PacketIDFilter;
+import org.jivesoftware.smack.packet.Bind;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.Session;
+import org.jivesoftware.smack.sasl.*;
+
+import javax.security.auth.callback.CallbackHandler;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.*;
+
+/**
+ * <p>This class is responsible authenticating the user using SASL, binding the resource
+ * to the connection and establishing a session with the server.</p>
+ *
+ * <p>Once TLS has been negotiated (i.e. the connection has been secured) it is possible to
+ * register with the server, authenticate using Non-SASL or authenticate using SASL. If the
+ * server supports SASL then Smack will first try to authenticate using SASL. But if that
+ * fails then Non-SASL will be tried.</p>
+ *
+ * <p>The server may support many SASL mechanisms to use for authenticating. Out of the box
+ * Smack provides several SASL mechanisms, but it is possible to register new SASL Mechanisms. Use
+ * {@link #registerSASLMechanism(String, Class)} to register a new mechanisms. A registered
+ * mechanism wont be used until {@link #supportSASLMechanism(String, int)} is called. By default,
+ * the list of supported SASL mechanisms is determined from the {@link SmackConfiguration}. </p>
+ *
+ * <p>Once the user has been authenticated with SASL, it is necessary to bind a resource for
+ * the connection. If no resource is passed in {@link #authenticate(String, String, String)}
+ * then the server will assign a resource for the connection. In case a resource is passed
+ * then the server will receive the desired resource but may assign a modified resource for
+ * the connection.</p>
+ *
+ * <p>Once a resource has been binded and if the server supports sessions then Smack will establish
+ * a session so that instant messaging and presence functionalities may be used.</p>
+ *
+ * @see org.jivesoftware.smack.sasl.SASLMechanism
+ *
+ * @author Gaston Dombiak
+ * @author Jay Kline
+ */
+public class SASLAuthentication implements UserAuthentication {
+
+ private static Map<String, Class<? extends SASLMechanism>> implementedMechanisms = new HashMap<String, Class<? extends SASLMechanism>>();
+ private static List<String> mechanismsPreferences = new ArrayList<String>();
+
+ private Connection connection;
+ private Collection<String> serverMechanisms = new ArrayList<String>();
+ private SASLMechanism currentMechanism = null;
+ /**
+ * Boolean indicating if SASL negotiation has finished and was successful.
+ */
+ private boolean saslNegotiated;
+ /**
+ * Boolean indication if SASL authentication has failed. When failed the server may end
+ * the connection.
+ */
+ private boolean saslFailed;
+ private boolean resourceBinded;
+ private boolean sessionSupported;
+ /**
+ * The SASL related error condition if there was one provided by the server.
+ */
+ private String errorCondition;
+
+ static {
+
+ // Register SASL mechanisms supported by Smack
+ registerSASLMechanism("EXTERNAL", SASLExternalMechanism.class);
+ registerSASLMechanism("GSSAPI", SASLGSSAPIMechanism.class);
+ registerSASLMechanism("DIGEST-MD5", SASLDigestMD5Mechanism.class);
+ registerSASLMechanism("CRAM-MD5", SASLCramMD5Mechanism.class);
+ registerSASLMechanism("PLAIN", SASLPlainMechanism.class);
+ registerSASLMechanism("ANONYMOUS", SASLAnonymous.class);
+
+ supportSASLMechanism("GSSAPI",0);
+ supportSASLMechanism("DIGEST-MD5",1);
+ supportSASLMechanism("CRAM-MD5",2);
+ supportSASLMechanism("PLAIN",3);
+ supportSASLMechanism("ANONYMOUS",4);
+
+ }
+
+ /**
+ * Registers a new SASL mechanism
+ *
+ * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
+ * @param mClass a SASLMechanism subclass.
+ */
+ public static void registerSASLMechanism(String name, Class<? extends SASLMechanism> mClass) {
+ implementedMechanisms.put(name, mClass);
+ }
+
+ /**
+ * Unregisters an existing SASL mechanism. Once the mechanism has been unregistered it won't
+ * be possible to authenticate users using the removed SASL mechanism. It also removes the
+ * mechanism from the supported list.
+ *
+ * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
+ */
+ public static void unregisterSASLMechanism(String name) {
+ implementedMechanisms.remove(name);
+ mechanismsPreferences.remove(name);
+ }
+
+
+ /**
+ * Registers a new SASL mechanism in the specified preference position. The client will try
+ * to authenticate using the most prefered SASL mechanism that is also supported by the server.
+ * The SASL mechanism must be registered via {@link #registerSASLMechanism(String, Class)}
+ *
+ * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
+ */
+ public static void supportSASLMechanism(String name) {
+ mechanismsPreferences.add(0, name);
+ }
+
+ /**
+ * Registers a new SASL mechanism in the specified preference position. The client will try
+ * to authenticate using the most prefered SASL mechanism that is also supported by the server.
+ * Use the <tt>index</tt> parameter to set the level of preference of the new SASL mechanism.
+ * A value of 0 means that the mechanism is the most prefered one. The SASL mechanism must be
+ * registered via {@link #registerSASLMechanism(String, Class)}
+ *
+ * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
+ * @param index preference position amongst all the implemented SASL mechanism. Starts with 0.
+ */
+ public static void supportSASLMechanism(String name, int index) {
+ mechanismsPreferences.add(index, name);
+ }
+
+ /**
+ * Un-supports an existing SASL mechanism. Once the mechanism has been unregistered it won't
+ * be possible to authenticate users using the removed SASL mechanism. Note that the mechanism
+ * is still registered, but will just not be used.
+ *
+ * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
+ */
+ public static void unsupportSASLMechanism(String name) {
+ mechanismsPreferences.remove(name);
+ }
+
+ /**
+ * Returns the registerd SASLMechanism classes sorted by the level of preference.
+ *
+ * @return the registerd SASLMechanism classes sorted by the level of preference.
+ */
+ public static List<Class<? extends SASLMechanism>> getRegisterSASLMechanisms() {
+ List<Class<? extends SASLMechanism>> answer = new ArrayList<Class<? extends SASLMechanism>>();
+ for (String mechanismsPreference : mechanismsPreferences) {
+ answer.add(implementedMechanisms.get(mechanismsPreference));
+ }
+ return answer;
+ }
+
+ SASLAuthentication(Connection connection) {
+ super();
+ this.connection = connection;
+ this.init();
+ }
+
+ /**
+ * Returns true if the server offered ANONYMOUS SASL as a way to authenticate users.
+ *
+ * @return true if the server offered ANONYMOUS SASL as a way to authenticate users.
+ */
+ public boolean hasAnonymousAuthentication() {
+ return serverMechanisms.contains("ANONYMOUS");
+ }
+
+ /**
+ * Returns true if the server offered SASL authentication besides ANONYMOUS SASL.
+ *
+ * @return true if the server offered SASL authentication besides ANONYMOUS SASL.
+ */
+ public boolean hasNonAnonymousAuthentication() {
+ return !serverMechanisms.isEmpty() && (serverMechanisms.size() != 1 || !hasAnonymousAuthentication());
+ }
+
+ /**
+ * Performs SASL authentication of the specified user. If SASL authentication was successful
+ * then resource binding and session establishment will be performed. This method will return
+ * the full JID provided by the server while binding a resource to the connection.<p>
+ *
+ * The server may assign a full JID with a username or resource different than the requested
+ * by this method.
+ *
+ * @param username the username that is authenticating with the server.
+ * @param resource the desired resource.
+ * @param cbh the CallbackHandler used to get information from the user
+ * @return the full JID provided by the server while binding a resource to the connection.
+ * @throws XMPPException if an error occures while authenticating.
+ */
+ public String authenticate(String username, String resource, CallbackHandler cbh)
+ throws XMPPException {
+ // Locate the SASLMechanism to use
+ String selectedMechanism = null;
+ for (String mechanism : mechanismsPreferences) {
+ if (implementedMechanisms.containsKey(mechanism) &&
+ serverMechanisms.contains(mechanism)) {
+ selectedMechanism = mechanism;
+ break;
+ }
+ }
+ if (selectedMechanism != null) {
+ // A SASL mechanism was found. Authenticate using the selected mechanism and then
+ // proceed to bind a resource
+ try {
+ Class<? extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism);
+ Constructor<? extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class);
+ currentMechanism = constructor.newInstance(this);
+ // 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.getHost(), cbh);
+
+ // Wait until SASL negotiation finishes
+ synchronized (this) {
+ if (!saslNegotiated && !saslFailed) {
+ try {
+ wait(30000);
+ }
+ catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ if (saslFailed) {
+ // SASL authentication failed and the server may have closed the connection
+ // so throw an exception
+ if (errorCondition != null) {
+ throw new XMPPException("SASL authentication " +
+ selectedMechanism + " failed: " + errorCondition);
+ }
+ else {
+ throw new XMPPException("SASL authentication failed using mechanism " +
+ selectedMechanism);
+ }
+ }
+
+ if (saslNegotiated) {
+ // Bind a resource for this connection and
+ return bindResourceAndEstablishSession(resource);
+ } else {
+ // SASL authentication failed
+ }
+ }
+ catch (XMPPException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ else {
+ throw new XMPPException("SASL Authentication failed. No known authentication mechanisims.");
+ }
+ throw new XMPPException("SASL authentication failed");
+ }
+
+ /**
+ * Performs SASL authentication of the specified user. If SASL authentication was successful
+ * then resource binding and session establishment will be performed. This method will return
+ * the full JID provided by the server while binding a resource to the connection.<p>
+ *
+ * The server may assign a full JID with a username or resource different than the requested
+ * by this method.
+ *
+ * @param username the username that is authenticating with the server.
+ * @param password the password to send to the server.
+ * @param resource the desired resource.
+ * @return the full JID provided by the server while binding a resource to the connection.
+ * @throws XMPPException if an error occures while authenticating.
+ */
+ public String authenticate(String username, String password, String resource)
+ throws XMPPException {
+ // Locate the SASLMechanism to use
+ String selectedMechanism = null;
+ for (String mechanism : mechanismsPreferences) {
+ if (implementedMechanisms.containsKey(mechanism) &&
+ serverMechanisms.contains(mechanism)) {
+ selectedMechanism = mechanism;
+ break;
+ }
+ }
+ if (selectedMechanism != null) {
+ // A SASL mechanism was found. Authenticate using the selected mechanism and then
+ // proceed to bind a resource
+ try {
+ Class<? extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism);
+ Constructor<? extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class);
+ currentMechanism = constructor.newInstance(this);
+ // 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.
+
+ //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) {
+ if (!saslNegotiated && !saslFailed) {
+ try {
+ wait(30000);
+ }
+ catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ if (saslFailed) {
+ // SASL authentication failed and the server may have closed the connection
+ // so throw an exception
+ if (errorCondition != null) {
+ throw new XMPPException("SASL authentication " +
+ selectedMechanism + " failed: " + errorCondition);
+ }
+ else {
+ throw new XMPPException("SASL authentication failed using mechanism " +
+ selectedMechanism);
+ }
+ }
+
+ if (saslNegotiated) {
+ // Bind a resource for this connection and
+ return bindResourceAndEstablishSession(resource);
+ }
+ else {
+ // SASL authentication failed so try a Non-SASL authentication
+ return new NonSASLAuthentication(connection)
+ .authenticate(username, password, resource);
+ }
+ }
+ catch (XMPPException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ // SASL authentication failed so try a Non-SASL authentication
+ return new NonSASLAuthentication(connection)
+ .authenticate(username, password, resource);
+ }
+ }
+ else {
+ // No SASL method was found so try a Non-SASL authentication
+ return new NonSASLAuthentication(connection).authenticate(username, password, resource);
+ }
+ }
+
+ /**
+ * Performs ANONYMOUS SASL authentication. If SASL authentication was successful
+ * then resource binding and session establishment will be performed. This method will return
+ * the full JID provided by the server while binding a resource to the connection.<p>
+ *
+ * The server will assign a full JID with a randomly generated resource and possibly with
+ * no username.
+ *
+ * @return the full JID provided by the server while binding a resource to the connection.
+ * @throws XMPPException if an error occures while authenticating.
+ */
+ public String authenticateAnonymously() throws XMPPException {
+ try {
+ currentMechanism = new SASLAnonymous(this);
+ currentMechanism.authenticate(null,null,null,"");
+
+ // Wait until SASL negotiation finishes
+ synchronized (this) {
+ if (!saslNegotiated && !saslFailed) {
+ try {
+ wait(5000);
+ }
+ catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ if (saslFailed) {
+ // SASL authentication failed and the server may have closed the connection
+ // so throw an exception
+ if (errorCondition != null) {
+ throw new XMPPException("SASL authentication failed: " + errorCondition);
+ }
+ else {
+ throw new XMPPException("SASL authentication failed");
+ }
+ }
+
+ if (saslNegotiated) {
+ // Bind a resource for this connection and
+ return bindResourceAndEstablishSession(null);
+ }
+ else {
+ return new NonSASLAuthentication(connection).authenticateAnonymously();
+ }
+ } catch (IOException e) {
+ return new NonSASLAuthentication(connection).authenticateAnonymously();
+ }
+ }
+
+ private String bindResourceAndEstablishSession(String resource) throws XMPPException {
+ // Wait until server sends response containing the <bind> element
+ synchronized (this) {
+ if (!resourceBinded) {
+ try {
+ wait(30000);
+ }
+ catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ if (!resourceBinded) {
+ // Server never offered resource binding
+ throw new XMPPException("Resource binding not offered by server");
+ }
+
+ Bind bindResource = new Bind();
+ bindResource.setResource(resource);
+
+ PacketCollector collector = connection
+ .createPacketCollector(new PacketIDFilter(bindResource.getPacketID()));
+ // Send the packet
+ connection.sendPacket(bindResource);
+ // Wait up to a certain number of seconds for a response from the server.
+ Bind response = (Bind) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from the server.");
+ }
+ // If the server replied with an error, throw an exception.
+ else if (response.getType() == IQ.Type.ERROR) {
+ throw new XMPPException(response.getError());
+ }
+ String userJID = response.getJid();
+
+ if (sessionSupported) {
+ Session session = new Session();
+ collector = connection.createPacketCollector(new PacketIDFilter(session.getPacketID()));
+ // Send the packet
+ connection.sendPacket(session);
+ // Wait up to a certain number of seconds for a response from the server.
+ IQ ack = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ collector.cancel();
+ if (ack == null) {
+ throw new XMPPException("No response from the server.");
+ }
+ // If the server replied with an error, throw an exception.
+ else if (ack.getType() == IQ.Type.ERROR) {
+ throw new XMPPException(ack.getError());
+ }
+ }
+ return userJID;
+ }
+
+ /**
+ * Sets the available SASL mechanism reported by the server. The server will report the
+ * available SASL mechanism once the TLS negotiation was successful. This information is
+ * stored and will be used when doing the authentication for logging in the user.
+ *
+ * @param mechanisms collection of strings with the available SASL mechanism reported
+ * by the server.
+ */
+ void setAvailableSASLMethods(Collection<String> mechanisms) {
+ this.serverMechanisms = mechanisms;
+ }
+
+ /**
+ * Returns true if the user was able to authenticate with the server usins SASL.
+ *
+ * @return true if the user was able to authenticate with the server usins SASL.
+ */
+ public boolean isAuthenticated() {
+ return saslNegotiated;
+ }
+
+ /**
+ * The server is challenging the SASL authentication we just sent. Forward the challenge
+ * to the current SASLMechanism we are using. The SASLMechanism will send a response to
+ * the server. The length of the challenge-response sequence varies according to the
+ * SASLMechanism in use.
+ *
+ * @param challenge a base64 encoded string representing the challenge.
+ * @throws IOException If a network error occures while authenticating.
+ */
+ void challengeReceived(String challenge) throws IOException {
+ currentMechanism.challengeReceived(challenge);
+ }
+
+ /**
+ * Notification message saying that SASL authentication was successful. The next step
+ * would be to bind the resource.
+ */
+ void authenticated() {
+ synchronized (this) {
+ saslNegotiated = true;
+ // Wake up the thread that is waiting in the #authenticate method
+ notify();
+ }
+ }
+
+ /**
+ * Notification message saying that SASL authentication has failed. The server may have
+ * closed the connection depending on the number of possible retries.
+ *
+ * @deprecated replaced by {@see #authenticationFailed(String)}.
+ */
+ void authenticationFailed() {
+ authenticationFailed(null);
+ }
+
+ /**
+ * Notification message saying that SASL authentication has failed. The server may have
+ * closed the connection depending on the number of possible retries.
+ *
+ * @param condition the error condition provided by the server.
+ */
+ void authenticationFailed(String condition) {
+ synchronized (this) {
+ saslFailed = true;
+ errorCondition = condition;
+ // Wake up the thread that is waiting in the #authenticate method
+ notify();
+ }
+ }
+
+ /**
+ * Notification message saying that the server requires the client to bind a
+ * resource to the stream.
+ */
+ void bindingRequired() {
+ synchronized (this) {
+ resourceBinded = true;
+ // Wake up the thread that is waiting in the #authenticate method
+ notify();
+ }
+ }
+
+ public void send(Packet stanza) {
+ connection.sendPacket(stanza);
+ }
+
+ /**
+ * Notification message saying that the server supports sessions. When a server supports
+ * sessions the client needs to send a Session packet after successfully binding a resource
+ * for the session.
+ */
+ void sessionsSupported() {
+ sessionSupported = true;
+ }
+
+ /**
+ * Initializes the internal state in order to be able to be reused. The authentication
+ * is used by the connection at the first login and then reused after the connection
+ * is disconnected and then reconnected.
+ */
+ protected void init() {
+ saslNegotiated = false;
+ saslFailed = false;
+ resourceBinded = false;
+ sessionSupported = false;
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SmackError.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SmackError.java
index af22e7c0e..8527876b6 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SmackError.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/SmackError.java
@@ -1,24 +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;
- }
-}
+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;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/UserAuthentication.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/UserAuthentication.java
index 8f0dd505a..728428b65 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/UserAuthentication.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/UserAuthentication.java
@@ -1,79 +1,79 @@
-/**
- * $RCSfile$
- * $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
- *
- * 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;
-
-import javax.security.auth.callback.CallbackHandler;
-
-/**
- * There are two ways to authenticate a user with a server. Using SASL or Non-SASL
- * authentication. This interface makes {@link SASLAuthentication} and
- * {@link NonSASLAuthentication} polyphormic.
- *
- * @author Gaston Dombiak
- * @author Jay Kline
- */
-interface UserAuthentication {
-
- /**
- * Authenticates the user with the server. This method will return the full JID provided by
- * the server. The server may assign a full JID with a username and resource different than
- * requested by this method.
- *
- * Note that using callbacks is the prefered method of authenticating users since it allows
- * more flexability in the mechanisms used.
- *
- * @param username the requested username (authorization ID) for authenticating to the server
- * @param resource the requested resource.
- * @param cbh the CallbackHandler used to obtain authentication ID, password, or other
- * information
- * @return the full JID provided by the server while binding a resource for the connection.
- * @throws XMPPException if an error occurs while authenticating.
- */
- String authenticate(String username, String resource, CallbackHandler cbh) throws
- XMPPException;
-
- /**
- * Authenticates the user with the server. This method will return the full JID provided by
- * the server. The server may assign a full JID with a username and resource different than
- * the requested by this method.
- *
- * It is recommended that @{link #authenticate(String, String, CallbackHandler)} be used instead
- * since it provides greater flexability in authenticaiton and authorization.
- *
- * @param username the username that is authenticating with the server.
- * @param password the password to send to the server.
- * @param resource the desired resource.
- * @return the full JID provided by the server while binding a resource for the connection.
- * @throws XMPPException if an error occures while authenticating.
- */
- String authenticate(String username, String password, String resource) throws
- XMPPException;
-
- /**
- * Performs an anonymous authentication with the server. The server will created a new full JID
- * for this connection. An exception will be thrown if the server does not support anonymous
- * authentication.
- *
- * @return the full JID provided by the server while binding a resource for the connection.
- * @throws XMPPException if an error occures while authenticating.
- */
- String authenticateAnonymously() throws XMPPException;
-}
+/**
+ * $RCSfile$
+ * $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
+ *
+ * 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;
+
+import javax.security.auth.callback.CallbackHandler;
+
+/**
+ * There are two ways to authenticate a user with a server. Using SASL or Non-SASL
+ * authentication. This interface makes {@link SASLAuthentication} and
+ * {@link NonSASLAuthentication} polyphormic.
+ *
+ * @author Gaston Dombiak
+ * @author Jay Kline
+ */
+interface UserAuthentication {
+
+ /**
+ * Authenticates the user with the server. This method will return the full JID provided by
+ * the server. The server may assign a full JID with a username and resource different than
+ * requested by this method.
+ *
+ * Note that using callbacks is the prefered method of authenticating users since it allows
+ * more flexability in the mechanisms used.
+ *
+ * @param username the requested username (authorization ID) for authenticating to the server
+ * @param resource the requested resource.
+ * @param cbh the CallbackHandler used to obtain authentication ID, password, or other
+ * information
+ * @return the full JID provided by the server while binding a resource for the connection.
+ * @throws XMPPException if an error occurs while authenticating.
+ */
+ String authenticate(String username, String resource, CallbackHandler cbh) throws
+ XMPPException;
+
+ /**
+ * Authenticates the user with the server. This method will return the full JID provided by
+ * the server. The server may assign a full JID with a username and resource different than
+ * the requested by this method.
+ *
+ * It is recommended that @{link #authenticate(String, String, CallbackHandler)} be used instead
+ * since it provides greater flexability in authenticaiton and authorization.
+ *
+ * @param username the username that is authenticating with the server.
+ * @param password the password to send to the server.
+ * @param resource the desired resource.
+ * @return the full JID provided by the server while binding a resource for the connection.
+ * @throws XMPPException if an error occures while authenticating.
+ */
+ String authenticate(String username, String password, String resource) throws
+ XMPPException;
+
+ /**
+ * Performs an anonymous authentication with the server. The server will created a new full JID
+ * for this connection. An exception will be thrown if the server does not support anonymous
+ * authentication.
+ *
+ * @return the full JID provided by the server while binding a resource for the connection.
+ * @throws XMPPException if an error occures while authenticating.
+ */
+ String authenticateAnonymously() throws XMPPException;
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/filter/IQTypeFilter.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/filter/IQTypeFilter.java
index dbab1c3af..efe600307 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/filter/IQTypeFilter.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/filter/IQTypeFilter.java
@@ -1,48 +1,48 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filter;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-
-/**
- * A filter for IQ packet types. Returns true only if the packet is an IQ packet
- * and it matches the type provided in the constructor.
- *
- * @author Alexander Wenckus
- *
- */
-public class IQTypeFilter implements PacketFilter {
-
- private IQ.Type type;
-
- public IQTypeFilter(IQ.Type type) {
- this.type = type;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.jivesoftware.smack.filter.PacketFilter#accept(org.jivesoftware.smack.packet.Packet)
- */
- public boolean accept(Packet packet) {
- return (packet instanceof IQ && ((IQ) packet).getType().equals(type));
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filter;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+
+/**
+ * A filter for IQ packet types. Returns true only if the packet is an IQ packet
+ * and it matches the type provided in the constructor.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+public class IQTypeFilter implements PacketFilter {
+
+ private IQ.Type type;
+
+ public IQTypeFilter(IQ.Type type) {
+ this.type = type;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.filter.PacketFilter#accept(org.jivesoftware.smack.packet.Packet)
+ */
+ public boolean accept(Packet packet) {
+ return (packet instanceof IQ && ((IQ) packet).getType().equals(type));
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Bind.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Bind.java
index 07cd1934e..fa150147f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Bind.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Bind.java
@@ -1,71 +1,71 @@
-/**
- * $RCSfile$
- * $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
- *
- * 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.packet;
-
-/**
- * IQ packet used by Smack to bind a resource and to obtain the jid assigned by the server.
- * There are two ways to bind a resource. One is simply sending an empty Bind packet where the
- * server will assign a new resource for this connection. The other option is to set a desired
- * resource but the server may return a modified version of the sent resource.<p>
- *
- * For more information refer to the following
- * <a href=http://www.xmpp.org/specs/rfc3920.html#bind>link</a>.
- *
- * @author Gaston Dombiak
- */
-public class Bind extends IQ {
-
- private String resource = null;
- private String jid = null;
-
- public Bind() {
- setType(IQ.Type.SET);
- }
-
- public String getResource() {
- return resource;
- }
-
- public void setResource(String resource) {
- this.resource = resource;
- }
-
- public String getJid() {
- return jid;
- }
-
- public void setJid(String jid) {
- this.jid = jid;
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">");
- if (resource != null) {
- buf.append("<resource>").append(resource).append("</resource>");
- }
- if (jid != null) {
- buf.append("<jid>").append(jid).append("</jid>");
- }
- buf.append("</bind>");
- return buf.toString();
- }
-}
+/**
+ * $RCSfile$
+ * $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
+ *
+ * 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.packet;
+
+/**
+ * IQ packet used by Smack to bind a resource and to obtain the jid assigned by the server.
+ * There are two ways to bind a resource. One is simply sending an empty Bind packet where the
+ * server will assign a new resource for this connection. The other option is to set a desired
+ * resource but the server may return a modified version of the sent resource.<p>
+ *
+ * For more information refer to the following
+ * <a href=http://www.xmpp.org/specs/rfc3920.html#bind>link</a>.
+ *
+ * @author Gaston Dombiak
+ */
+public class Bind extends IQ {
+
+ private String resource = null;
+ private String jid = null;
+
+ public Bind() {
+ setType(IQ.Type.SET);
+ }
+
+ public String getResource() {
+ return resource;
+ }
+
+ public void setResource(String resource) {
+ this.resource = resource;
+ }
+
+ public String getJid() {
+ return jid;
+ }
+
+ public void setJid(String jid) {
+ this.jid = jid;
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">");
+ if (resource != null) {
+ buf.append("<resource>").append(resource).append("</resource>");
+ }
+ if (jid != null) {
+ buf.append("<jid>").append(jid).append("</jid>");
+ }
+ buf.append("</bind>");
+ return buf.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Privacy.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Privacy.java
index a62d578a8..3af6c4b72 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Privacy.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Privacy.java
@@ -1,323 +1,323 @@
-/**
- * $Revision$
- * $Date$
- *
- * Copyright 2006-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
- *
- * 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.packet;
-
-import java.util.*;
-
-/**
- * A Privacy IQ Packet, is used by the {@link org.jivesoftware.smack.PrivacyListManager}
- * and {@link org.jivesoftware.smack.provider.PrivacyProvider} to allow and block
- * communications from other users. It contains the appropriate structure to suit
- * user-defined privacy lists. Different configured Privacy packages are used in the
- * server & manager communication in order to:
- * <ul>
- * <li>Retrieving one's privacy lists.
- * <li>Adding, removing, and editing one's privacy lists.
- * <li>Setting, changing, or declining active lists.
- * <li>Setting, changing, or declining the default list (i.e., the list that is active by default).
- * </ul>
- * Privacy Items can handle different kind of blocking communications based on JID, group,
- * subscription type or globally {@link PrivacyItem}
- *
- * @author Francisco Vives
- */
-public class Privacy extends IQ {
- /** declineActiveList is true when the user declines the use of the active list **/
- private boolean declineActiveList=false;
- /** activeName is the name associated with the active list set for the session **/
- private String activeName;
- /** declineDefaultList is true when the user declines the use of the default list **/
- private boolean declineDefaultList=false;
- /** defaultName is the name of the default list that applies to the user as a whole **/
- private String defaultName;
- /** itemLists holds the set of privacy items classified in lists. It is a map where the
- * key is the name of the list and the value a collection with privacy items. **/
- private Map<String, List<PrivacyItem>> itemLists = new HashMap<String, List<PrivacyItem>>();
-
- /**
- * Set or update a privacy list with privacy items.
- *
- * @param listName the name of the new privacy list.
- * @param listItem the {@link PrivacyItem} that rules the list.
- * @return the privacy List.
- */
- public List<PrivacyItem> setPrivacyList(String listName, List<PrivacyItem> listItem) {
- // Add new list to the itemLists
- this.getItemLists().put(listName, listItem);
- return listItem;
- }
-
- /**
- * Set the active list based on the default list.
- *
- * @return the active List.
- */
- public List<PrivacyItem> setActivePrivacyList() {
- this.setActiveName(this.getDefaultName());
- return this.getItemLists().get(this.getActiveName());
- }
-
- /**
- * Deletes an existing privacy list. If the privacy list being deleted was the default list
- * then the user will end up with no default list. Therefore, the user will have to set a new
- * default list.
- *
- * @param listName the name of the list being deleted.
- */
- public void deletePrivacyList(String listName) {
- // Remove the list from the cache
- this.getItemLists().remove(listName);
-
- // Check if deleted list was the default list
- if (this.getDefaultName() != null && listName.equals(this.getDefaultName())) {
- this.setDefaultName(null);
- }
- }
-
- /**
- * Returns the active privacy list or <tt>null</tt> if none was found.
- *
- * @return list with {@link PrivacyItem} or <tt>null</tt> if none was found.
- */
- public List<PrivacyItem> getActivePrivacyList() {
- // Check if we have the default list
- if (this.getActiveName() == null) {
- return null;
- } else {
- return this.getItemLists().get(this.getActiveName());
- }
- }
-
- /**
- * Returns the default privacy list or <tt>null</tt> if none was found.
- *
- * @return list with {@link PrivacyItem} or <tt>null</tt> if none was found.
- */
- public List<PrivacyItem> getDefaultPrivacyList() {
- // Check if we have the default list
- if (this.getDefaultName() == null) {
- return null;
- } else {
- return this.getItemLists().get(this.getDefaultName());
- }
- }
-
- /**
- * Returns a specific privacy list.
- *
- * @param listName the name of the list to get.
- * @return a List with {@link PrivacyItem}
- */
- public List<PrivacyItem> getPrivacyList(String listName) {
- return this.getItemLists().get(listName);
- }
-
- /**
- * Returns the privacy item in the specified order.
- *
- * @param listName the name of the privacy list.
- * @param order the order of the element.
- * @return a List with {@link PrivacyItem}
- */
- public PrivacyItem getItem(String listName, int order) {
- Iterator<PrivacyItem> values = getPrivacyList(listName).iterator();
- PrivacyItem itemFound = null;
- while (itemFound == null && values.hasNext()) {
- PrivacyItem element = values.next();
- if (element.getOrder() == order) {
- itemFound = element;
- }
- }
- return itemFound;
- }
-
- /**
- * Sets a given privacy list as the new user default list.
- *
- * @param newDefault the new default privacy list.
- * @return if the default list was changed.
- */
- public boolean changeDefaultList(String newDefault) {
- if (this.getItemLists().containsKey(newDefault)) {
- this.setDefaultName(newDefault);
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Remove the list.
- *
- * @param listName name of the list to remove.
- */
- public void deleteList(String listName) {
- this.getItemLists().remove(listName);
- }
-
- /**
- * Returns the name associated with the active list set for the session. Communications
- * will be verified against the active list.
- *
- * @return the name of the active list.
- */
- public String getActiveName() {
- return activeName;
- }
-
- /**
- * Sets the name associated with the active list set for the session. Communications
- * will be verified against the active list.
- *
- * @param activeName is the name of the active list.
- */
- public void setActiveName(String activeName) {
- this.activeName = activeName;
- }
-
- /**
- * Returns the name of the default list that applies to the user as a whole. Default list is
- * processed if there is no active list set for the target session/resource to which a stanza
- * is addressed, or if there are no current sessions for the user.
- *
- * @return the name of the default list.
- */
- public String getDefaultName() {
- return defaultName;
- }
-
- /**
- * Sets the name of the default list that applies to the user as a whole. Default list is
- * processed if there is no active list set for the target session/resource to which a stanza
- * is addressed, or if there are no current sessions for the user.
- *
- * If there is no default list set, then all Privacy Items are processed.
- *
- * @param defaultName is the name of the default list.
- */
- public void setDefaultName(String defaultName) {
- this.defaultName = defaultName;
- }
-
- /**
- * Returns the collection of privacy list that the user holds. A Privacy List contains a set of
- * rules that define if communication with the list owner is allowed or denied.
- * Users may have zero, one or more privacy items.
- *
- * @return a map where the key is the name of the list and the value the
- * collection of privacy items.
- */
- public Map<String, List<PrivacyItem>> getItemLists() {
- return itemLists;
- }
-
- /**
- * Returns whether the receiver allows or declines the use of an active list.
- *
- * @return the decline status of the list.
- */
- public boolean isDeclineActiveList() {
- return declineActiveList;
- }
-
- /**
- * Sets whether the receiver allows or declines the use of an active list.
- *
- * @param declineActiveList indicates if the receiver declines the use of an active list.
- */
- public void setDeclineActiveList(boolean declineActiveList) {
- this.declineActiveList = declineActiveList;
- }
-
- /**
- * Returns whether the receiver allows or declines the use of a default list.
- *
- * @return the decline status of the list.
- */
- public boolean isDeclineDefaultList() {
- return declineDefaultList;
- }
-
- /**
- * Sets whether the receiver allows or declines the use of a default list.
- *
- * @param declineDefaultList indicates if the receiver declines the use of a default list.
- */
- public void setDeclineDefaultList(boolean declineDefaultList) {
- this.declineDefaultList = declineDefaultList;
- }
-
- /**
- * Returns all the list names the user has defined to group restrictions.
- *
- * @return a Set with Strings containing every list names.
- */
- public Set<String> getPrivacyListNames() {
- return this.itemLists.keySet();
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<query xmlns=\"jabber:iq:privacy\">");
-
- // Add the active tag
- if (this.isDeclineActiveList()) {
- buf.append("<active/>");
- } else {
- if (this.getActiveName() != null) {
- buf.append("<active name=\"").append(this.getActiveName()).append("\"/>");
- }
- }
- // Add the default tag
- if (this.isDeclineDefaultList()) {
- buf.append("<default/>");
- } else {
- if (this.getDefaultName() != null) {
- buf.append("<default name=\"").append(this.getDefaultName()).append("\"/>");
- }
- }
-
- // Add the list with their privacy items
- for (Map.Entry<String, List<PrivacyItem>> entry : this.getItemLists().entrySet()) {
- String listName = entry.getKey();
- List<PrivacyItem> items = entry.getValue();
- // Begin the list tag
- if (items.isEmpty()) {
- buf.append("<list name=\"").append(listName).append("\"/>");
- } else {
- buf.append("<list name=\"").append(listName).append("\">");
- }
- for (PrivacyItem item : items) {
- // Append the item xml representation
- buf.append(item.toXML());
- }
- // Close the list tag
- if (!items.isEmpty()) {
- buf.append("</list>");
- }
- }
-
- // Add packet extensions, if any are defined.
- buf.append(getExtensionsXML());
- buf.append("</query>");
- return buf.toString();
- }
-
+/**
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2006-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
+ *
+ * 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.packet;
+
+import java.util.*;
+
+/**
+ * A Privacy IQ Packet, is used by the {@link org.jivesoftware.smack.PrivacyListManager}
+ * and {@link org.jivesoftware.smack.provider.PrivacyProvider} to allow and block
+ * communications from other users. It contains the appropriate structure to suit
+ * user-defined privacy lists. Different configured Privacy packages are used in the
+ * server & manager communication in order to:
+ * <ul>
+ * <li>Retrieving one's privacy lists.
+ * <li>Adding, removing, and editing one's privacy lists.
+ * <li>Setting, changing, or declining active lists.
+ * <li>Setting, changing, or declining the default list (i.e., the list that is active by default).
+ * </ul>
+ * Privacy Items can handle different kind of blocking communications based on JID, group,
+ * subscription type or globally {@link PrivacyItem}
+ *
+ * @author Francisco Vives
+ */
+public class Privacy extends IQ {
+ /** declineActiveList is true when the user declines the use of the active list **/
+ private boolean declineActiveList=false;
+ /** activeName is the name associated with the active list set for the session **/
+ private String activeName;
+ /** declineDefaultList is true when the user declines the use of the default list **/
+ private boolean declineDefaultList=false;
+ /** defaultName is the name of the default list that applies to the user as a whole **/
+ private String defaultName;
+ /** itemLists holds the set of privacy items classified in lists. It is a map where the
+ * key is the name of the list and the value a collection with privacy items. **/
+ private Map<String, List<PrivacyItem>> itemLists = new HashMap<String, List<PrivacyItem>>();
+
+ /**
+ * Set or update a privacy list with privacy items.
+ *
+ * @param listName the name of the new privacy list.
+ * @param listItem the {@link PrivacyItem} that rules the list.
+ * @return the privacy List.
+ */
+ public List<PrivacyItem> setPrivacyList(String listName, List<PrivacyItem> listItem) {
+ // Add new list to the itemLists
+ this.getItemLists().put(listName, listItem);
+ return listItem;
+ }
+
+ /**
+ * Set the active list based on the default list.
+ *
+ * @return the active List.
+ */
+ public List<PrivacyItem> setActivePrivacyList() {
+ this.setActiveName(this.getDefaultName());
+ return this.getItemLists().get(this.getActiveName());
+ }
+
+ /**
+ * Deletes an existing privacy list. If the privacy list being deleted was the default list
+ * then the user will end up with no default list. Therefore, the user will have to set a new
+ * default list.
+ *
+ * @param listName the name of the list being deleted.
+ */
+ public void deletePrivacyList(String listName) {
+ // Remove the list from the cache
+ this.getItemLists().remove(listName);
+
+ // Check if deleted list was the default list
+ if (this.getDefaultName() != null && listName.equals(this.getDefaultName())) {
+ this.setDefaultName(null);
+ }
+ }
+
+ /**
+ * Returns the active privacy list or <tt>null</tt> if none was found.
+ *
+ * @return list with {@link PrivacyItem} or <tt>null</tt> if none was found.
+ */
+ public List<PrivacyItem> getActivePrivacyList() {
+ // Check if we have the default list
+ if (this.getActiveName() == null) {
+ return null;
+ } else {
+ return this.getItemLists().get(this.getActiveName());
+ }
+ }
+
+ /**
+ * Returns the default privacy list or <tt>null</tt> if none was found.
+ *
+ * @return list with {@link PrivacyItem} or <tt>null</tt> if none was found.
+ */
+ public List<PrivacyItem> getDefaultPrivacyList() {
+ // Check if we have the default list
+ if (this.getDefaultName() == null) {
+ return null;
+ } else {
+ return this.getItemLists().get(this.getDefaultName());
+ }
+ }
+
+ /**
+ * Returns a specific privacy list.
+ *
+ * @param listName the name of the list to get.
+ * @return a List with {@link PrivacyItem}
+ */
+ public List<PrivacyItem> getPrivacyList(String listName) {
+ return this.getItemLists().get(listName);
+ }
+
+ /**
+ * Returns the privacy item in the specified order.
+ *
+ * @param listName the name of the privacy list.
+ * @param order the order of the element.
+ * @return a List with {@link PrivacyItem}
+ */
+ public PrivacyItem getItem(String listName, int order) {
+ Iterator<PrivacyItem> values = getPrivacyList(listName).iterator();
+ PrivacyItem itemFound = null;
+ while (itemFound == null && values.hasNext()) {
+ PrivacyItem element = values.next();
+ if (element.getOrder() == order) {
+ itemFound = element;
+ }
+ }
+ return itemFound;
+ }
+
+ /**
+ * Sets a given privacy list as the new user default list.
+ *
+ * @param newDefault the new default privacy list.
+ * @return if the default list was changed.
+ */
+ public boolean changeDefaultList(String newDefault) {
+ if (this.getItemLists().containsKey(newDefault)) {
+ this.setDefaultName(newDefault);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Remove the list.
+ *
+ * @param listName name of the list to remove.
+ */
+ public void deleteList(String listName) {
+ this.getItemLists().remove(listName);
+ }
+
+ /**
+ * Returns the name associated with the active list set for the session. Communications
+ * will be verified against the active list.
+ *
+ * @return the name of the active list.
+ */
+ public String getActiveName() {
+ return activeName;
+ }
+
+ /**
+ * Sets the name associated with the active list set for the session. Communications
+ * will be verified against the active list.
+ *
+ * @param activeName is the name of the active list.
+ */
+ public void setActiveName(String activeName) {
+ this.activeName = activeName;
+ }
+
+ /**
+ * Returns the name of the default list that applies to the user as a whole. Default list is
+ * processed if there is no active list set for the target session/resource to which a stanza
+ * is addressed, or if there are no current sessions for the user.
+ *
+ * @return the name of the default list.
+ */
+ public String getDefaultName() {
+ return defaultName;
+ }
+
+ /**
+ * Sets the name of the default list that applies to the user as a whole. Default list is
+ * processed if there is no active list set for the target session/resource to which a stanza
+ * is addressed, or if there are no current sessions for the user.
+ *
+ * If there is no default list set, then all Privacy Items are processed.
+ *
+ * @param defaultName is the name of the default list.
+ */
+ public void setDefaultName(String defaultName) {
+ this.defaultName = defaultName;
+ }
+
+ /**
+ * Returns the collection of privacy list that the user holds. A Privacy List contains a set of
+ * rules that define if communication with the list owner is allowed or denied.
+ * Users may have zero, one or more privacy items.
+ *
+ * @return a map where the key is the name of the list and the value the
+ * collection of privacy items.
+ */
+ public Map<String, List<PrivacyItem>> getItemLists() {
+ return itemLists;
+ }
+
+ /**
+ * Returns whether the receiver allows or declines the use of an active list.
+ *
+ * @return the decline status of the list.
+ */
+ public boolean isDeclineActiveList() {
+ return declineActiveList;
+ }
+
+ /**
+ * Sets whether the receiver allows or declines the use of an active list.
+ *
+ * @param declineActiveList indicates if the receiver declines the use of an active list.
+ */
+ public void setDeclineActiveList(boolean declineActiveList) {
+ this.declineActiveList = declineActiveList;
+ }
+
+ /**
+ * Returns whether the receiver allows or declines the use of a default list.
+ *
+ * @return the decline status of the list.
+ */
+ public boolean isDeclineDefaultList() {
+ return declineDefaultList;
+ }
+
+ /**
+ * Sets whether the receiver allows or declines the use of a default list.
+ *
+ * @param declineDefaultList indicates if the receiver declines the use of a default list.
+ */
+ public void setDeclineDefaultList(boolean declineDefaultList) {
+ this.declineDefaultList = declineDefaultList;
+ }
+
+ /**
+ * Returns all the list names the user has defined to group restrictions.
+ *
+ * @return a Set with Strings containing every list names.
+ */
+ public Set<String> getPrivacyListNames() {
+ return this.itemLists.keySet();
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<query xmlns=\"jabber:iq:privacy\">");
+
+ // Add the active tag
+ if (this.isDeclineActiveList()) {
+ buf.append("<active/>");
+ } else {
+ if (this.getActiveName() != null) {
+ buf.append("<active name=\"").append(this.getActiveName()).append("\"/>");
+ }
+ }
+ // Add the default tag
+ if (this.isDeclineDefaultList()) {
+ buf.append("<default/>");
+ } else {
+ if (this.getDefaultName() != null) {
+ buf.append("<default name=\"").append(this.getDefaultName()).append("\"/>");
+ }
+ }
+
+ // Add the list with their privacy items
+ for (Map.Entry<String, List<PrivacyItem>> entry : this.getItemLists().entrySet()) {
+ String listName = entry.getKey();
+ List<PrivacyItem> items = entry.getValue();
+ // Begin the list tag
+ if (items.isEmpty()) {
+ buf.append("<list name=\"").append(listName).append("\"/>");
+ } else {
+ buf.append("<list name=\"").append(listName).append("\">");
+ }
+ for (PrivacyItem item : items) {
+ // Append the item xml representation
+ buf.append(item.toXML());
+ }
+ // Close the list tag
+ if (!items.isEmpty()) {
+ buf.append("</list>");
+ }
+ }
+
+ // Add packet extensions, if any are defined.
+ buf.append(getExtensionsXML());
+ buf.append("</query>");
+ return buf.toString();
+ }
+
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/PrivacyItem.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/PrivacyItem.java
index 2e144eec6..e108f6897 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/PrivacyItem.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/PrivacyItem.java
@@ -15,448 +15,448 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smack.packet;
-
-/**
- * A privacy item acts a rule that when matched defines if a packet should be blocked or not.
- *
- * Privacy Items can handle different kind of blocking communications based on JID, group,
- * subscription type or globally by:<ul>
- * <li>Allowing or blocking messages.
- * <li>Allowing or blocking inbound presence notifications.
- * <li>Allowing or blocking outbound presence notifications.
- * <li>Allowing or blocking IQ stanzas.
- * <li>Allowing or blocking all communications.
- * </ul>
- * @author Francisco Vives
- */
-public class PrivacyItem {
- /** allow is the action associated with the item, it can allow or deny the communication. */
- private boolean allow;
- /** order is a non-negative integer that is unique among all items in the list. */
- private int order;
- /** rule hold the kind of communication ([jid|group|subscription]) it will allow or block and
- * identifier to apply the action.
- * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
- * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
- * in the user's roster.
- * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
- * "from", or "none". */
- private PrivacyRule rule;
-
- /** blocks incoming IQ stanzas. */
- private boolean filterIQ = false;
- /** filterMessage blocks incoming message stanzas. */
- private boolean filterMessage = false;
- /** blocks incoming presence notifications. */
- private boolean filterPresence_in = false;
- /** blocks outgoing presence notifications. */
- private boolean filterPresence_out = false;
-
- /**
- * Creates a new privacy item.
- *
- * @param type the type.
- */
- public PrivacyItem(String type, boolean allow, int order) {
- this.setRule(PrivacyRule.fromString(type));
- this.setAllow(allow);
- this.setOrder(order);
- }
-
- /**
- * Returns the action associated with the item, it MUST be filled and will allow or deny
- * the communication.
- *
- * @return the allow communication status.
- */
- public boolean isAllow() {
- return allow;
- }
-
- /**
- * Sets the action associated with the item, it can allow or deny the communication.
- *
- * @param allow indicates if the receiver allow or deny the communication.
- */
- private void setAllow(boolean allow) {
- this.allow = allow;
- }
-
-
- /**
- * Returns whether the receiver allow or deny incoming IQ stanzas or not.
- *
- * @return the iq filtering status.
- */
- public boolean isFilterIQ() {
- return filterIQ;
- }
-
-
- /**
- * Sets whether the receiver allows or denies incoming IQ stanzas or not.
- *
- * @param filterIQ indicates if the receiver allows or denies incoming IQ stanzas.
- */
- public void setFilterIQ(boolean filterIQ) {
- this.filterIQ = filterIQ;
- }
-
-
- /**
- * Returns whether the receiver allows or denies incoming messages or not.
- *
- * @return the message filtering status.
- */
- public boolean isFilterMessage() {
- return filterMessage;
- }
-
-
- /**
- * Sets wheather the receiver allows or denies incoming messages or not.
- *
- * @param filterMessage indicates if the receiver allows or denies incoming messages or not.
- */
- public void setFilterMessage(boolean filterMessage) {
- this.filterMessage = filterMessage;
- }
-
-
- /**
- * Returns whether the receiver allows or denies incoming presence or not.
- *
- * @return the iq filtering incoming presence status.
- */
- public boolean isFilterPresence_in() {
- return filterPresence_in;
- }
-
-
- /**
- * Sets whether the receiver allows or denies incoming presence or not.
- *
- * @param filterPresence_in indicates if the receiver allows or denies filtering incoming presence.
- */
- public void setFilterPresence_in(boolean filterPresence_in) {
- this.filterPresence_in = filterPresence_in;
- }
-
-
- /**
- * Returns whether the receiver allows or denies incoming presence or not.
- *
- * @return the iq filtering incoming presence status.
- */
- public boolean isFilterPresence_out() {
- return filterPresence_out;
- }
-
-
- /**
- * Sets whether the receiver allows or denies outgoing presence or not.
- *
- * @param filterPresence_out indicates if the receiver allows or denies filtering outgoing presence
- */
- public void setFilterPresence_out(boolean filterPresence_out) {
- this.filterPresence_out = filterPresence_out;
- }
-
-
- /**
- * Returns the order where the receiver is processed. List items are processed in
- * ascending order.
- *
- * The order MUST be filled and its value MUST be a non-negative integer
- * that is unique among all items in the list.
- *
- * @return the order number.
- */
- public int getOrder() {
- return order;
- }
-
-
- /**
- * Sets the order where the receiver is processed.
- *
- * The order MUST be filled and its value MUST be a non-negative integer
- * that is unique among all items in the list.
- *
- * @param order indicates the order in the list.
- */
- public void setOrder(int order) {
- this.order = order;
- }
-
- /**
- * Sets the element identifier to apply the action.
- *
- * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
- * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
- * in the user's roster.
- * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
- * "from", or "none".
- *
- * @param value is the identifier to apply the action.
- */
- public void setValue(String value) {
- if (!(this.getRule() == null && value == null)) {
- this.getRule().setValue(value);
- }
- }
-
- /**
- * Returns the type hold the kind of communication it will allow or block.
- * It MUST be filled with one of these values: jid, group or subscription.
- *
- * @return the type of communication it represent.
- */
- public Type getType() {
- if (this.getRule() == null) {
- return null;
- } else {
- return this.getRule().getType();
- }
- }
-
- /**
- * Returns the element identifier to apply the action.
- *
- * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
- * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
- * in the user's roster.
- * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
- * "from", or "none".
- *
- * @return the identifier to apply the action.
- */
- public String getValue() {
- if (this.getRule() == null) {
- return null;
- } else {
- return this.getRule().getValue();
- }
- }
-
-
- /**
- * Returns whether the receiver allows or denies every kind of communication.
- *
- * When filterIQ, filterMessage, filterPresence_in and filterPresence_out are not set
- * the receiver will block all communications.
- *
- * @return the all communications status.
- */
- public boolean isFilterEverything() {
- return !(this.isFilterIQ() || this.isFilterMessage() || this.isFilterPresence_in()
- || this.isFilterPresence_out());
- }
-
-
- private PrivacyRule getRule() {
- return rule;
- }
-
- private void setRule(PrivacyRule rule) {
- this.rule = rule;
- }
- /**
- * Answer an xml representation of the receiver according to the RFC 3921.
- *
- * @return the text xml representation.
- */
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<item");
- if (this.isAllow()) {
- buf.append(" action=\"allow\"");
- } else {
- buf.append(" action=\"deny\"");
- }
- buf.append(" order=\"").append(getOrder()).append("\"");
- if (getType() != null) {
- buf.append(" type=\"").append(getType()).append("\"");
- }
- if (getValue() != null) {
- buf.append(" value=\"").append(getValue()).append("\"");
- }
- if (isFilterEverything()) {
- buf.append("/>");
- } else {
- buf.append(">");
- if (this.isFilterIQ()) {
- buf.append("<iq/>");
- }
- if (this.isFilterMessage()) {
- buf.append("<message/>");
- }
- if (this.isFilterPresence_in()) {
- buf.append("<presence-in/>");
- }
- if (this.isFilterPresence_out()) {
- buf.append("<presence-out/>");
- }
- buf.append("</item>");
- }
- return buf.toString();
- }
-
-
- /**
- * Privacy Rule represents the kind of action to apply.
- * It holds the kind of communication ([jid|group|subscription]) it will allow or block and
- * identifier to apply the action.
- */
-
- public static class PrivacyRule {
- /**
- * Type defines if the rule is based on JIDs, roster groups or presence subscription types.
- * Available values are: [jid|group|subscription]
- */
- private Type type;
- /**
- * The value hold the element identifier to apply the action.
- * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
- * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
- * in the user's roster.
- * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
- * "from", or "none".
- */
- private String value;
-
- /**
- * If the type is "subscription", then the 'value' attribute MUST be one of "both",
- * "to", "from", or "none"
- */
- public static final String SUBSCRIPTION_BOTH = "both";
- public static final String SUBSCRIPTION_TO = "to";
- public static final String SUBSCRIPTION_FROM = "from";
- public static final String SUBSCRIPTION_NONE = "none";
-
- /**
- * Returns the type constant associated with the String value.
- */
- protected static PrivacyRule fromString(String value) {
- if (value == null) {
- return null;
- }
- PrivacyRule rule = new PrivacyRule();
- rule.setType(Type.valueOf(value.toLowerCase()));
- return rule;
- }
-
- /**
- * Returns the type hold the kind of communication it will allow or block.
- * It MUST be filled with one of these values: jid, group or subscription.
- *
- * @return the type of communication it represent.
- */
- public Type getType() {
- return type;
- }
-
- /**
- * Sets the action associated with the item, it can allow or deny the communication.
- *
- * @param type indicates if the receiver allows or denies the communication.
- */
- private void setType(Type type) {
- this.type = type;
- }
-
- /**
- * Returns the element identifier to apply the action.
- *
- * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
- * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
- * in the user's roster.
- * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
- * "from", or "none".
- *
- * @return the identifier to apply the action.
- */
- public String getValue() {
- return value;
- }
-
- /**
- * Sets the element identifier to apply the action.
- *
- * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
- * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
- * in the user's roster.
- * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
- * "from", or "none".
- *
- * @param value is the identifier to apply the action.
- */
- protected void setValue(String value) {
- if (this.isSuscription()) {
- setSuscriptionValue(value);
- } else {
- this.value = value;
- }
- }
-
- /**
- * Sets the element identifier to apply the action.
- *
- * The 'value' attribute MUST be one of "both", "to", "from", or "none".
- *
- * @param value is the identifier to apply the action.
- */
- private void setSuscriptionValue(String value) {
- String setValue;
- if (value == null) {
- // Do nothing
- }
- if (SUBSCRIPTION_BOTH.equalsIgnoreCase(value)) {
- setValue = SUBSCRIPTION_BOTH;
- }
- else if (SUBSCRIPTION_TO.equalsIgnoreCase(value)) {
- setValue = SUBSCRIPTION_TO;
- }
- else if (SUBSCRIPTION_FROM.equalsIgnoreCase(value)) {
- setValue = SUBSCRIPTION_FROM;
- }
- else if (SUBSCRIPTION_NONE.equalsIgnoreCase(value)) {
- setValue = SUBSCRIPTION_NONE;
- }
- // Default to available.
- else {
- setValue = null;
- }
- this.value = setValue;
- }
-
- /**
- * Returns if the receiver represents a subscription rule.
- *
- * @return if the receiver represents a subscription rule.
- */
- public boolean isSuscription () {
- return this.getType() == Type.subscription;
- }
- }
-
- /**
- * Type defines if the rule is based on JIDs, roster groups or presence subscription types.
- */
- public static enum Type {
- /**
- * JID being analyzed should belong to a roster group of the list's owner.
- */
- group,
- /**
- * JID being analyzed should have a resource match, domain match or bare JID match.
- */
- jid,
- /**
- * JID being analyzed should belong to a contact present in the owner's roster with
- * the specified subscription status.
- */
- subscription
- }
-}
+package org.jivesoftware.smack.packet;
+
+/**
+ * A privacy item acts a rule that when matched defines if a packet should be blocked or not.
+ *
+ * Privacy Items can handle different kind of blocking communications based on JID, group,
+ * subscription type or globally by:<ul>
+ * <li>Allowing or blocking messages.
+ * <li>Allowing or blocking inbound presence notifications.
+ * <li>Allowing or blocking outbound presence notifications.
+ * <li>Allowing or blocking IQ stanzas.
+ * <li>Allowing or blocking all communications.
+ * </ul>
+ * @author Francisco Vives
+ */
+public class PrivacyItem {
+ /** allow is the action associated with the item, it can allow or deny the communication. */
+ private boolean allow;
+ /** order is a non-negative integer that is unique among all items in the list. */
+ private int order;
+ /** rule hold the kind of communication ([jid|group|subscription]) it will allow or block and
+ * identifier to apply the action.
+ * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
+ * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
+ * in the user's roster.
+ * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
+ * "from", or "none". */
+ private PrivacyRule rule;
+
+ /** blocks incoming IQ stanzas. */
+ private boolean filterIQ = false;
+ /** filterMessage blocks incoming message stanzas. */
+ private boolean filterMessage = false;
+ /** blocks incoming presence notifications. */
+ private boolean filterPresence_in = false;
+ /** blocks outgoing presence notifications. */
+ private boolean filterPresence_out = false;
+
+ /**
+ * Creates a new privacy item.
+ *
+ * @param type the type.
+ */
+ public PrivacyItem(String type, boolean allow, int order) {
+ this.setRule(PrivacyRule.fromString(type));
+ this.setAllow(allow);
+ this.setOrder(order);
+ }
+
+ /**
+ * Returns the action associated with the item, it MUST be filled and will allow or deny
+ * the communication.
+ *
+ * @return the allow communication status.
+ */
+ public boolean isAllow() {
+ return allow;
+ }
+
+ /**
+ * Sets the action associated with the item, it can allow or deny the communication.
+ *
+ * @param allow indicates if the receiver allow or deny the communication.
+ */
+ private void setAllow(boolean allow) {
+ this.allow = allow;
+ }
+
+
+ /**
+ * Returns whether the receiver allow or deny incoming IQ stanzas or not.
+ *
+ * @return the iq filtering status.
+ */
+ public boolean isFilterIQ() {
+ return filterIQ;
+ }
+
+
+ /**
+ * Sets whether the receiver allows or denies incoming IQ stanzas or not.
+ *
+ * @param filterIQ indicates if the receiver allows or denies incoming IQ stanzas.
+ */
+ public void setFilterIQ(boolean filterIQ) {
+ this.filterIQ = filterIQ;
+ }
+
+
+ /**
+ * Returns whether the receiver allows or denies incoming messages or not.
+ *
+ * @return the message filtering status.
+ */
+ public boolean isFilterMessage() {
+ return filterMessage;
+ }
+
+
+ /**
+ * Sets wheather the receiver allows or denies incoming messages or not.
+ *
+ * @param filterMessage indicates if the receiver allows or denies incoming messages or not.
+ */
+ public void setFilterMessage(boolean filterMessage) {
+ this.filterMessage = filterMessage;
+ }
+
+
+ /**
+ * Returns whether the receiver allows or denies incoming presence or not.
+ *
+ * @return the iq filtering incoming presence status.
+ */
+ public boolean isFilterPresence_in() {
+ return filterPresence_in;
+ }
+
+
+ /**
+ * Sets whether the receiver allows or denies incoming presence or not.
+ *
+ * @param filterPresence_in indicates if the receiver allows or denies filtering incoming presence.
+ */
+ public void setFilterPresence_in(boolean filterPresence_in) {
+ this.filterPresence_in = filterPresence_in;
+ }
+
+
+ /**
+ * Returns whether the receiver allows or denies incoming presence or not.
+ *
+ * @return the iq filtering incoming presence status.
+ */
+ public boolean isFilterPresence_out() {
+ return filterPresence_out;
+ }
+
+
+ /**
+ * Sets whether the receiver allows or denies outgoing presence or not.
+ *
+ * @param filterPresence_out indicates if the receiver allows or denies filtering outgoing presence
+ */
+ public void setFilterPresence_out(boolean filterPresence_out) {
+ this.filterPresence_out = filterPresence_out;
+ }
+
+
+ /**
+ * Returns the order where the receiver is processed. List items are processed in
+ * ascending order.
+ *
+ * The order MUST be filled and its value MUST be a non-negative integer
+ * that is unique among all items in the list.
+ *
+ * @return the order number.
+ */
+ public int getOrder() {
+ return order;
+ }
+
+
+ /**
+ * Sets the order where the receiver is processed.
+ *
+ * The order MUST be filled and its value MUST be a non-negative integer
+ * that is unique among all items in the list.
+ *
+ * @param order indicates the order in the list.
+ */
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ /**
+ * Sets the element identifier to apply the action.
+ *
+ * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
+ * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
+ * in the user's roster.
+ * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
+ * "from", or "none".
+ *
+ * @param value is the identifier to apply the action.
+ */
+ public void setValue(String value) {
+ if (!(this.getRule() == null && value == null)) {
+ this.getRule().setValue(value);
+ }
+ }
+
+ /**
+ * Returns the type hold the kind of communication it will allow or block.
+ * It MUST be filled with one of these values: jid, group or subscription.
+ *
+ * @return the type of communication it represent.
+ */
+ public Type getType() {
+ if (this.getRule() == null) {
+ return null;
+ } else {
+ return this.getRule().getType();
+ }
+ }
+
+ /**
+ * Returns the element identifier to apply the action.
+ *
+ * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
+ * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
+ * in the user's roster.
+ * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
+ * "from", or "none".
+ *
+ * @return the identifier to apply the action.
+ */
+ public String getValue() {
+ if (this.getRule() == null) {
+ return null;
+ } else {
+ return this.getRule().getValue();
+ }
+ }
+
+
+ /**
+ * Returns whether the receiver allows or denies every kind of communication.
+ *
+ * When filterIQ, filterMessage, filterPresence_in and filterPresence_out are not set
+ * the receiver will block all communications.
+ *
+ * @return the all communications status.
+ */
+ public boolean isFilterEverything() {
+ return !(this.isFilterIQ() || this.isFilterMessage() || this.isFilterPresence_in()
+ || this.isFilterPresence_out());
+ }
+
+
+ private PrivacyRule getRule() {
+ return rule;
+ }
+
+ private void setRule(PrivacyRule rule) {
+ this.rule = rule;
+ }
+ /**
+ * Answer an xml representation of the receiver according to the RFC 3921.
+ *
+ * @return the text xml representation.
+ */
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<item");
+ if (this.isAllow()) {
+ buf.append(" action=\"allow\"");
+ } else {
+ buf.append(" action=\"deny\"");
+ }
+ buf.append(" order=\"").append(getOrder()).append("\"");
+ if (getType() != null) {
+ buf.append(" type=\"").append(getType()).append("\"");
+ }
+ if (getValue() != null) {
+ buf.append(" value=\"").append(getValue()).append("\"");
+ }
+ if (isFilterEverything()) {
+ buf.append("/>");
+ } else {
+ buf.append(">");
+ if (this.isFilterIQ()) {
+ buf.append("<iq/>");
+ }
+ if (this.isFilterMessage()) {
+ buf.append("<message/>");
+ }
+ if (this.isFilterPresence_in()) {
+ buf.append("<presence-in/>");
+ }
+ if (this.isFilterPresence_out()) {
+ buf.append("<presence-out/>");
+ }
+ buf.append("</item>");
+ }
+ return buf.toString();
+ }
+
+
+ /**
+ * Privacy Rule represents the kind of action to apply.
+ * It holds the kind of communication ([jid|group|subscription]) it will allow or block and
+ * identifier to apply the action.
+ */
+
+ public static class PrivacyRule {
+ /**
+ * Type defines if the rule is based on JIDs, roster groups or presence subscription types.
+ * Available values are: [jid|group|subscription]
+ */
+ private Type type;
+ /**
+ * The value hold the element identifier to apply the action.
+ * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
+ * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
+ * in the user's roster.
+ * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
+ * "from", or "none".
+ */
+ private String value;
+
+ /**
+ * If the type is "subscription", then the 'value' attribute MUST be one of "both",
+ * "to", "from", or "none"
+ */
+ public static final String SUBSCRIPTION_BOTH = "both";
+ public static final String SUBSCRIPTION_TO = "to";
+ public static final String SUBSCRIPTION_FROM = "from";
+ public static final String SUBSCRIPTION_NONE = "none";
+
+ /**
+ * Returns the type constant associated with the String value.
+ */
+ protected static PrivacyRule fromString(String value) {
+ if (value == null) {
+ return null;
+ }
+ PrivacyRule rule = new PrivacyRule();
+ rule.setType(Type.valueOf(value.toLowerCase()));
+ return rule;
+ }
+
+ /**
+ * Returns the type hold the kind of communication it will allow or block.
+ * It MUST be filled with one of these values: jid, group or subscription.
+ *
+ * @return the type of communication it represent.
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Sets the action associated with the item, it can allow or deny the communication.
+ *
+ * @param type indicates if the receiver allows or denies the communication.
+ */
+ private void setType(Type type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the element identifier to apply the action.
+ *
+ * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
+ * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
+ * in the user's roster.
+ * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
+ * "from", or "none".
+ *
+ * @return the identifier to apply the action.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the element identifier to apply the action.
+ *
+ * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
+ * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
+ * in the user's roster.
+ * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
+ * "from", or "none".
+ *
+ * @param value is the identifier to apply the action.
+ */
+ protected void setValue(String value) {
+ if (this.isSuscription()) {
+ setSuscriptionValue(value);
+ } else {
+ this.value = value;
+ }
+ }
+
+ /**
+ * Sets the element identifier to apply the action.
+ *
+ * The 'value' attribute MUST be one of "both", "to", "from", or "none".
+ *
+ * @param value is the identifier to apply the action.
+ */
+ private void setSuscriptionValue(String value) {
+ String setValue;
+ if (value == null) {
+ // Do nothing
+ }
+ if (SUBSCRIPTION_BOTH.equalsIgnoreCase(value)) {
+ setValue = SUBSCRIPTION_BOTH;
+ }
+ else if (SUBSCRIPTION_TO.equalsIgnoreCase(value)) {
+ setValue = SUBSCRIPTION_TO;
+ }
+ else if (SUBSCRIPTION_FROM.equalsIgnoreCase(value)) {
+ setValue = SUBSCRIPTION_FROM;
+ }
+ else if (SUBSCRIPTION_NONE.equalsIgnoreCase(value)) {
+ setValue = SUBSCRIPTION_NONE;
+ }
+ // Default to available.
+ else {
+ setValue = null;
+ }
+ this.value = setValue;
+ }
+
+ /**
+ * Returns if the receiver represents a subscription rule.
+ *
+ * @return if the receiver represents a subscription rule.
+ */
+ public boolean isSuscription () {
+ return this.getType() == Type.subscription;
+ }
+ }
+
+ /**
+ * Type defines if the rule is based on JIDs, roster groups or presence subscription types.
+ */
+ public static enum Type {
+ /**
+ * JID being analyzed should belong to a roster group of the list's owner.
+ */
+ group,
+ /**
+ * JID being analyzed should have a resource match, domain match or bare JID match.
+ */
+ jid,
+ /**
+ * JID being analyzed should belong to a contact present in the owner's roster with
+ * the specified subscription status.
+ */
+ subscription
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Session.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Session.java
index fd403ae20..427c01a2a 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Session.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/Session.java
@@ -1,45 +1,45 @@
-/**
- * $RCSfile$
- * $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
- *
- * 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.packet;
-
-/**
- * IQ packet that will be sent to the server to establish a session.<p>
- *
- * If a server supports sessions, it MUST include a <i>session</i> element in the
- * stream features it advertises to a client after the completion of stream authentication.
- * Upon being informed that session establishment is required by the server the client MUST
- * establish a session if it desires to engage in instant messaging and presence functionality.<p>
- *
- * For more information refer to the following
- * <a href=http://www.xmpp.org/specs/rfc3921.html#session>link</a>.
- *
- * @author Gaston Dombiak
- */
-public class Session extends IQ {
-
- public Session() {
- setType(IQ.Type.SET);
- }
-
- public String getChildElementXML() {
- return "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>";
- }
-}
+/**
+ * $RCSfile$
+ * $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
+ *
+ * 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.packet;
+
+/**
+ * IQ packet that will be sent to the server to establish a session.<p>
+ *
+ * If a server supports sessions, it MUST include a <i>session</i> element in the
+ * stream features it advertises to a client after the completion of stream authentication.
+ * Upon being informed that session establishment is required by the server the client MUST
+ * establish a session if it desires to engage in instant messaging and presence functionality.<p>
+ *
+ * For more information refer to the following
+ * <a href=http://www.xmpp.org/specs/rfc3921.html#session>link</a>.
+ *
+ * @author Gaston Dombiak
+ */
+public class Session extends IQ {
+
+ public Session() {
+ setType(IQ.Type.SET);
+ }
+
+ public String getChildElementXML() {
+ return "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/StreamError.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/StreamError.java
index 8bb4c75bc..72679a8df 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/StreamError.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/packet/StreamError.java
@@ -1,106 +1,106 @@
-/**
- * $Revision: 2408 $
- * $Date: 2004-11-02 20:53:30 -0300 (Tue, 02 Nov 2004) $
- *
- * Copyright 2003-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.
- * 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.packet;
-
-/**
- * Represents a stream error packet. Stream errors are unrecoverable errors where the server
- * will close the unrelying TCP connection after the stream error was sent to the client.
- * These is the list of stream errors as defined in the XMPP spec:<p>
- *
- * <table border=1>
- * <tr><td><b>Code</b></td><td><b>Description</b></td></tr>
- * <tr><td> bad-format </td><td> the entity has sent XML that cannot be processed </td></tr>
- * <tr><td> unsupported-encoding </td><td> the entity has sent a namespace prefix that is
- * unsupported </td></tr>
- * <tr><td> bad-namespace-prefix </td><td> Remote Server Timeout </td></tr>
- * <tr><td> conflict </td><td> the server is closing the active stream for this entity
- * because a new stream has been initiated that conflicts with the existing
- * stream. </td></tr>
- * <tr><td> connection-timeout </td><td> the entity has not generated any traffic over
- * the stream for some period of time. </td></tr>
- * <tr><td> host-gone </td><td> the value of the 'to' attribute provided by the initiating
- * entity in the stream header corresponds to a hostname that is no longer hosted by
- * the server. </td></tr>
- * <tr><td> host-unknown </td><td> the value of the 'to' attribute provided by the
- * initiating entity in the stream header does not correspond to a hostname that is
- * hosted by the server. </td></tr>
- * <tr><td> improper-addressing </td><td> a stanza sent between two servers lacks a 'to'
- * or 'from' attribute </td></tr>
- * <tr><td> internal-server-error </td><td> the server has experienced a
- * misconfiguration. </td></tr>
- * <tr><td> invalid-from </td><td> the JID or hostname provided in a 'from' address does
- * not match an authorized JID. </td></tr>
- * <tr><td> invalid-id </td><td> the stream ID or dialback ID is invalid or does not match
- * an ID previously provided. </td></tr>
- * <tr><td> invalid-namespace </td><td> the streams namespace name is invalid. </td></tr>
- * <tr><td> invalid-xml </td><td> the entity has sent invalid XML over the stream. </td></tr>
- * <tr><td> not-authorized </td><td> the entity has attempted to send data before the
- * stream has been authenticated </td></tr>
- * <tr><td> policy-violation </td><td> the entity has violated some local service
- * policy. </td></tr>
- * <tr><td> remote-connection-failed </td><td> Rthe server is unable to properly connect
- * to a remote entity. </td></tr>
- * <tr><td> resource-constraint </td><td> Rthe server lacks the system resources necessary
- * to service the stream. </td></tr>
- * <tr><td> restricted-xml </td><td> the entity has attempted to send restricted XML
- * features. </td></tr>
- * <tr><td> see-other-host </td><td> the server will not provide service to the initiating
- * entity but is redirecting traffic to another host. </td></tr>
- * <tr><td> system-shutdown </td><td> the server is being shut down and all active streams
- * are being closed. </td></tr>
- * <tr><td> undefined-condition </td><td> the error condition is not one of those defined
- * by the other conditions in this list. </td></tr>
- * <tr><td> unsupported-encoding </td><td> the initiating entity has encoded the stream in
- * an encoding that is not supported. </td></tr>
- * <tr><td> unsupported-stanza-type </td><td> the initiating entity has sent a first-level
- * child of the stream that is not supported. </td></tr>
- * <tr><td> unsupported-version </td><td> the value of the 'version' attribute provided by
- * the initiating entity in the stream header specifies a version of XMPP that is not
- * supported. </td></tr>
- * <tr><td> xml-not-well-formed </td><td> the initiating entity has sent XML that is
- * not well-formed. </td></tr>
- * </table>
- *
- * @author Gaston Dombiak
- */
-public class StreamError {
-
- private String code;
-
- public StreamError(String code) {
- super();
- this.code = code;
- }
-
- /**
- * Returns the error code.
- *
- * @return the error code.
- */
- public String getCode() {
- return code;
- }
-
- public String toString() {
- StringBuilder txt = new StringBuilder();
- txt.append("stream:error (").append(code).append(")");
- return txt.toString();
- }
-}
+/**
+ * $Revision: 2408 $
+ * $Date: 2004-11-02 20:53:30 -0300 (Tue, 02 Nov 2004) $
+ *
+ * Copyright 2003-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.
+ * 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.packet;
+
+/**
+ * Represents a stream error packet. Stream errors are unrecoverable errors where the server
+ * will close the unrelying TCP connection after the stream error was sent to the client.
+ * These is the list of stream errors as defined in the XMPP spec:<p>
+ *
+ * <table border=1>
+ * <tr><td><b>Code</b></td><td><b>Description</b></td></tr>
+ * <tr><td> bad-format </td><td> the entity has sent XML that cannot be processed </td></tr>
+ * <tr><td> unsupported-encoding </td><td> the entity has sent a namespace prefix that is
+ * unsupported </td></tr>
+ * <tr><td> bad-namespace-prefix </td><td> Remote Server Timeout </td></tr>
+ * <tr><td> conflict </td><td> the server is closing the active stream for this entity
+ * because a new stream has been initiated that conflicts with the existing
+ * stream. </td></tr>
+ * <tr><td> connection-timeout </td><td> the entity has not generated any traffic over
+ * the stream for some period of time. </td></tr>
+ * <tr><td> host-gone </td><td> the value of the 'to' attribute provided by the initiating
+ * entity in the stream header corresponds to a hostname that is no longer hosted by
+ * the server. </td></tr>
+ * <tr><td> host-unknown </td><td> the value of the 'to' attribute provided by the
+ * initiating entity in the stream header does not correspond to a hostname that is
+ * hosted by the server. </td></tr>
+ * <tr><td> improper-addressing </td><td> a stanza sent between two servers lacks a 'to'
+ * or 'from' attribute </td></tr>
+ * <tr><td> internal-server-error </td><td> the server has experienced a
+ * misconfiguration. </td></tr>
+ * <tr><td> invalid-from </td><td> the JID or hostname provided in a 'from' address does
+ * not match an authorized JID. </td></tr>
+ * <tr><td> invalid-id </td><td> the stream ID or dialback ID is invalid or does not match
+ * an ID previously provided. </td></tr>
+ * <tr><td> invalid-namespace </td><td> the streams namespace name is invalid. </td></tr>
+ * <tr><td> invalid-xml </td><td> the entity has sent invalid XML over the stream. </td></tr>
+ * <tr><td> not-authorized </td><td> the entity has attempted to send data before the
+ * stream has been authenticated </td></tr>
+ * <tr><td> policy-violation </td><td> the entity has violated some local service
+ * policy. </td></tr>
+ * <tr><td> remote-connection-failed </td><td> Rthe server is unable to properly connect
+ * to a remote entity. </td></tr>
+ * <tr><td> resource-constraint </td><td> Rthe server lacks the system resources necessary
+ * to service the stream. </td></tr>
+ * <tr><td> restricted-xml </td><td> the entity has attempted to send restricted XML
+ * features. </td></tr>
+ * <tr><td> see-other-host </td><td> the server will not provide service to the initiating
+ * entity but is redirecting traffic to another host. </td></tr>
+ * <tr><td> system-shutdown </td><td> the server is being shut down and all active streams
+ * are being closed. </td></tr>
+ * <tr><td> undefined-condition </td><td> the error condition is not one of those defined
+ * by the other conditions in this list. </td></tr>
+ * <tr><td> unsupported-encoding </td><td> the initiating entity has encoded the stream in
+ * an encoding that is not supported. </td></tr>
+ * <tr><td> unsupported-stanza-type </td><td> the initiating entity has sent a first-level
+ * child of the stream that is not supported. </td></tr>
+ * <tr><td> unsupported-version </td><td> the value of the 'version' attribute provided by
+ * the initiating entity in the stream header specifies a version of XMPP that is not
+ * supported. </td></tr>
+ * <tr><td> xml-not-well-formed </td><td> the initiating entity has sent XML that is
+ * not well-formed. </td></tr>
+ * </table>
+ *
+ * @author Gaston Dombiak
+ */
+public class StreamError {
+
+ private String code;
+
+ public StreamError(String code) {
+ super();
+ this.code = code;
+ }
+
+ /**
+ * Returns the error code.
+ *
+ * @return the error code.
+ */
+ public String getCode() {
+ return code;
+ }
+
+ public String toString() {
+ StringBuilder txt = new StringBuilder();
+ txt.append("stream:error (").append(code).append(")");
+ return txt.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java
index e7b4b9317..84b5079f0 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java
@@ -1,109 +1,109 @@
-/**
- * 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.provider;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
-import org.jivesoftware.smackx.pubsub.provider.ItemsProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- *
- * This class simplifies parsing of embedded elements by using the
- * <a href="http://en.wikipedia.org/wiki/Template_method_pattern">Template Method Pattern</a>.
- * After extracting the current element attributes and content of any child elements, the template method
- * ({@link #createReturnExtension(String, String, Map, List)} is called. Subclasses
- * then override this method to create the specific return type.
- *
- * <p>To use this class, you simply register your subclasses as extension providers in the
- * <b>smack.properties</b> file. Then they will be automatically picked up and used to parse
- * any child elements.
- *
- * <pre>
- * For example, given the following message
- *
- * &lt;message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo&gt;
- * &lt;event xmlns='http://jabber.org/protocol/pubsub#event&gt;
- * &lt;items node='princely_musings'&gt;
- * &lt;item id='asdjkwei3i34234n356'&gt;
- * &lt;entry xmlns='http://www.w3.org/2005/Atom'&gt;
- * &lt;title&gt;Soliloquy&lt;/title&gt;
- * &lt;link rel='alternative' type='text/html'/&gt;
- * &lt;id>tag:denmark.lit,2003:entry-32397&lt;/id&gt;
- * &lt;/entry&gt;
- * &lt;/item&gt;
- * &lt;/items&gt;
- * &lt;/event&gt;
- * &lt;/message&gt;
- *
- * I would have a classes
- * {@link ItemsProvider} extends {@link EmbeddedExtensionProvider}
- * {@link ItemProvider} extends {@link EmbeddedExtensionProvider}
- * and
- * AtomProvider extends {@link PacketExtensionProvider}
- *
- * These classes are then registered in the meta-inf/smack.providers file
- * as follows.
- *
- * &lt;extensionProvider&gt;
- * &lt;elementName&gt;items&lt;/elementName&gt;
- * &lt;namespace&gt;http://jabber.org/protocol/pubsub#event&lt;/namespace&gt;
- * &lt;className&gt;org.jivesoftware.smackx.provider.ItemsEventProvider&lt;/className&gt;
- * &lt;/extensionProvider&gt;
- * &lt;extensionProvider&gt;
- * &lt;elementName&gt;item&lt;/elementName&gt;
- * &lt;namespace&gt;http://jabber.org/protocol/pubsub#event&lt;/namespace&gt;
- * &lt;className&gt;org.jivesoftware.smackx.provider.ItemProvider&lt;/className&gt;
- * &lt;/extensionProvider&gt;
- *
- * </pre>
- *
- * @author Robin Collier
- */
-abstract public class EmbeddedExtensionProvider implements PacketExtensionProvider
-{
-
- final public PacketExtension parseExtension(XmlPullParser parser) throws Exception
- {
- String namespace = parser.getNamespace();
- String name = parser.getName();
- Map<String, String> attMap = new HashMap<String, String>();
-
- for(int i=0; i<parser.getAttributeCount(); i++)
- {
- attMap.put(parser.getAttributeName(i), parser.getAttributeValue(i));
- }
- List<PacketExtension> extensions = new ArrayList<PacketExtension>();
-
- do
- {
- int tag = parser.next();
-
- if (tag == XmlPullParser.START_TAG)
- extensions.add(PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser));
- } while (!name.equals(parser.getName()));
-
- return createReturnExtension(name, namespace, attMap, extensions);
- }
-
- abstract protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content);
-}
+/**
+ * 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.provider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
+import org.jivesoftware.smackx.pubsub.provider.ItemsProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ *
+ * This class simplifies parsing of embedded elements by using the
+ * <a href="http://en.wikipedia.org/wiki/Template_method_pattern">Template Method Pattern</a>.
+ * After extracting the current element attributes and content of any child elements, the template method
+ * ({@link #createReturnExtension(String, String, Map, List)} is called. Subclasses
+ * then override this method to create the specific return type.
+ *
+ * <p>To use this class, you simply register your subclasses as extension providers in the
+ * <b>smack.properties</b> file. Then they will be automatically picked up and used to parse
+ * any child elements.
+ *
+ * <pre>
+ * For example, given the following message
+ *
+ * &lt;message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo&gt;
+ * &lt;event xmlns='http://jabber.org/protocol/pubsub#event&gt;
+ * &lt;items node='princely_musings'&gt;
+ * &lt;item id='asdjkwei3i34234n356'&gt;
+ * &lt;entry xmlns='http://www.w3.org/2005/Atom'&gt;
+ * &lt;title&gt;Soliloquy&lt;/title&gt;
+ * &lt;link rel='alternative' type='text/html'/&gt;
+ * &lt;id>tag:denmark.lit,2003:entry-32397&lt;/id&gt;
+ * &lt;/entry&gt;
+ * &lt;/item&gt;
+ * &lt;/items&gt;
+ * &lt;/event&gt;
+ * &lt;/message&gt;
+ *
+ * I would have a classes
+ * {@link ItemsProvider} extends {@link EmbeddedExtensionProvider}
+ * {@link ItemProvider} extends {@link EmbeddedExtensionProvider}
+ * and
+ * AtomProvider extends {@link PacketExtensionProvider}
+ *
+ * These classes are then registered in the meta-inf/smack.providers file
+ * as follows.
+ *
+ * &lt;extensionProvider&gt;
+ * &lt;elementName&gt;items&lt;/elementName&gt;
+ * &lt;namespace&gt;http://jabber.org/protocol/pubsub#event&lt;/namespace&gt;
+ * &lt;className&gt;org.jivesoftware.smackx.provider.ItemsEventProvider&lt;/className&gt;
+ * &lt;/extensionProvider&gt;
+ * &lt;extensionProvider&gt;
+ * &lt;elementName&gt;item&lt;/elementName&gt;
+ * &lt;namespace&gt;http://jabber.org/protocol/pubsub#event&lt;/namespace&gt;
+ * &lt;className&gt;org.jivesoftware.smackx.provider.ItemProvider&lt;/className&gt;
+ * &lt;/extensionProvider&gt;
+ *
+ * </pre>
+ *
+ * @author Robin Collier
+ */
+abstract public class EmbeddedExtensionProvider implements PacketExtensionProvider
+{
+
+ final public PacketExtension parseExtension(XmlPullParser parser) throws Exception
+ {
+ String namespace = parser.getNamespace();
+ String name = parser.getName();
+ Map<String, String> attMap = new HashMap<String, String>();
+
+ for(int i=0; i<parser.getAttributeCount(); i++)
+ {
+ attMap.put(parser.getAttributeName(i), parser.getAttributeValue(i));
+ }
+ List<PacketExtension> extensions = new ArrayList<PacketExtension>();
+
+ do
+ {
+ int tag = parser.next();
+
+ if (tag == XmlPullParser.START_TAG)
+ extensions.add(PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser));
+ } while (!name.equals(parser.getName()));
+
+ return createReturnExtension(name, namespace, attMap, extensions);
+ }
+
+ abstract protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content);
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/PrivacyProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/PrivacyProvider.java
index 62b31205d..4ce9ea659 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/PrivacyProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/provider/PrivacyProvider.java
@@ -15,137 +15,137 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smack.provider;
-
-import org.jivesoftware.smack.packet.DefaultPacketExtension;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Privacy;
-import org.jivesoftware.smack.packet.PrivacyItem;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.ArrayList;
-
-/**
- * The PrivacyProvider parses {@link Privacy} packets. {@link Privacy}
- * Parses the <tt>query</tt> sub-document and creates an instance of {@link Privacy}.
- * For each <tt>item</tt> in the <tt>list</tt> element, it creates an instance
- * of {@link PrivacyItem} and {@link org.jivesoftware.smack.packet.PrivacyItem.PrivacyRule}.
- *
- * @author Francisco Vives
- */
-public class PrivacyProvider implements IQProvider {
-
- public PrivacyProvider() {
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- Privacy privacy = new Privacy();
- /* privacy.addExtension(PacketParserUtils.parsePacketExtension(parser
- .getName(), parser.getNamespace(), parser)); */
- privacy.addExtension(new DefaultPacketExtension(parser.getName(), parser.getNamespace()));
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("active")) {
- String activeName = parser.getAttributeValue("", "name");
- if (activeName == null) {
- privacy.setDeclineActiveList(true);
- } else {
- privacy.setActiveName(activeName);
- }
- }
- else if (parser.getName().equals("default")) {
- String defaultName = parser.getAttributeValue("", "name");
- if (defaultName == null) {
- privacy.setDeclineDefaultList(true);
- } else {
- privacy.setDefaultName(defaultName);
- }
- }
- else if (parser.getName().equals("list")) {
- parseList(parser, privacy);
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("query")) {
- done = true;
- }
- }
- }
-
- return privacy;
- }
-
- // Parse the list complex type
- public void parseList(XmlPullParser parser, Privacy privacy) throws Exception {
- boolean done = false;
- String listName = parser.getAttributeValue("", "name");
- ArrayList<PrivacyItem> items = new ArrayList<PrivacyItem>();
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("item")) {
- items.add(parseItem(parser));
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("list")) {
- done = true;
- }
- }
- }
-
- privacy.setPrivacyList(listName, items);
- }
-
- // Parse the list complex type
- public PrivacyItem parseItem(XmlPullParser parser) throws Exception {
- boolean done = false;
- // Retrieves the required attributes
- String actionValue = parser.getAttributeValue("", "action");
- String orderValue = parser.getAttributeValue("", "order");
- String type = parser.getAttributeValue("", "type");
-
- /*
- * According the action value it sets the allow status. The fall-through action is assumed
- * to be "allow"
- */
- boolean allow = true;
- if ("allow".equalsIgnoreCase(actionValue)) {
- allow = true;
- } else if ("deny".equalsIgnoreCase(actionValue)) {
- allow = false;
- }
- // Set the order number
- int order = Integer.parseInt(orderValue);
-
- // Create the privacy item
- PrivacyItem item = new PrivacyItem(type, allow, order);
- item.setValue(parser.getAttributeValue("", "value"));
-
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("iq")) {
- item.setFilterIQ(true);
- }
- if (parser.getName().equals("message")) {
- item.setFilterMessage(true);
- }
- if (parser.getName().equals("presence-in")) {
- item.setFilterPresence_in(true);
- }
- if (parser.getName().equals("presence-out")) {
- item.setFilterPresence_out(true);
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("item")) {
- done = true;
- }
- }
- }
- return item;
- }
-}
+package org.jivesoftware.smack.provider;
+
+import org.jivesoftware.smack.packet.DefaultPacketExtension;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Privacy;
+import org.jivesoftware.smack.packet.PrivacyItem;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+
+/**
+ * The PrivacyProvider parses {@link Privacy} packets. {@link Privacy}
+ * Parses the <tt>query</tt> sub-document and creates an instance of {@link Privacy}.
+ * For each <tt>item</tt> in the <tt>list</tt> element, it creates an instance
+ * of {@link PrivacyItem} and {@link org.jivesoftware.smack.packet.PrivacyItem.PrivacyRule}.
+ *
+ * @author Francisco Vives
+ */
+public class PrivacyProvider implements IQProvider {
+
+ public PrivacyProvider() {
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ Privacy privacy = new Privacy();
+ /* privacy.addExtension(PacketParserUtils.parsePacketExtension(parser
+ .getName(), parser.getNamespace(), parser)); */
+ privacy.addExtension(new DefaultPacketExtension(parser.getName(), parser.getNamespace()));
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("active")) {
+ String activeName = parser.getAttributeValue("", "name");
+ if (activeName == null) {
+ privacy.setDeclineActiveList(true);
+ } else {
+ privacy.setActiveName(activeName);
+ }
+ }
+ else if (parser.getName().equals("default")) {
+ String defaultName = parser.getAttributeValue("", "name");
+ if (defaultName == null) {
+ privacy.setDeclineDefaultList(true);
+ } else {
+ privacy.setDefaultName(defaultName);
+ }
+ }
+ else if (parser.getName().equals("list")) {
+ parseList(parser, privacy);
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("query")) {
+ done = true;
+ }
+ }
+ }
+
+ return privacy;
+ }
+
+ // Parse the list complex type
+ public void parseList(XmlPullParser parser, Privacy privacy) throws Exception {
+ boolean done = false;
+ String listName = parser.getAttributeValue("", "name");
+ ArrayList<PrivacyItem> items = new ArrayList<PrivacyItem>();
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("item")) {
+ items.add(parseItem(parser));
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("list")) {
+ done = true;
+ }
+ }
+ }
+
+ privacy.setPrivacyList(listName, items);
+ }
+
+ // Parse the list complex type
+ public PrivacyItem parseItem(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ // Retrieves the required attributes
+ String actionValue = parser.getAttributeValue("", "action");
+ String orderValue = parser.getAttributeValue("", "order");
+ String type = parser.getAttributeValue("", "type");
+
+ /*
+ * According the action value it sets the allow status. The fall-through action is assumed
+ * to be "allow"
+ */
+ boolean allow = true;
+ if ("allow".equalsIgnoreCase(actionValue)) {
+ allow = true;
+ } else if ("deny".equalsIgnoreCase(actionValue)) {
+ allow = false;
+ }
+ // Set the order number
+ int order = Integer.parseInt(orderValue);
+
+ // Create the privacy item
+ PrivacyItem item = new PrivacyItem(type, allow, order);
+ item.setValue(parser.getAttributeValue("", "value"));
+
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("iq")) {
+ item.setFilterIQ(true);
+ }
+ if (parser.getName().equals("message")) {
+ item.setFilterMessage(true);
+ }
+ if (parser.getName().equals("presence-in")) {
+ item.setFilterPresence_in(true);
+ }
+ if (parser.getName().equals("presence-out")) {
+ item.setFilterPresence_out(true);
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("item")) {
+ done = true;
+ }
+ }
+ }
+ return item;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLAnonymous.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLAnonymous.java
index 8ef9d1846..b959e968f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLAnonymous.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLAnonymous.java
@@ -1,62 +1,62 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- *
- * 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.sasl;
-
-import org.jivesoftware.smack.SASLAuthentication;
-
-import java.io.IOException;
-import javax.security.auth.callback.CallbackHandler;
-
-/**
- * Implementation of the SASL ANONYMOUS mechanism
- *
- * @author Jay Kline
- */
-public class SASLAnonymous extends SASLMechanism {
-
- public SASLAnonymous(SASLAuthentication saslAuthentication) {
- super(saslAuthentication);
- }
-
- protected String getName() {
- return "ANONYMOUS";
- }
-
- public void authenticate(String username, String host, CallbackHandler cbh) throws IOException {
- authenticate();
- }
-
- public void authenticate(String username, String host, String password) throws IOException {
- authenticate();
- }
-
- protected void authenticate() throws IOException {
- // Send the authentication to the server
- getSASLAuthentication().send(new AuthMechanism(getName(), null));
- }
-
- public void challengeReceived(String challenge) throws IOException {
- // Build the challenge response stanza encoding the response text
- // and send the authentication to the server
- getSASLAuthentication().send(new Response());
- }
-
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ *
+ * 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.sasl;
+
+import org.jivesoftware.smack.SASLAuthentication;
+
+import java.io.IOException;
+import javax.security.auth.callback.CallbackHandler;
+
+/**
+ * Implementation of the SASL ANONYMOUS mechanism
+ *
+ * @author Jay Kline
+ */
+public class SASLAnonymous extends SASLMechanism {
+
+ public SASLAnonymous(SASLAuthentication saslAuthentication) {
+ super(saslAuthentication);
+ }
+
+ protected String getName() {
+ return "ANONYMOUS";
+ }
+
+ public void authenticate(String username, String host, CallbackHandler cbh) throws IOException {
+ authenticate();
+ }
+
+ public void authenticate(String username, String host, String password) throws IOException {
+ authenticate();
+ }
+
+ protected void authenticate() throws IOException {
+ // Send the authentication to the server
+ getSASLAuthentication().send(new AuthMechanism(getName(), null));
+ }
+
+ public void challengeReceived(String challenge) throws IOException {
+ // Build the challenge response stanza encoding the response text
+ // and send the authentication to the server
+ getSASLAuthentication().send(new Response());
+ }
+
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLCramMD5Mechanism.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLCramMD5Mechanism.java
index 82d218fd0..f2be038e0 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLCramMD5Mechanism.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLCramMD5Mechanism.java
@@ -1,38 +1,38 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- *
- * 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.sasl;
-
-import org.jivesoftware.smack.SASLAuthentication;
-
-/**
- * Implementation of the SASL CRAM-MD5 mechanism
- *
- * @author Jay Kline
- */
-public class SASLCramMD5Mechanism extends SASLMechanism {
-
- public SASLCramMD5Mechanism(SASLAuthentication saslAuthentication) {
- super(saslAuthentication);
- }
-
- protected String getName() {
- return "CRAM-MD5";
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ *
+ * 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.sasl;
+
+import org.jivesoftware.smack.SASLAuthentication;
+
+/**
+ * Implementation of the SASL CRAM-MD5 mechanism
+ *
+ * @author Jay Kline
+ */
+public class SASLCramMD5Mechanism extends SASLMechanism {
+
+ public SASLCramMD5Mechanism(SASLAuthentication saslAuthentication) {
+ super(saslAuthentication);
+ }
+
+ protected String getName() {
+ return "CRAM-MD5";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLDigestMD5Mechanism.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLDigestMD5Mechanism.java
index 7af65fb96..bfaec0ab4 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLDigestMD5Mechanism.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLDigestMD5Mechanism.java
@@ -1,38 +1,38 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- *
- * 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.sasl;
-
-import org.jivesoftware.smack.SASLAuthentication;
-
-/**
- * Implementation of the SASL DIGEST-MD5 mechanism
- *
- * @author Jay Kline
- */
-public class SASLDigestMD5Mechanism extends SASLMechanism {
-
- public SASLDigestMD5Mechanism(SASLAuthentication saslAuthentication) {
- super(saslAuthentication);
- }
-
- protected String getName() {
- return "DIGEST-MD5";
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ *
+ * 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.sasl;
+
+import org.jivesoftware.smack.SASLAuthentication;
+
+/**
+ * Implementation of the SASL DIGEST-MD5 mechanism
+ *
+ * @author Jay Kline
+ */
+public class SASLDigestMD5Mechanism extends SASLMechanism {
+
+ public SASLDigestMD5Mechanism(SASLAuthentication saslAuthentication) {
+ super(saslAuthentication);
+ }
+
+ protected String getName() {
+ return "DIGEST-MD5";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLExternalMechanism.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLExternalMechanism.java
index dff18fb58..248a650e6 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLExternalMechanism.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLExternalMechanism.java
@@ -1,59 +1,59 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- *
- * 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.sasl;
-
-import org.jivesoftware.smack.SASLAuthentication;
-
-/**
- * Implementation of the SASL EXTERNAL mechanism.
- *
- * To effectively use this mechanism, Java must be configured to properly
- * supply a client SSL certificate (of some sort) to the server. It is up
- * to the implementer to determine how to do this. Here is one method:
- *
- * Create a java keystore with your SSL certificate in it:
- * keytool -genkey -alias username -dname "cn=username,ou=organizationalUnit,o=organizationaName,l=locality,s=state,c=country"
- *
- * Next, set the System Properties:
- * <ul>
- * <li>javax.net.ssl.keyStore to the location of the keyStore
- * <li>javax.net.ssl.keyStorePassword to the password of the keyStore
- * <li>javax.net.ssl.trustStore to the location of the trustStore
- * <li>javax.net.ssl.trustStorePassword to the the password of the trustStore
- * </ul>
- *
- * Then, when the server requests or requires the client certificate, java will
- * simply provide the one in the keyStore.
- *
- * Also worth noting is the EXTERNAL mechanism in Smack is not enabled by default.
- * To enable it, the implementer will need to call SASLAuthentication.supportSASLMechamism("EXTERNAL");
- *
- * @author Jay Kline
- */
-public class SASLExternalMechanism extends SASLMechanism {
-
- public SASLExternalMechanism(SASLAuthentication saslAuthentication) {
- super(saslAuthentication);
- }
-
- protected String getName() {
- return "EXTERNAL";
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ *
+ * 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.sasl;
+
+import org.jivesoftware.smack.SASLAuthentication;
+
+/**
+ * Implementation of the SASL EXTERNAL mechanism.
+ *
+ * To effectively use this mechanism, Java must be configured to properly
+ * supply a client SSL certificate (of some sort) to the server. It is up
+ * to the implementer to determine how to do this. Here is one method:
+ *
+ * Create a java keystore with your SSL certificate in it:
+ * keytool -genkey -alias username -dname "cn=username,ou=organizationalUnit,o=organizationaName,l=locality,s=state,c=country"
+ *
+ * Next, set the System Properties:
+ * <ul>
+ * <li>javax.net.ssl.keyStore to the location of the keyStore
+ * <li>javax.net.ssl.keyStorePassword to the password of the keyStore
+ * <li>javax.net.ssl.trustStore to the location of the trustStore
+ * <li>javax.net.ssl.trustStorePassword to the the password of the trustStore
+ * </ul>
+ *
+ * Then, when the server requests or requires the client certificate, java will
+ * simply provide the one in the keyStore.
+ *
+ * Also worth noting is the EXTERNAL mechanism in Smack is not enabled by default.
+ * To enable it, the implementer will need to call SASLAuthentication.supportSASLMechamism("EXTERNAL");
+ *
+ * @author Jay Kline
+ */
+public class SASLExternalMechanism extends SASLMechanism {
+
+ public SASLExternalMechanism(SASLAuthentication saslAuthentication) {
+ super(saslAuthentication);
+ }
+
+ protected String getName() {
+ return "EXTERNAL";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java
index 3f0b7d899..8101ca5b2 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java
@@ -1,89 +1,89 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- *
- * 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.sasl;
-
-import org.jivesoftware.smack.SASLAuthentication;
-import org.jivesoftware.smack.XMPPException;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.HashMap;
-import javax.security.sasl.Sasl;
-import javax.security.auth.callback.CallbackHandler;
-
-/**
- * Implementation of the SASL GSSAPI mechanism
- *
- * @author Jay Kline
- */
-public class SASLGSSAPIMechanism extends SASLMechanism {
-
- public SASLGSSAPIMechanism(SASLAuthentication saslAuthentication) {
- super(saslAuthentication);
-
- System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
- System.setProperty("java.security.auth.login.config","gss.conf");
-
- }
-
- protected String getName() {
- return "GSSAPI";
- }
-
- /**
- * Builds and sends the <tt>auth</tt> stanza to the server.
- * This overrides from the abstract class because the initial token
- * needed for GSSAPI is binary, and not safe to put in a string, thus
- * getAuthenticationText() cannot be used.
- *
- * @param username the username of the user being authenticated.
- * @param host the hostname where the user account resides.
- * @param cbh the CallbackHandler (not used with GSSAPI)
- * @throws IOException If a network error occures while authenticating.
- */
- public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
- String[] mechanisms = { getName() };
- Map<String,String> props = new HashMap<String,String>();
- props.put(Sasl.SERVER_AUTH,"TRUE");
- sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, cbh);
- authenticate();
- }
-
- /**
- * Builds and sends the <tt>auth</tt> stanza to the server.
- * This overrides from the abstract class because the initial token
- * needed for GSSAPI is binary, and not safe to put in a string, thus
- * getAuthenticationText() cannot be used.
- *
- * @param username the username of the user being authenticated.
- * @param host the hostname where the user account resides.
- * @param password the password of the user (ignored for GSSAPI)
- * @throws IOException If a network error occures while authenticating.
- */
- public void authenticate(String username, String host, String password) throws IOException, XMPPException {
- String[] mechanisms = { getName() };
- Map<String,String> props = new HashMap<String, String>();
- props.put(Sasl.SERVER_AUTH,"TRUE");
- sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
- authenticate();
- }
-
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ *
+ * 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.sasl;
+
+import org.jivesoftware.smack.SASLAuthentication;
+import org.jivesoftware.smack.XMPPException;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.HashMap;
+import javax.security.sasl.Sasl;
+import javax.security.auth.callback.CallbackHandler;
+
+/**
+ * Implementation of the SASL GSSAPI mechanism
+ *
+ * @author Jay Kline
+ */
+public class SASLGSSAPIMechanism extends SASLMechanism {
+
+ public SASLGSSAPIMechanism(SASLAuthentication saslAuthentication) {
+ super(saslAuthentication);
+
+ System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
+ System.setProperty("java.security.auth.login.config","gss.conf");
+
+ }
+
+ protected String getName() {
+ return "GSSAPI";
+ }
+
+ /**
+ * Builds and sends the <tt>auth</tt> stanza to the server.
+ * This overrides from the abstract class because the initial token
+ * needed for GSSAPI is binary, and not safe to put in a string, thus
+ * getAuthenticationText() cannot be used.
+ *
+ * @param username the username of the user being authenticated.
+ * @param host the hostname where the user account resides.
+ * @param cbh the CallbackHandler (not used with GSSAPI)
+ * @throws IOException If a network error occures while authenticating.
+ */
+ public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
+ String[] mechanisms = { getName() };
+ Map<String,String> props = new HashMap<String,String>();
+ props.put(Sasl.SERVER_AUTH,"TRUE");
+ sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, cbh);
+ authenticate();
+ }
+
+ /**
+ * Builds and sends the <tt>auth</tt> stanza to the server.
+ * This overrides from the abstract class because the initial token
+ * needed for GSSAPI is binary, and not safe to put in a string, thus
+ * getAuthenticationText() cannot be used.
+ *
+ * @param username the username of the user being authenticated.
+ * @param host the hostname where the user account resides.
+ * @param password the password of the user (ignored for GSSAPI)
+ * @throws IOException If a network error occures while authenticating.
+ */
+ public void authenticate(String username, String host, String password) throws IOException, XMPPException {
+ String[] mechanisms = { getName() };
+ Map<String,String> props = new HashMap<String, String>();
+ props.put(Sasl.SERVER_AUTH,"TRUE");
+ sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
+ authenticate();
+ }
+
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLMechanism.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLMechanism.java
index 0d096f2a2..45212e460 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLMechanism.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLMechanism.java
@@ -1,404 +1,404 @@
-/**
- * $RCSfile$
- * $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
- *
- * 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.sasl;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.SASLAuthentication;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.util.StringUtils;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.HashMap;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.sasl.RealmCallback;
-import javax.security.sasl.RealmChoiceCallback;
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-
-/**
- * Base class for SASL mechanisms. Subclasses must implement these methods:
- * <ul>
- * <li>{@link #getName()} -- returns the common name of the SASL mechanism.</li>
- * </ul>
- * Subclasses will likely want to implement their own versions of these mthods:
- * <li>{@link #authenticate(String, String, String)} -- Initiate authentication stanza using the
- * deprecated method.</li>
- * <li>{@link #authenticate(String, String, CallbackHandler)} -- Initiate authentication stanza
- * 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
- */
-public abstract class SASLMechanism implements CallbackHandler {
-
- private SASLAuthentication saslAuthentication;
- protected SaslClient sc;
- protected String authenticationId;
- 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
- * {@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 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 serviceName, String password) throws IOException, XMPPException {
- //Since we were not provided with a CallbackHandler, we will use our own with the given
- //information
-
- //Set the authenticationID as the username, since they must be the same in this case.
- this.authenticationId = username;
- this.password = password;
- this.hostname = host;
-
- String[] mechanisms = { getName() };
- Map<String,String> props = new HashMap<String,String>();
- 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.
- *
- * @param username the username of the user being authenticated.
- * @param host the hostname where the user account resides.
- * @param cbh the CallbackHandler to obtain user information.
- * @throws IOException If a network error occures while authenticating.
- * @throws XMPPException If a protocol error occurs or the user is not authenticated.
- */
- public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
- String[] mechanisms = { getName() };
- Map<String,String> props = new HashMap<String,String>();
- sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, cbh);
- authenticate();
- }
-
- protected void authenticate() throws IOException, XMPPException {
- String authenticationText = null;
- try {
- if(sc.hasInitialResponse()) {
- byte[] response = sc.evaluateChallenge(new byte[0]);
- authenticationText = StringUtils.encodeBase64(response, false);
- }
- } catch (SaslException e) {
- throw new XMPPException("SASL authentication failed", e);
- }
-
- // Send the authentication to the server
- getSASLAuthentication().send(new AuthMechanism(getName(), authenticationText));
- }
-
-
- /**
- * The server is challenging the SASL mechanism for the stanza he just sent. Send a
- * response to the server's challenge.
- *
- * @param challenge a base64 encoded string representing the challenge.
- * @throws IOException if an exception sending the response occurs.
- */
- public void challengeReceived(String challenge) throws IOException {
- byte response[];
- if(challenge != null) {
- response = sc.evaluateChallenge(StringUtils.decodeBase64(challenge));
- } else {
- response = sc.evaluateChallenge(new byte[0]);
- }
-
- Packet responseStanza;
- if (response == null) {
- responseStanza = new Response();
- }
- else {
- responseStanza = new Response(StringUtils.encodeBase64(response, false));
- }
-
- // Send the authentication to the server
- getSASLAuthentication().send(responseStanza);
- }
-
- /**
- * Returns the common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or GSSAPI.
- *
- * @return the common name of the SASL mechanism.
- */
- protected abstract String getName();
-
-
- protected SASLAuthentication getSASLAuthentication() {
- return saslAuthentication;
- }
-
- /**
- *
- */
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- for (int i = 0; i < callbacks.length; i++) {
- if (callbacks[i] instanceof NameCallback) {
- NameCallback ncb = (NameCallback)callbacks[i];
- ncb.setName(authenticationId);
- } else if(callbacks[i] instanceof PasswordCallback) {
- PasswordCallback pcb = (PasswordCallback)callbacks[i];
- pcb.setPassword(password.toCharArray());
- } else if(callbacks[i] instanceof RealmCallback) {
- RealmCallback rcb = (RealmCallback)callbacks[i];
- //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];
- } else {
- throw new UnsupportedCallbackException(callbacks[i]);
- }
- }
- }
-
- /**
- * Initiating SASL authentication by select a mechanism.
- */
- public class AuthMechanism extends Packet {
- final private String name;
- final private String authenticationText;
-
- public AuthMechanism(String name, String authenticationText) {
- if (name == null) {
- throw new NullPointerException("SASL mechanism name shouldn't be null.");
- }
- this.name = name;
- this.authenticationText = authenticationText;
- }
-
- public String toXML() {
- StringBuilder stanza = new StringBuilder();
- stanza.append("<auth mechanism=\"").append(name);
- stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
- if (authenticationText != null &&
- authenticationText.trim().length() > 0) {
- stanza.append(authenticationText);
- }
- stanza.append("</auth>");
- return stanza.toString();
- }
- }
-
- /**
- * A SASL challenge stanza.
- */
- public static class Challenge extends Packet {
- final private String data;
-
- public Challenge(String data) {
- this.data = data;
- }
-
- public String toXML() {
- StringBuilder stanza = new StringBuilder();
- stanza.append("<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
- if (data != null &&
- data.trim().length() > 0) {
- stanza.append(data);
- }
- stanza.append("</challenge>");
- return stanza.toString();
- }
- }
-
- /**
- * A SASL response stanza.
- */
- public class Response extends Packet {
- final private String authenticationText;
-
- public Response() {
- authenticationText = null;
- }
-
- public Response(String authenticationText) {
- if (authenticationText == null || authenticationText.trim().length() == 0) {
- this.authenticationText = null;
- }
- else {
- this.authenticationText = authenticationText;
- }
- }
-
- public String toXML() {
- StringBuilder stanza = new StringBuilder();
- stanza.append("<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
- if (authenticationText != null) {
- stanza.append(authenticationText);
- }
- stanza.append("</response>");
- return stanza.toString();
- }
- }
-
- /**
- * A SASL success stanza.
- */
- public static class Success extends Packet {
- final private String data;
-
- public Success(String data) {
- this.data = data;
- }
-
- public String toXML() {
- StringBuilder stanza = new StringBuilder();
- stanza.append("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
- if (data != null &&
- data.trim().length() > 0) {
- stanza.append(data);
- }
- stanza.append("</success>");
- return stanza.toString();
- }
- }
-
- /**
- * A SASL failure stanza.
- */
- public static class Failure extends Packet {
- final private String condition;
-
- public Failure(String condition) {
- this.condition = condition;
- }
-
- /**
- * Get the SASL related error condition.
- *
- * @return the SASL related error condition.
- */
- public String getCondition() {
- return condition;
- }
-
- public String toXML() {
- StringBuilder stanza = new StringBuilder();
- stanza.append("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
- if (condition != null &&
- condition.trim().length() > 0) {
- stanza.append("<").append(condition).append("/>");
- }
- stanza.append("</failure>");
- return stanza.toString();
- }
- }
-}
+/**
+ * $RCSfile$
+ * $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
+ *
+ * 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.sasl;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.SASLAuthentication;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.util.StringUtils;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.HashMap;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.sasl.RealmCallback;
+import javax.security.sasl.RealmChoiceCallback;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+/**
+ * Base class for SASL mechanisms. Subclasses must implement these methods:
+ * <ul>
+ * <li>{@link #getName()} -- returns the common name of the SASL mechanism.</li>
+ * </ul>
+ * Subclasses will likely want to implement their own versions of these mthods:
+ * <li>{@link #authenticate(String, String, String)} -- Initiate authentication stanza using the
+ * deprecated method.</li>
+ * <li>{@link #authenticate(String, String, CallbackHandler)} -- Initiate authentication stanza
+ * 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
+ */
+public abstract class SASLMechanism implements CallbackHandler {
+
+ private SASLAuthentication saslAuthentication;
+ protected SaslClient sc;
+ protected String authenticationId;
+ 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
+ * {@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 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 serviceName, String password) throws IOException, XMPPException {
+ //Since we were not provided with a CallbackHandler, we will use our own with the given
+ //information
+
+ //Set the authenticationID as the username, since they must be the same in this case.
+ this.authenticationId = username;
+ this.password = password;
+ this.hostname = host;
+
+ String[] mechanisms = { getName() };
+ Map<String,String> props = new HashMap<String,String>();
+ 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.
+ *
+ * @param username the username of the user being authenticated.
+ * @param host the hostname where the user account resides.
+ * @param cbh the CallbackHandler to obtain user information.
+ * @throws IOException If a network error occures while authenticating.
+ * @throws XMPPException If a protocol error occurs or the user is not authenticated.
+ */
+ public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
+ String[] mechanisms = { getName() };
+ Map<String,String> props = new HashMap<String,String>();
+ sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, cbh);
+ authenticate();
+ }
+
+ protected void authenticate() throws IOException, XMPPException {
+ String authenticationText = null;
+ try {
+ if(sc.hasInitialResponse()) {
+ byte[] response = sc.evaluateChallenge(new byte[0]);
+ authenticationText = StringUtils.encodeBase64(response, false);
+ }
+ } catch (SaslException e) {
+ throw new XMPPException("SASL authentication failed", e);
+ }
+
+ // Send the authentication to the server
+ getSASLAuthentication().send(new AuthMechanism(getName(), authenticationText));
+ }
+
+
+ /**
+ * The server is challenging the SASL mechanism for the stanza he just sent. Send a
+ * response to the server's challenge.
+ *
+ * @param challenge a base64 encoded string representing the challenge.
+ * @throws IOException if an exception sending the response occurs.
+ */
+ public void challengeReceived(String challenge) throws IOException {
+ byte response[];
+ if(challenge != null) {
+ response = sc.evaluateChallenge(StringUtils.decodeBase64(challenge));
+ } else {
+ response = sc.evaluateChallenge(new byte[0]);
+ }
+
+ Packet responseStanza;
+ if (response == null) {
+ responseStanza = new Response();
+ }
+ else {
+ responseStanza = new Response(StringUtils.encodeBase64(response, false));
+ }
+
+ // Send the authentication to the server
+ getSASLAuthentication().send(responseStanza);
+ }
+
+ /**
+ * Returns the common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or GSSAPI.
+ *
+ * @return the common name of the SASL mechanism.
+ */
+ protected abstract String getName();
+
+
+ protected SASLAuthentication getSASLAuthentication() {
+ return saslAuthentication;
+ }
+
+ /**
+ *
+ */
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ for (int i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof NameCallback) {
+ NameCallback ncb = (NameCallback)callbacks[i];
+ ncb.setName(authenticationId);
+ } else if(callbacks[i] instanceof PasswordCallback) {
+ PasswordCallback pcb = (PasswordCallback)callbacks[i];
+ pcb.setPassword(password.toCharArray());
+ } else if(callbacks[i] instanceof RealmCallback) {
+ RealmCallback rcb = (RealmCallback)callbacks[i];
+ //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];
+ } else {
+ throw new UnsupportedCallbackException(callbacks[i]);
+ }
+ }
+ }
+
+ /**
+ * Initiating SASL authentication by select a mechanism.
+ */
+ public class AuthMechanism extends Packet {
+ final private String name;
+ final private String authenticationText;
+
+ public AuthMechanism(String name, String authenticationText) {
+ if (name == null) {
+ throw new NullPointerException("SASL mechanism name shouldn't be null.");
+ }
+ this.name = name;
+ this.authenticationText = authenticationText;
+ }
+
+ public String toXML() {
+ StringBuilder stanza = new StringBuilder();
+ stanza.append("<auth mechanism=\"").append(name);
+ stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
+ if (authenticationText != null &&
+ authenticationText.trim().length() > 0) {
+ stanza.append(authenticationText);
+ }
+ stanza.append("</auth>");
+ return stanza.toString();
+ }
+ }
+
+ /**
+ * A SASL challenge stanza.
+ */
+ public static class Challenge extends Packet {
+ final private String data;
+
+ public Challenge(String data) {
+ this.data = data;
+ }
+
+ public String toXML() {
+ StringBuilder stanza = new StringBuilder();
+ stanza.append("<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
+ if (data != null &&
+ data.trim().length() > 0) {
+ stanza.append(data);
+ }
+ stanza.append("</challenge>");
+ return stanza.toString();
+ }
+ }
+
+ /**
+ * A SASL response stanza.
+ */
+ public class Response extends Packet {
+ final private String authenticationText;
+
+ public Response() {
+ authenticationText = null;
+ }
+
+ public Response(String authenticationText) {
+ if (authenticationText == null || authenticationText.trim().length() == 0) {
+ this.authenticationText = null;
+ }
+ else {
+ this.authenticationText = authenticationText;
+ }
+ }
+
+ public String toXML() {
+ StringBuilder stanza = new StringBuilder();
+ stanza.append("<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
+ if (authenticationText != null) {
+ stanza.append(authenticationText);
+ }
+ stanza.append("</response>");
+ return stanza.toString();
+ }
+ }
+
+ /**
+ * A SASL success stanza.
+ */
+ public static class Success extends Packet {
+ final private String data;
+
+ public Success(String data) {
+ this.data = data;
+ }
+
+ public String toXML() {
+ StringBuilder stanza = new StringBuilder();
+ stanza.append("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
+ if (data != null &&
+ data.trim().length() > 0) {
+ stanza.append(data);
+ }
+ stanza.append("</success>");
+ return stanza.toString();
+ }
+ }
+
+ /**
+ * A SASL failure stanza.
+ */
+ public static class Failure extends Packet {
+ final private String condition;
+
+ public Failure(String condition) {
+ this.condition = condition;
+ }
+
+ /**
+ * Get the SASL related error condition.
+ *
+ * @return the SASL related error condition.
+ */
+ public String getCondition() {
+ return condition;
+ }
+
+ public String toXML() {
+ StringBuilder stanza = new StringBuilder();
+ stanza.append("<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
+ if (condition != null &&
+ condition.trim().length() > 0) {
+ stanza.append("<").append(condition).append("/>");
+ }
+ stanza.append("</failure>");
+ return stanza.toString();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLPlainMechanism.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLPlainMechanism.java
index cd973eb87..c341d6761 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLPlainMechanism.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/sasl/SASLPlainMechanism.java
@@ -1,34 +1,34 @@
-/**
- *
- * 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.sasl;
-
-import org.jivesoftware.smack.SASLAuthentication;
-
-/**
- * Implementation of the SASL PLAIN mechanism
- *
- * @author Jay Kline
- */
-public class SASLPlainMechanism extends SASLMechanism {
-
- public SASLPlainMechanism(SASLAuthentication saslAuthentication) {
- super(saslAuthentication);
- }
-
- protected String getName() {
- return "PLAIN";
- }
-}
+/**
+ *
+ * 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.sasl;
+
+import org.jivesoftware.smack.SASLAuthentication;
+
+/**
+ * Implementation of the SASL PLAIN mechanism
+ *
+ * @author Jay Kline
+ */
+public class SASLPlainMechanism extends SASLMechanism {
+
+ public SASLPlainMechanism(SASLAuthentication saslAuthentication) {
+ super(saslAuthentication);
+ }
+
+ protected String getName() {
+ return "PLAIN";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/Base64.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/Base64.java
index ba6eb371f..0923f037f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/Base64.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/Base64.java
@@ -4,1686 +4,1686 @@
* $Date$
*
*/
-package org.jivesoftware.smack.util;
-
-/**
+package org.jivesoftware.smack.util;
+
+/**
* <p>Encodes and decodes to and from Base64 notation.</p>
- * This code was obtained from <a href="http://iharder.net/base64">http://iharder.net/base64</a></p>
- *
- *
- * @author Robert Harder
- * @author rob@iharder.net
- * @version 2.2.1
- */
-public class Base64
-{
-
-/* ******** P U B L I C F I E L D S ******** */
-
-
- /** No options specified. Value is zero. */
- public final static int NO_OPTIONS = 0;
-
- /** Specify encoding. */
- public final static int ENCODE = 1;
-
-
- /** Specify decoding. */
- public final static int DECODE = 0;
-
-
- /** Specify that data should be gzip-compressed. */
- public final static int GZIP = 2;
-
-
- /** Don't break lines when encoding (violates strict Base64 specification) */
- public final static int DONT_BREAK_LINES = 8;
-
- /**
- * Encode using Base64-like encoding that is URL- and Filename-safe as described
- * in Section 4 of RFC3548:
- * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
- * It is important to note that data encoded this way is <em>not</em> officially valid Base64,
- * or at the very least should not be called Base64 without also specifying that is
- * was encoded using the URL- and Filename-safe dialect.
- */
- public final static int URL_SAFE = 16;
-
-
- /**
- * Encode using the special "ordered" dialect of Base64 described here:
- * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
- */
- public final static int ORDERED = 32;
-
-
-/* ******** P R I V A T E F I E L D S ******** */
-
-
- /** Maximum line length (76) of Base64 output. */
- private final static int MAX_LINE_LENGTH = 76;
-
-
- /** The equals sign (=) as a byte. */
- private final static byte EQUALS_SIGN = (byte)'=';
-
-
- /** The new line character (\n) as a byte. */
- private final static byte NEW_LINE = (byte)'\n';
-
-
- /** Preferred encoding. */
- private final static String PREFERRED_ENCODING = "UTF-8";
-
-
- // I think I end up not using the BAD_ENCODING indicator.
- //private final static byte BAD_ENCODING = -9; // Indicates error in encoding
- private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
- private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
-
-
-/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */
-
- /** The 64 valid Base64 values. */
- //private final static byte[] ALPHABET;
- /* Host platform me be something funny like EBCDIC, so we hardcode these values. */
- private final static byte[] _STANDARD_ALPHABET =
- {
- (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
- (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
- (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
- (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
- (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
- (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
- (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
- (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
- (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
- (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
- };
-
-
- /**
- * Translates a Base64 value to either its 6-bit reconstruction value
- * or a negative number indicating some other meaning.
- **/
- private final static byte[] _STANDARD_DECODABET =
- {
- -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
- -5,-5, // Whitespace: Tab and Linefeed
- -9,-9, // Decimal 11 - 12
- -5, // Whitespace: Carriage Return
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
- -9,-9,-9,-9,-9, // Decimal 27 - 31
- -5, // Whitespace: Space
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
- 62, // Plus sign at decimal 43
- -9,-9,-9, // Decimal 44 - 46
- 63, // Slash at decimal 47
- 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
- -9,-9,-9, // Decimal 58 - 60
- -1, // Equals sign at decimal 61
- -9,-9,-9, // Decimal 62 - 64
- 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
- 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
- -9,-9,-9,-9,-9,-9, // Decimal 91 - 96
- 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
- 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
- -9,-9,-9,-9 // Decimal 123 - 126
- /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
- };
-
-
-/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */
-
- /**
- * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548:
- * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
- * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
- */
- private final static byte[] _URL_SAFE_ALPHABET =
- {
- (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
- (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
- (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
- (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
- (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
- (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
- (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
- (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
- (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
- (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'
- };
-
- /**
- * Used in decoding URL- and Filename-safe dialects of Base64.
- */
- private final static byte[] _URL_SAFE_DECODABET =
- {
- -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
- -5,-5, // Whitespace: Tab and Linefeed
- -9,-9, // Decimal 11 - 12
- -5, // Whitespace: Carriage Return
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
- -9,-9,-9,-9,-9, // Decimal 27 - 31
- -5, // Whitespace: Space
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
- -9, // Plus sign at decimal 43
- -9, // Decimal 44
- 62, // Minus sign at decimal 45
- -9, // Decimal 46
- -9, // Slash at decimal 47
- 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
- -9,-9,-9, // Decimal 58 - 60
- -1, // Equals sign at decimal 61
- -9,-9,-9, // Decimal 62 - 64
- 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
- 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
- -9,-9,-9,-9, // Decimal 91 - 94
- 63, // Underscore at decimal 95
- -9, // Decimal 96
- 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
- 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
- -9,-9,-9,-9 // Decimal 123 - 126
- /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
- };
-
-
-
-/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */
-
- /**
- * I don't get the point of this technique, but it is described here:
- * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
- */
- private final static byte[] _ORDERED_ALPHABET =
- {
- (byte)'-',
- (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
- (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
- (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
- (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
- (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
- (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
- (byte)'_',
- (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
- (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
- (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
- (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'
- };
-
- /**
- * Used in decoding the "ordered" dialect of Base64.
- */
- private final static byte[] _ORDERED_DECODABET =
- {
- -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
- -5,-5, // Whitespace: Tab and Linefeed
- -9,-9, // Decimal 11 - 12
- -5, // Whitespace: Carriage Return
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
- -9,-9,-9,-9,-9, // Decimal 27 - 31
- -5, // Whitespace: Space
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
- -9, // Plus sign at decimal 43
- -9, // Decimal 44
- 0, // Minus sign at decimal 45
- -9, // Decimal 46
- -9, // Slash at decimal 47
- 1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine
- -9,-9,-9, // Decimal 58 - 60
- -1, // Equals sign at decimal 61
- -9,-9,-9, // Decimal 62 - 64
- 11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M'
- 24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z'
- -9,-9,-9,-9, // Decimal 91 - 94
- 37, // Underscore at decimal 95
- -9, // Decimal 96
- 38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm'
- 51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z'
- -9,-9,-9,-9 // Decimal 123 - 126
- /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
- -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
- };
-
-
-/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */
-
-
- /**
- * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
- * the options specified.
- * It's possible, though silly, to specify ORDERED and URLSAFE
- * in which case one of them will be picked, though there is
- * no guarantee as to which one will be picked.
- */
- private final static byte[] getAlphabet( int options )
- {
- if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_ALPHABET;
- else if( (options & ORDERED) == ORDERED ) return _ORDERED_ALPHABET;
- else return _STANDARD_ALPHABET;
-
- } // end getAlphabet
-
-
- /**
- * Returns one of the _SOMETHING_DECODABET byte arrays depending on
- * the options specified.
- * It's possible, though silly, to specify ORDERED and URL_SAFE
- * in which case one of them will be picked, though there is
- * no guarantee as to which one will be picked.
- */
- private final static byte[] getDecodabet( int options )
- {
- if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_DECODABET;
- else if( (options & ORDERED) == ORDERED ) return _ORDERED_DECODABET;
- else return _STANDARD_DECODABET;
-
- } // end getAlphabet
-
-
-
- /** Defeats instantiation. */
- private Base64(){}
-
- /**
- * Prints command line usage.
- *
- * @param msg A message to include with usage info.
- */
- private final static void usage( String msg )
- {
- System.err.println( msg );
- System.err.println( "Usage: java Base64 -e|-d inputfile outputfile" );
- } // end usage
-
-
-/* ******** E N C O D I N G M E T H O D S ******** */
-
-
- /**
- * Encodes up to the first three bytes of array <var>threeBytes</var>
- * and returns a four-byte array in Base64 notation.
- * The actual number of significant bytes in your array is
- * given by <var>numSigBytes</var>.
- * The array <var>threeBytes</var> needs only be as big as
- * <var>numSigBytes</var>.
- * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
- *
- * @param b4 A reusable byte array to reduce array instantiation
- * @param threeBytes the array to convert
- * @param numSigBytes the number of significant bytes in your array
- * @return four byte array in Base64 notation.
- * @since 1.5.1
- */
- private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options )
- {
- encode3to4( threeBytes, 0, numSigBytes, b4, 0, options );
- return b4;
- } // end encode3to4
-
-
- /**
- * <p>Encodes up to three bytes of the array <var>source</var>
- * and writes the resulting four Base64 bytes to <var>destination</var>.
- * The source and destination arrays can be manipulated
- * anywhere along their length by specifying
- * <var>srcOffset</var> and <var>destOffset</var>.
- * This method does not check to make sure your arrays
- * are large enough to accomodate <var>srcOffset</var> + 3 for
- * the <var>source</var> array or <var>destOffset</var> + 4 for
- * the <var>destination</var> array.
- * The actual number of significant bytes in your array is
- * given by <var>numSigBytes</var>.</p>
- * <p>This is the lowest level of the encoding methods with
- * all possible parameters.</p>
- *
- * @param source the array to convert
- * @param srcOffset the index where conversion begins
- * @param numSigBytes the number of significant bytes in your array
- * @param destination the array to hold the conversion
- * @param destOffset the index where output will be put
- * @return the <var>destination</var> array
- * @since 1.3
- */
- private static byte[] encode3to4(
- byte[] source, int srcOffset, int numSigBytes,
- byte[] destination, int destOffset, int options )
- {
- byte[] ALPHABET = getAlphabet( options );
-
- // 1 2 3
- // 01234567890123456789012345678901 Bit position
- // --------000000001111111122222222 Array position from threeBytes
- // --------| || || || | Six bit groups to index ALPHABET
- // >>18 >>12 >> 6 >> 0 Right shift necessary
- // 0x3f 0x3f 0x3f Additional AND
-
- // Create buffer with zero-padding if there are only one or two
- // significant bytes passed in the array.
- // We have to shift left 24 in order to flush out the 1's that appear
- // when Java treats a value as negative that is cast from a byte to an int.
- int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 )
- | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
- | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
-
- switch( numSigBytes )
- {
- case 3:
- destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
- destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
- destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
- destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ];
- return destination;
-
- case 2:
- destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
- destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
- destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
- destination[ destOffset + 3 ] = EQUALS_SIGN;
- return destination;
-
- case 1:
- destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
- destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
- destination[ destOffset + 2 ] = EQUALS_SIGN;
- destination[ destOffset + 3 ] = EQUALS_SIGN;
- return destination;
-
- default:
- return destination;
- } // end switch
- } // end encode3to4
-
-
-
- /**
- * Serializes an object and returns the Base64-encoded
- * version of that serialized object. If the object
- * cannot be serialized or there is another error,
- * the method will return <tt>null</tt>.
- * The object is not GZip-compressed before being encoded.
- *
- * @param serializableObject The object to encode
- * @return The Base64-encoded object
- * @since 1.4
- */
- public static String encodeObject( java.io.Serializable serializableObject )
- {
- return encodeObject( serializableObject, NO_OPTIONS );
- } // end encodeObject
-
-
-
- /**
- * Serializes an object and returns the Base64-encoded
- * version of that serialized object. If the object
- * cannot be serialized or there is another error,
- * the method will return <tt>null</tt>.
- * <p>
- * Valid options:<pre>
- * GZIP: gzip-compresses object before encoding it.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * <i>Note: Technically, this makes your encoding non-compliant.</i>
- * </pre>
- * <p>
- * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
- * <p>
- * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
- *
- * @param serializableObject The object to encode
- * @param options Specified options
- * @return The Base64-encoded object
- * @see Base64#GZIP
- * @see Base64#DONT_BREAK_LINES
- * @since 2.0
- */
- public static String encodeObject( java.io.Serializable serializableObject, int options )
- {
- // Streams
- java.io.ByteArrayOutputStream baos = null;
- java.io.OutputStream b64os = null;
- java.io.ObjectOutputStream oos = null;
- java.util.zip.GZIPOutputStream gzos = null;
-
- // Isolate options
- int gzip = (options & GZIP);
- int dontBreakLines = (options & DONT_BREAK_LINES);
-
- try
- {
- // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
- baos = new java.io.ByteArrayOutputStream();
- b64os = new Base64.OutputStream( baos, ENCODE | options );
-
- // GZip?
- if( gzip == GZIP )
- {
- gzos = new java.util.zip.GZIPOutputStream( b64os );
- oos = new java.io.ObjectOutputStream( gzos );
- } // end if: gzip
- else
- oos = new java.io.ObjectOutputStream( b64os );
-
- oos.writeObject( serializableObject );
- } // end try
- catch( java.io.IOException e )
- {
- e.printStackTrace();
- return null;
- } // end catch
- finally
- {
- try{ oos.close(); } catch( Exception e ){}
- try{ gzos.close(); } catch( Exception e ){}
- try{ b64os.close(); } catch( Exception e ){}
- try{ baos.close(); } catch( Exception e ){}
- } // end finally
-
- // Return value according to relevant encoding.
- try
- {
- return new String( baos.toByteArray(), PREFERRED_ENCODING );
- } // end try
- catch (java.io.UnsupportedEncodingException uue)
- {
- return new String( baos.toByteArray() );
- } // end catch
-
- } // end encode
-
-
-
- /**
- * Encodes a byte array into Base64 notation.
- * Does not GZip-compress data.
- *
- * @param source The data to convert
- * @since 1.4
- */
- public static String encodeBytes( byte[] source )
- {
- return encodeBytes( source, 0, source.length, NO_OPTIONS );
- } // end encodeBytes
-
-
-
- /**
- * Encodes a byte array into Base64 notation.
- * <p>
- * Valid options:<pre>
- * GZIP: gzip-compresses object before encoding it.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * <i>Note: Technically, this makes your encoding non-compliant.</i>
- * </pre>
- * <p>
- * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
- * <p>
- * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
- *
- *
- * @param source The data to convert
- * @param options Specified options
- * @see Base64#GZIP
- * @see Base64#DONT_BREAK_LINES
- * @since 2.0
- */
- public static String encodeBytes( byte[] source, int options )
- {
- return encodeBytes( source, 0, source.length, options );
- } // end encodeBytes
-
-
- /**
- * Encodes a byte array into Base64 notation.
- * Does not GZip-compress data.
- *
- * @param source The data to convert
- * @param off Offset in array where conversion should begin
- * @param len Length of data to convert
- * @since 1.4
- */
- public static String encodeBytes( byte[] source, int off, int len )
- {
- return encodeBytes( source, off, len, NO_OPTIONS );
- } // end encodeBytes
-
-
-
- /**
- * Encodes a byte array into Base64 notation.
- * <p>
- * Valid options:<pre>
- * GZIP: gzip-compresses object before encoding it.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * <i>Note: Technically, this makes your encoding non-compliant.</i>
- * </pre>
- * <p>
- * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
- * <p>
- * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
- *
- *
- * @param source The data to convert
- * @param off Offset in array where conversion should begin
- * @param len Length of data to convert
- * @param options Specified options; alphabet type is pulled from this (standard, url-safe, ordered)
- * @see Base64#GZIP
- * @see Base64#DONT_BREAK_LINES
- * @since 2.0
- */
- public static String encodeBytes( byte[] source, int off, int len, int options )
- {
- // Isolate options
- int dontBreakLines = ( options & DONT_BREAK_LINES );
- int gzip = ( options & GZIP );
-
- // Compress?
- if( gzip == GZIP )
- {
- java.io.ByteArrayOutputStream baos = null;
- java.util.zip.GZIPOutputStream gzos = null;
- Base64.OutputStream b64os = null;
-
-
- try
- {
- // GZip -> Base64 -> ByteArray
- baos = new java.io.ByteArrayOutputStream();
- b64os = new Base64.OutputStream( baos, ENCODE | options );
- gzos = new java.util.zip.GZIPOutputStream( b64os );
-
- gzos.write( source, off, len );
- gzos.close();
- } // end try
- catch( java.io.IOException e )
- {
- e.printStackTrace();
- return null;
- } // end catch
- finally
- {
- try{ gzos.close(); } catch( Exception e ){}
- try{ b64os.close(); } catch( Exception e ){}
- try{ baos.close(); } catch( Exception e ){}
- } // end finally
-
- // Return value according to relevant encoding.
- try
- {
- return new String( baos.toByteArray(), PREFERRED_ENCODING );
- } // end try
- catch (java.io.UnsupportedEncodingException uue)
- {
- return new String( baos.toByteArray() );
- } // end catch
- } // end if: compress
-
- // Else, don't compress. Better not to use streams at all then.
- else
- {
- // Convert option to boolean in way that code likes it.
- boolean breakLines = dontBreakLines == 0;
-
- int len43 = len * 4 / 3;
- byte[] outBuff = new byte[ ( len43 ) // Main 4:3
- + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
- + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
- int d = 0;
- int e = 0;
- int len2 = len - 2;
- int lineLength = 0;
- for( ; d < len2; d+=3, e+=4 )
- {
- encode3to4( source, d+off, 3, outBuff, e, options );
-
- lineLength += 4;
- if( breakLines && lineLength == MAX_LINE_LENGTH )
- {
- outBuff[e+4] = NEW_LINE;
- e++;
- lineLength = 0;
- } // end if: end of line
- } // en dfor: each piece of array
-
- if( d < len )
- {
- encode3to4( source, d+off, len - d, outBuff, e, options );
- e += 4;
- } // end if: some padding needed
-
-
- // Return value according to relevant encoding.
- try
- {
- return new String( outBuff, 0, e, PREFERRED_ENCODING );
- } // end try
- catch (java.io.UnsupportedEncodingException uue)
- {
- return new String( outBuff, 0, e );
- } // end catch
-
- } // end else: don't compress
-
- } // end encodeBytes
-
-
-
-
-
-/* ******** D E C O D I N G M E T H O D S ******** */
-
-
- /**
- * Decodes four bytes from array <var>source</var>
- * and writes the resulting bytes (up to three of them)
- * to <var>destination</var>.
- * The source and destination arrays can be manipulated
- * anywhere along their length by specifying
- * <var>srcOffset</var> and <var>destOffset</var>.
- * This method does not check to make sure your arrays
- * are large enough to accomodate <var>srcOffset</var> + 4 for
- * the <var>source</var> array or <var>destOffset</var> + 3 for
- * the <var>destination</var> array.
- * This method returns the actual number of bytes that
- * were converted from the Base64 encoding.
- * <p>This is the lowest level of the decoding methods with
- * all possible parameters.</p>
- *
- *
- * @param source the array to convert
- * @param srcOffset the index where conversion begins
- * @param destination the array to hold the conversion
- * @param destOffset the index where output will be put
- * @param options alphabet type is pulled from this (standard, url-safe, ordered)
- * @return the number of decoded bytes converted
- * @since 1.3
- */
- private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset, int options )
- {
- byte[] DECODABET = getDecodabet( options );
-
- // Example: Dk==
- if( source[ srcOffset + 2] == EQUALS_SIGN )
- {
- // Two ways to do the same thing. Don't know which way I like best.
- //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
- // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
- int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
- | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
-
- destination[ destOffset ] = (byte)( outBuff >>> 16 );
- return 1;
- }
-
- // Example: DkL=
- else if( source[ srcOffset + 3 ] == EQUALS_SIGN )
- {
- // Two ways to do the same thing. Don't know which way I like best.
- //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
- // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
- // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
- int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
- | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
- | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 );
-
- destination[ destOffset ] = (byte)( outBuff >>> 16 );
- destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 );
- return 2;
- }
-
- // Example: DkLE
- else
- {
- try{
- // Two ways to do the same thing. Don't know which way I like best.
- //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
- // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
- // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
- // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
- int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
- | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
- | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6)
- | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) );
-
-
- destination[ destOffset ] = (byte)( outBuff >> 16 );
- destination[ destOffset + 1 ] = (byte)( outBuff >> 8 );
- destination[ destOffset + 2 ] = (byte)( outBuff );
-
- return 3;
- }catch( Exception e){
- System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) );
- System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) );
- System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) );
- System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) );
- return -1;
- } // end catch
- }
- } // end decodeToBytes
-
-
-
-
- /**
- * Very low-level access to decoding ASCII characters in
- * the form of a byte array. Does not support automatically
- * gunzipping or any other "fancy" features.
- *
- * @param source The Base64 encoded data
- * @param off The offset of where to begin decoding
- * @param len The length of characters to decode
- * @return decoded data
- * @since 1.3
- */
- public static byte[] decode( byte[] source, int off, int len, int options )
- {
- byte[] DECODABET = getDecodabet( options );
-
- int len34 = len * 3 / 4;
- byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
- int outBuffPosn = 0;
-
- byte[] b4 = new byte[4];
- int b4Posn = 0;
- int i = 0;
- byte sbiCrop = 0;
- byte sbiDecode = 0;
- for( i = off; i < off+len; i++ )
- {
- sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
- sbiDecode = DECODABET[ sbiCrop ];
-
- if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better
- {
- if( sbiDecode >= EQUALS_SIGN_ENC )
- {
- b4[ b4Posn++ ] = sbiCrop;
- if( b4Posn > 3 )
- {
- outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
- b4Posn = 0;
-
- // If that was the equals sign, break out of 'for' loop
- if( sbiCrop == EQUALS_SIGN )
- break;
- } // end if: quartet built
-
- } // end if: equals sign or better
-
- } // end if: white space, equals sign or better
- else
- {
- System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" );
- return null;
- } // end else:
- } // each input character
-
- byte[] out = new byte[ outBuffPosn ];
- System.arraycopy( outBuff, 0, out, 0, outBuffPosn );
- return out;
- } // end decode
-
-
-
-
- /**
- * Decodes data from Base64 notation, automatically
- * detecting gzip-compressed data and decompressing it.
- *
- * @param s the string to decode
- * @return the decoded data
- * @since 1.4
- */
- public static byte[] decode( String s )
- {
- return decode( s, NO_OPTIONS );
- }
-
-
- /**
- * Decodes data from Base64 notation, automatically
- * detecting gzip-compressed data and decompressing it.
- *
- * @param s the string to decode
- * @param options encode options such as URL_SAFE
- * @return the decoded data
- * @since 1.4
- */
- public static byte[] decode( String s, int options )
- {
- byte[] bytes;
- try
- {
- bytes = s.getBytes( PREFERRED_ENCODING );
- } // end try
- catch( java.io.UnsupportedEncodingException uee )
- {
- bytes = s.getBytes();
- } // end catch
- //</change>
-
- // Decode
- bytes = decode( bytes, 0, bytes.length, options );
-
-
- // Check to see if it's gzip-compressed
- // GZIP Magic Two-Byte Number: 0x8b1f (35615)
- if( bytes != null && bytes.length >= 4 )
- {
-
- int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
- if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head )
- {
- java.io.ByteArrayInputStream bais = null;
- java.util.zip.GZIPInputStream gzis = null;
- java.io.ByteArrayOutputStream baos = null;
- byte[] buffer = new byte[2048];
- int length = 0;
-
- try
- {
- baos = new java.io.ByteArrayOutputStream();
- bais = new java.io.ByteArrayInputStream( bytes );
- gzis = new java.util.zip.GZIPInputStream( bais );
-
- while( ( length = gzis.read( buffer ) ) >= 0 )
- {
- baos.write(buffer,0,length);
- } // end while: reading input
-
- // No error? Get new bytes.
- bytes = baos.toByteArray();
-
- } // end try
- catch( java.io.IOException e )
- {
- // Just return originally-decoded bytes
- } // end catch
- finally
- {
- try{ baos.close(); } catch( Exception e ){}
- try{ gzis.close(); } catch( Exception e ){}
- try{ bais.close(); } catch( Exception e ){}
- } // end finally
-
- } // end if: gzipped
- } // end if: bytes.length >= 2
-
- return bytes;
- } // end decode
-
-
-
-
- /**
- * Attempts to decode Base64 data and deserialize a Java
- * Object within. Returns <tt>null</tt> if there was an error.
- *
- * @param encodedObject The Base64 data to decode
- * @return The decoded and deserialized object
- * @since 1.5
- */
- public static Object decodeToObject( String encodedObject )
- {
- // Decode and gunzip if necessary
- byte[] objBytes = decode( encodedObject );
-
- java.io.ByteArrayInputStream bais = null;
- java.io.ObjectInputStream ois = null;
- Object obj = null;
-
- try
- {
- bais = new java.io.ByteArrayInputStream( objBytes );
- ois = new java.io.ObjectInputStream( bais );
-
- obj = ois.readObject();
- } // end try
- catch( java.io.IOException e )
- {
- e.printStackTrace();
- obj = null;
- } // end catch
- catch( java.lang.ClassNotFoundException e )
- {
- e.printStackTrace();
- obj = null;
- } // end catch
- finally
- {
- try{ bais.close(); } catch( Exception e ){}
- try{ ois.close(); } catch( Exception e ){}
- } // end finally
-
- return obj;
- } // end decodeObject
-
-
-
- /**
- * Convenience method for encoding data to a file.
- *
- * @param dataToEncode byte array of data to encode in base64 form
- * @param filename Filename for saving encoded data
- * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
- *
- * @since 2.1
- */
- public static boolean encodeToFile( byte[] dataToEncode, String filename )
- {
- boolean success = false;
- Base64.OutputStream bos = null;
- try
- {
- bos = new Base64.OutputStream(
- new java.io.FileOutputStream( filename ), Base64.ENCODE );
- bos.write( dataToEncode );
- success = true;
- } // end try
- catch( java.io.IOException e )
- {
-
- success = false;
- } // end catch: IOException
- finally
- {
- try{ bos.close(); } catch( Exception e ){}
- } // end finally
-
- return success;
- } // end encodeToFile
-
-
- /**
- * Convenience method for decoding data to a file.
- *
- * @param dataToDecode Base64-encoded data as a string
- * @param filename Filename for saving decoded data
- * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
- *
- * @since 2.1
- */
- public static boolean decodeToFile( String dataToDecode, String filename )
- {
- boolean success = false;
- Base64.OutputStream bos = null;
- try
- {
- bos = new Base64.OutputStream(
- new java.io.FileOutputStream( filename ), Base64.DECODE );
- bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) );
- success = true;
- } // end try
- catch( java.io.IOException e )
- {
- success = false;
- } // end catch: IOException
- finally
- {
- try{ bos.close(); } catch( Exception e ){}
- } // end finally
-
- return success;
- } // end decodeToFile
-
-
-
-
- /**
- * Convenience method for reading a base64-encoded
- * file and decoding it.
- *
- * @param filename Filename for reading encoded data
- * @return decoded byte array or null if unsuccessful
- *
- * @since 2.1
- */
- public static byte[] decodeFromFile( String filename )
- {
- byte[] decodedData = null;
- Base64.InputStream bis = null;
- try
- {
- // Set up some useful variables
- java.io.File file = new java.io.File( filename );
- byte[] buffer = null;
- int length = 0;
- int numBytes = 0;
-
- // Check for size of file
- if( file.length() > Integer.MAX_VALUE )
- {
- System.err.println( "File is too big for this convenience method (" + file.length() + " bytes)." );
- return null;
- } // end if: file too big for int index
- buffer = new byte[ (int)file.length() ];
-
- // Open a stream
- bis = new Base64.InputStream(
- new java.io.BufferedInputStream(
- new java.io.FileInputStream( file ) ), Base64.DECODE );
-
- // Read until done
- while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 )
- length += numBytes;
-
- // Save in a variable to return
- decodedData = new byte[ length ];
- System.arraycopy( buffer, 0, decodedData, 0, length );
-
- } // end try
- catch( java.io.IOException e )
- {
- System.err.println( "Error decoding from file " + filename );
- } // end catch: IOException
- finally
- {
- try{ bis.close(); } catch( Exception e) {}
- } // end finally
-
- return decodedData;
- } // end decodeFromFile
-
-
-
- /**
- * Convenience method for reading a binary file
- * and base64-encoding it.
- *
- * @param filename Filename for reading binary data
- * @return base64-encoded string or null if unsuccessful
- *
- * @since 2.1
- */
- public static String encodeFromFile( String filename )
- {
- String encodedData = null;
- Base64.InputStream bis = null;
- try
- {
- // Set up some useful variables
- java.io.File file = new java.io.File( filename );
- byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4),40) ]; // Need max() for math on small files (v2.2.1)
- int length = 0;
- int numBytes = 0;
-
- // Open a stream
- bis = new Base64.InputStream(
- new java.io.BufferedInputStream(
- new java.io.FileInputStream( file ) ), Base64.ENCODE );
-
- // Read until done
- while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 )
- length += numBytes;
-
- // Save in a variable to return
- encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING );
-
- } // end try
- catch( java.io.IOException e )
- {
- System.err.println( "Error encoding from file " + filename );
- } // end catch: IOException
- finally
- {
- try{ bis.close(); } catch( Exception e) {}
- } // end finally
-
- return encodedData;
- } // end encodeFromFile
-
- /**
- * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.
- *
- * @param infile Input file
- * @param outfile Output file
- * @since 2.2
- */
- public static void encodeFileToFile( String infile, String outfile )
- {
- String encoded = Base64.encodeFromFile( infile );
- java.io.OutputStream out = null;
- try{
- out = new java.io.BufferedOutputStream(
- new java.io.FileOutputStream( outfile ) );
- out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output.
- } // end try
- catch( java.io.IOException ex ) {
- ex.printStackTrace();
- } // end catch
- finally {
- try { out.close(); }
- catch( Exception ex ){}
- } // end finally
- } // end encodeFileToFile
-
-
- /**
- * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.
- *
- * @param infile Input file
- * @param outfile Output file
- * @since 2.2
- */
- public static void decodeFileToFile( String infile, String outfile )
- {
- byte[] decoded = Base64.decodeFromFile( infile );
- java.io.OutputStream out = null;
- try{
- out = new java.io.BufferedOutputStream(
- new java.io.FileOutputStream( outfile ) );
- out.write( decoded );
- } // end try
- catch( java.io.IOException ex ) {
- ex.printStackTrace();
- } // end catch
- finally {
- try { out.close(); }
- catch( Exception ex ){}
- } // end finally
- } // end decodeFileToFile
-
-
- /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */
-
-
-
- /**
- * A {@link Base64.InputStream} will read data from another
- * <tt>java.io.InputStream</tt>, given in the constructor,
- * and encode/decode to/from Base64 notation on the fly.
- *
- * @see Base64
- * @since 1.3
- */
- public static class InputStream extends java.io.FilterInputStream
- {
- private boolean encode; // Encoding or decoding
- private int position; // Current position in the buffer
- private byte[] buffer; // Small buffer holding converted data
- private int bufferLength; // Length of buffer (3 or 4)
- private int numSigBytes; // Number of meaningful bytes in the buffer
- private int lineLength;
- private boolean breakLines; // Break lines at less than 80 characters
- private int options; // Record options used to create the stream.
- private byte[] alphabet; // Local copies to avoid extra method calls
- private byte[] decodabet; // Local copies to avoid extra method calls
-
-
- /**
- * Constructs a {@link Base64.InputStream} in DECODE mode.
- *
- * @param in the <tt>java.io.InputStream</tt> from which to read data.
- * @since 1.3
- */
- public InputStream( java.io.InputStream in )
- {
- this( in, DECODE );
- } // end constructor
-
-
- /**
- * Constructs a {@link Base64.InputStream} in
- * either ENCODE or DECODE mode.
- * <p>
- * Valid options:<pre>
- * ENCODE or DECODE: Encode or Decode as data is read.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * (only meaningful when encoding)
- * <i>Note: Technically, this makes your encoding non-compliant.</i>
- * </pre>
- * <p>
- * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
- *
- *
- * @param in the <tt>java.io.InputStream</tt> from which to read data.
- * @param options Specified options
- * @see Base64#ENCODE
- * @see Base64#DECODE
- * @see Base64#DONT_BREAK_LINES
- * @since 2.0
- */
- public InputStream( java.io.InputStream in, int options )
- {
- super( in );
- this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
- this.encode = (options & ENCODE) == ENCODE;
- this.bufferLength = encode ? 4 : 3;
- this.buffer = new byte[ bufferLength ];
- this.position = -1;
- this.lineLength = 0;
- this.options = options; // Record for later, mostly to determine which alphabet to use
- this.alphabet = getAlphabet(options);
- this.decodabet = getDecodabet(options);
- } // end constructor
-
- /**
- * Reads enough of the input stream to convert
- * to/from Base64 and returns the next byte.
- *
- * @return next byte
- * @since 1.3
- */
- public int read() throws java.io.IOException
- {
- // Do we need to get data?
- if( position < 0 )
- {
- if( encode )
- {
- byte[] b3 = new byte[3];
- int numBinaryBytes = 0;
- for( int i = 0; i < 3; i++ )
- {
- try
- {
- int b = in.read();
-
- // If end of stream, b is -1.
- if( b >= 0 )
- {
- b3[i] = (byte)b;
- numBinaryBytes++;
- } // end if: not end of stream
-
- } // end try: read
- catch( java.io.IOException e )
- {
- // Only a problem if we got no data at all.
- if( i == 0 )
- throw e;
-
- } // end catch
- } // end for: each needed input byte
-
- if( numBinaryBytes > 0 )
- {
- encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
- position = 0;
- numSigBytes = 4;
- } // end if: got data
- else
- {
- return -1;
- } // end else
- } // end if: encoding
-
- // Else decoding
- else
- {
- byte[] b4 = new byte[4];
- int i = 0;
- for( i = 0; i < 4; i++ )
- {
- // Read four "meaningful" bytes:
- int b = 0;
- do{ b = in.read(); }
- while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
-
- if( b < 0 )
- break; // Reads a -1 if end of stream
-
- b4[i] = (byte)b;
- } // end for: each needed input byte
-
- if( i == 4 )
- {
- numSigBytes = decode4to3( b4, 0, buffer, 0, options );
- position = 0;
- } // end if: got four characters
- else if( i == 0 ){
- return -1;
- } // end else if: also padded correctly
- else
- {
- // Must have broken out from above.
- throw new java.io.IOException( "Improperly padded Base64 input." );
- } // end
-
- } // end else: decode
- } // end else: get data
-
- // Got data?
- if( position >= 0 )
- {
- // End of relevant data?
- if( /*!encode &&*/ position >= numSigBytes )
- return -1;
-
- if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
- {
- lineLength = 0;
- return '\n';
- } // end if
- else
- {
- lineLength++; // This isn't important when decoding
- // but throwing an extra "if" seems
- // just as wasteful.
-
- int b = buffer[ position++ ];
-
- if( position >= bufferLength )
- position = -1;
-
- return b & 0xFF; // This is how you "cast" a byte that's
- // intended to be unsigned.
- } // end else
- } // end if: position >= 0
-
- // Else error
- else
- {
- // When JDK1.4 is more accepted, use an assertion here.
- throw new java.io.IOException( "Error in Base64 code reading stream." );
- } // end else
- } // end read
-
-
- /**
- * Calls {@link #read()} repeatedly until the end of stream
- * is reached or <var>len</var> bytes are read.
- * Returns number of bytes read into array or -1 if
- * end of stream is encountered.
- *
- * @param dest array to hold values
- * @param off offset for array
- * @param len max number of bytes to read into array
- * @return bytes read into array or -1 if end of stream is encountered.
- * @since 1.3
- */
- public int read( byte[] dest, int off, int len ) throws java.io.IOException
- {
- int i;
- int b;
- for( i = 0; i < len; i++ )
- {
- b = read();
-
- //if( b < 0 && i == 0 )
- // return -1;
-
- if( b >= 0 )
- dest[off + i] = (byte)b;
- else if( i == 0 )
- return -1;
- else
- break; // Out of 'for' loop
- } // end for: each byte read
- return i;
- } // end read
-
- } // end inner class InputStream
-
-
-
-
-
-
- /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
-
-
-
- /**
- * A {@link Base64.OutputStream} will write data to another
- * <tt>java.io.OutputStream</tt>, given in the constructor,
- * and encode/decode to/from Base64 notation on the fly.
- *
- * @see Base64
- * @since 1.3
- */
- public static class OutputStream extends java.io.FilterOutputStream
- {
- private boolean encode;
- private int position;
- private byte[] buffer;
- private int bufferLength;
- private int lineLength;
- private boolean breakLines;
- private byte[] b4; // Scratch used in a few places
- private boolean suspendEncoding;
- private int options; // Record for later
- private byte[] alphabet; // Local copies to avoid extra method calls
- private byte[] decodabet; // Local copies to avoid extra method calls
-
- /**
- * Constructs a {@link Base64.OutputStream} in ENCODE mode.
- *
- * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
- * @since 1.3
- */
- public OutputStream( java.io.OutputStream out )
- {
- this( out, ENCODE );
- } // end constructor
-
-
- /**
- * Constructs a {@link Base64.OutputStream} in
- * either ENCODE or DECODE mode.
- * <p>
- * Valid options:<pre>
- * ENCODE or DECODE: Encode or Decode as data is read.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * (only meaningful when encoding)
- * <i>Note: Technically, this makes your encoding non-compliant.</i>
- * </pre>
- * <p>
- * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
- *
- * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
- * @param options Specified options.
- * @see Base64#ENCODE
- * @see Base64#DECODE
- * @see Base64#DONT_BREAK_LINES
- * @since 1.3
- */
- public OutputStream( java.io.OutputStream out, int options )
- {
- super( out );
- this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
- this.encode = (options & ENCODE) == ENCODE;
- this.bufferLength = encode ? 3 : 4;
- this.buffer = new byte[ bufferLength ];
- this.position = 0;
- this.lineLength = 0;
- this.suspendEncoding = false;
- this.b4 = new byte[4];
- this.options = options;
- this.alphabet = getAlphabet(options);
- this.decodabet = getDecodabet(options);
- } // end constructor
-
-
- /**
- * Writes the byte to the output stream after
- * converting to/from Base64 notation.
- * When encoding, bytes are buffered three
- * at a time before the output stream actually
- * gets a write() call.
- * When decoding, bytes are buffered four
- * at a time.
- *
- * @param theByte the byte to write
- * @since 1.3
- */
- public void write(int theByte) throws java.io.IOException
- {
- // Encoding suspended?
- if( suspendEncoding )
- {
- super.out.write( theByte );
- return;
- } // end if: supsended
-
- // Encode?
- if( encode )
- {
- buffer[ position++ ] = (byte)theByte;
- if( position >= bufferLength ) // Enough to encode.
- {
- out.write( encode3to4( b4, buffer, bufferLength, options ) );
-
- lineLength += 4;
- if( breakLines && lineLength >= MAX_LINE_LENGTH )
- {
- out.write( NEW_LINE );
- lineLength = 0;
- } // end if: end of line
-
- position = 0;
- } // end if: enough to output
- } // end if: encoding
-
- // Else, Decoding
- else
- {
- // Meaningful Base64 character?
- if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC )
- {
- buffer[ position++ ] = (byte)theByte;
- if( position >= bufferLength ) // Enough to output.
- {
- int len = Base64.decode4to3( buffer, 0, b4, 0, options );
- out.write( b4, 0, len );
- //out.write( Base64.decode4to3( buffer ) );
- position = 0;
- } // end if: enough to output
- } // end if: meaningful base64 character
- else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC )
- {
- throw new java.io.IOException( "Invalid character in Base64 data." );
- } // end else: not white space either
- } // end else: decoding
- } // end write
-
-
-
- /**
- * Calls {@link #write(int)} repeatedly until <var>len</var>
- * bytes are written.
- *
- * @param theBytes array from which to read bytes
- * @param off offset for array
- * @param len max number of bytes to read into array
- * @since 1.3
- */
- public void write( byte[] theBytes, int off, int len ) throws java.io.IOException
- {
- // Encoding suspended?
- if( suspendEncoding )
- {
- super.out.write( theBytes, off, len );
- return;
- } // end if: supsended
-
- for( int i = 0; i < len; i++ )
- {
- write( theBytes[ off + i ] );
- } // end for: each byte written
-
- } // end write
-
-
-
- /**
- * Method added by PHIL. [Thanks, PHIL. -Rob]
- * This pads the buffer without closing the stream.
- */
- public void flushBase64() throws java.io.IOException
- {
- if( position > 0 )
- {
- if( encode )
- {
- out.write( encode3to4( b4, buffer, position, options ) );
- position = 0;
- } // end if: encoding
- else
- {
- throw new java.io.IOException( "Base64 input not properly padded." );
- } // end else: decoding
- } // end if: buffer partially full
-
- } // end flush
-
-
- /**
- * Flushes and closes (I think, in the superclass) the stream.
- *
- * @since 1.3
- */
- public void close() throws java.io.IOException
- {
- // 1. Ensure that pending characters are written
- flushBase64();
-
- // 2. Actually close the stream
- // Base class both flushes and closes.
- super.close();
-
- buffer = null;
- out = null;
- } // end close
-
-
-
- /**
- * Suspends encoding of the stream.
- * May be helpful if you need to embed a piece of
- * base640-encoded data in a stream.
- *
- * @since 1.5.1
- */
- public void suspendEncoding() throws java.io.IOException
- {
- flushBase64();
- this.suspendEncoding = true;
- } // end suspendEncoding
-
-
- /**
- * Resumes encoding of the stream.
- * May be helpful if you need to embed a piece of
- * base640-encoded data in a stream.
- *
- * @since 1.5.1
- */
- public void resumeEncoding()
- {
- this.suspendEncoding = false;
- } // end resumeEncoding
-
-
-
- } // end inner class OutputStream
-
-
-} // end class Base64
-
+ * This code was obtained from <a href="http://iharder.net/base64">http://iharder.net/base64</a></p>
+ *
+ *
+ * @author Robert Harder
+ * @author rob@iharder.net
+ * @version 2.2.1
+ */
+public class Base64
+{
+
+/* ******** P U B L I C F I E L D S ******** */
+
+
+ /** No options specified. Value is zero. */
+ public final static int NO_OPTIONS = 0;
+
+ /** Specify encoding. */
+ public final static int ENCODE = 1;
+
+
+ /** Specify decoding. */
+ public final static int DECODE = 0;
+
+
+ /** Specify that data should be gzip-compressed. */
+ public final static int GZIP = 2;
+
+
+ /** Don't break lines when encoding (violates strict Base64 specification) */
+ public final static int DONT_BREAK_LINES = 8;
+
+ /**
+ * Encode using Base64-like encoding that is URL- and Filename-safe as described
+ * in Section 4 of RFC3548:
+ * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
+ * It is important to note that data encoded this way is <em>not</em> officially valid Base64,
+ * or at the very least should not be called Base64 without also specifying that is
+ * was encoded using the URL- and Filename-safe dialect.
+ */
+ public final static int URL_SAFE = 16;
+
+
+ /**
+ * Encode using the special "ordered" dialect of Base64 described here:
+ * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+ */
+ public final static int ORDERED = 32;
+
+
+/* ******** P R I V A T E F I E L D S ******** */
+
+
+ /** Maximum line length (76) of Base64 output. */
+ private final static int MAX_LINE_LENGTH = 76;
+
+
+ /** The equals sign (=) as a byte. */
+ private final static byte EQUALS_SIGN = (byte)'=';
+
+
+ /** The new line character (\n) as a byte. */
+ private final static byte NEW_LINE = (byte)'\n';
+
+
+ /** Preferred encoding. */
+ private final static String PREFERRED_ENCODING = "UTF-8";
+
+
+ // I think I end up not using the BAD_ENCODING indicator.
+ //private final static byte BAD_ENCODING = -9; // Indicates error in encoding
+ private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
+ private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
+
+
+/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */
+
+ /** The 64 valid Base64 values. */
+ //private final static byte[] ALPHABET;
+ /* Host platform me be something funny like EBCDIC, so we hardcode these values. */
+ private final static byte[] _STANDARD_ALPHABET =
+ {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
+ (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
+ };
+
+
+ /**
+ * Translates a Base64 value to either its 6-bit reconstruction value
+ * or a negative number indicating some other meaning.
+ **/
+ private final static byte[] _STANDARD_DECODABET =
+ {
+ -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
+ -5,-5, // Whitespace: Tab and Linefeed
+ -9,-9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
+ -9,-9,-9,-9,-9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
+ 62, // Plus sign at decimal 43
+ -9,-9,-9, // Decimal 44 - 46
+ 63, // Slash at decimal 47
+ 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
+ -9,-9,-9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9,-9,-9, // Decimal 62 - 64
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
+ 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
+ -9,-9,-9,-9,-9,-9, // Decimal 91 - 96
+ 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
+ 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
+ -9,-9,-9,-9 // Decimal 123 - 126
+ /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
+ };
+
+
+/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */
+
+ /**
+ * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548:
+ * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
+ * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
+ */
+ private final static byte[] _URL_SAFE_ALPHABET =
+ {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
+ (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'
+ };
+
+ /**
+ * Used in decoding URL- and Filename-safe dialects of Base64.
+ */
+ private final static byte[] _URL_SAFE_DECODABET =
+ {
+ -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
+ -5,-5, // Whitespace: Tab and Linefeed
+ -9,-9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
+ -9,-9,-9,-9,-9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
+ -9, // Plus sign at decimal 43
+ -9, // Decimal 44
+ 62, // Minus sign at decimal 45
+ -9, // Decimal 46
+ -9, // Slash at decimal 47
+ 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
+ -9,-9,-9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9,-9,-9, // Decimal 62 - 64
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
+ 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
+ -9,-9,-9,-9, // Decimal 91 - 94
+ 63, // Underscore at decimal 95
+ -9, // Decimal 96
+ 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
+ 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
+ -9,-9,-9,-9 // Decimal 123 - 126
+ /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
+ };
+
+
+
+/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */
+
+ /**
+ * I don't get the point of this technique, but it is described here:
+ * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+ */
+ private final static byte[] _ORDERED_ALPHABET =
+ {
+ (byte)'-',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
+ (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'_',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'
+ };
+
+ /**
+ * Used in decoding the "ordered" dialect of Base64.
+ */
+ private final static byte[] _ORDERED_DECODABET =
+ {
+ -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
+ -5,-5, // Whitespace: Tab and Linefeed
+ -9,-9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
+ -9,-9,-9,-9,-9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
+ -9, // Plus sign at decimal 43
+ -9, // Decimal 44
+ 0, // Minus sign at decimal 45
+ -9, // Decimal 46
+ -9, // Slash at decimal 47
+ 1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine
+ -9,-9,-9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9,-9,-9, // Decimal 62 - 64
+ 11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M'
+ 24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z'
+ -9,-9,-9,-9, // Decimal 91 - 94
+ 37, // Underscore at decimal 95
+ -9, // Decimal 96
+ 38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm'
+ 51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z'
+ -9,-9,-9,-9 // Decimal 123 - 126
+ /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
+ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
+ };
+
+
+/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */
+
+
+ /**
+ * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
+ * the options specified.
+ * It's possible, though silly, to specify ORDERED and URLSAFE
+ * in which case one of them will be picked, though there is
+ * no guarantee as to which one will be picked.
+ */
+ private final static byte[] getAlphabet( int options )
+ {
+ if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_ALPHABET;
+ else if( (options & ORDERED) == ORDERED ) return _ORDERED_ALPHABET;
+ else return _STANDARD_ALPHABET;
+
+ } // end getAlphabet
+
+
+ /**
+ * Returns one of the _SOMETHING_DECODABET byte arrays depending on
+ * the options specified.
+ * It's possible, though silly, to specify ORDERED and URL_SAFE
+ * in which case one of them will be picked, though there is
+ * no guarantee as to which one will be picked.
+ */
+ private final static byte[] getDecodabet( int options )
+ {
+ if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_DECODABET;
+ else if( (options & ORDERED) == ORDERED ) return _ORDERED_DECODABET;
+ else return _STANDARD_DECODABET;
+
+ } // end getAlphabet
+
+
+
+ /** Defeats instantiation. */
+ private Base64(){}
+
+ /**
+ * Prints command line usage.
+ *
+ * @param msg A message to include with usage info.
+ */
+ private final static void usage( String msg )
+ {
+ System.err.println( msg );
+ System.err.println( "Usage: java Base64 -e|-d inputfile outputfile" );
+ } // end usage
+
+
+/* ******** E N C O D I N G M E T H O D S ******** */
+
+
+ /**
+ * Encodes up to the first three bytes of array <var>threeBytes</var>
+ * and returns a four-byte array in Base64 notation.
+ * The actual number of significant bytes in your array is
+ * given by <var>numSigBytes</var>.
+ * The array <var>threeBytes</var> needs only be as big as
+ * <var>numSigBytes</var>.
+ * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
+ *
+ * @param b4 A reusable byte array to reduce array instantiation
+ * @param threeBytes the array to convert
+ * @param numSigBytes the number of significant bytes in your array
+ * @return four byte array in Base64 notation.
+ * @since 1.5.1
+ */
+ private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options )
+ {
+ encode3to4( threeBytes, 0, numSigBytes, b4, 0, options );
+ return b4;
+ } // end encode3to4
+
+
+ /**
+ * <p>Encodes up to three bytes of the array <var>source</var>
+ * and writes the resulting four Base64 bytes to <var>destination</var>.
+ * The source and destination arrays can be manipulated
+ * anywhere along their length by specifying
+ * <var>srcOffset</var> and <var>destOffset</var>.
+ * This method does not check to make sure your arrays
+ * are large enough to accomodate <var>srcOffset</var> + 3 for
+ * the <var>source</var> array or <var>destOffset</var> + 4 for
+ * the <var>destination</var> array.
+ * The actual number of significant bytes in your array is
+ * given by <var>numSigBytes</var>.</p>
+ * <p>This is the lowest level of the encoding methods with
+ * all possible parameters.</p>
+ *
+ * @param source the array to convert
+ * @param srcOffset the index where conversion begins
+ * @param numSigBytes the number of significant bytes in your array
+ * @param destination the array to hold the conversion
+ * @param destOffset the index where output will be put
+ * @return the <var>destination</var> array
+ * @since 1.3
+ */
+ private static byte[] encode3to4(
+ byte[] source, int srcOffset, int numSigBytes,
+ byte[] destination, int destOffset, int options )
+ {
+ byte[] ALPHABET = getAlphabet( options );
+
+ // 1 2 3
+ // 01234567890123456789012345678901 Bit position
+ // --------000000001111111122222222 Array position from threeBytes
+ // --------| || || || | Six bit groups to index ALPHABET
+ // >>18 >>12 >> 6 >> 0 Right shift necessary
+ // 0x3f 0x3f 0x3f Additional AND
+
+ // Create buffer with zero-padding if there are only one or two
+ // significant bytes passed in the array.
+ // We have to shift left 24 in order to flush out the 1's that appear
+ // when Java treats a value as negative that is cast from a byte to an int.
+ int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 )
+ | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
+ | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
+
+ switch( numSigBytes )
+ {
+ case 3:
+ destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
+ destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+ destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
+ destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ];
+ return destination;
+
+ case 2:
+ destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
+ destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+ destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
+ destination[ destOffset + 3 ] = EQUALS_SIGN;
+ return destination;
+
+ case 1:
+ destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
+ destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+ destination[ destOffset + 2 ] = EQUALS_SIGN;
+ destination[ destOffset + 3 ] = EQUALS_SIGN;
+ return destination;
+
+ default:
+ return destination;
+ } // end switch
+ } // end encode3to4
+
+
+
+ /**
+ * Serializes an object and returns the Base64-encoded
+ * version of that serialized object. If the object
+ * cannot be serialized or there is another error,
+ * the method will return <tt>null</tt>.
+ * The object is not GZip-compressed before being encoded.
+ *
+ * @param serializableObject The object to encode
+ * @return The Base64-encoded object
+ * @since 1.4
+ */
+ public static String encodeObject( java.io.Serializable serializableObject )
+ {
+ return encodeObject( serializableObject, NO_OPTIONS );
+ } // end encodeObject
+
+
+
+ /**
+ * Serializes an object and returns the Base64-encoded
+ * version of that serialized object. If the object
+ * cannot be serialized or there is another error,
+ * the method will return <tt>null</tt>.
+ * <p>
+ * Valid options:<pre>
+ * GZIP: gzip-compresses object before encoding it.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>
+ * </pre>
+ * <p>
+ * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
+ * <p>
+ * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
+ *
+ * @param serializableObject The object to encode
+ * @param options Specified options
+ * @return The Base64-encoded object
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeObject( java.io.Serializable serializableObject, int options )
+ {
+ // Streams
+ java.io.ByteArrayOutputStream baos = null;
+ java.io.OutputStream b64os = null;
+ java.io.ObjectOutputStream oos = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+
+ // Isolate options
+ int gzip = (options & GZIP);
+ int dontBreakLines = (options & DONT_BREAK_LINES);
+
+ try
+ {
+ // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream( baos, ENCODE | options );
+
+ // GZip?
+ if( gzip == GZIP )
+ {
+ gzos = new java.util.zip.GZIPOutputStream( b64os );
+ oos = new java.io.ObjectOutputStream( gzos );
+ } // end if: gzip
+ else
+ oos = new java.io.ObjectOutputStream( b64os );
+
+ oos.writeObject( serializableObject );
+ } // end try
+ catch( java.io.IOException e )
+ {
+ e.printStackTrace();
+ return null;
+ } // end catch
+ finally
+ {
+ try{ oos.close(); } catch( Exception e ){}
+ try{ gzos.close(); } catch( Exception e ){}
+ try{ b64os.close(); } catch( Exception e ){}
+ try{ baos.close(); } catch( Exception e ){}
+ } // end finally
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String( baos.toByteArray(), PREFERRED_ENCODING );
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ return new String( baos.toByteArray() );
+ } // end catch
+
+ } // end encode
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ *
+ * @param source The data to convert
+ * @since 1.4
+ */
+ public static String encodeBytes( byte[] source )
+ {
+ return encodeBytes( source, 0, source.length, NO_OPTIONS );
+ } // end encodeBytes
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * <p>
+ * Valid options:<pre>
+ * GZIP: gzip-compresses object before encoding it.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>
+ * </pre>
+ * <p>
+ * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
+ * <p>
+ * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
+ *
+ *
+ * @param source The data to convert
+ * @param options Specified options
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeBytes( byte[] source, int options )
+ {
+ return encodeBytes( source, 0, source.length, options );
+ } // end encodeBytes
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @since 1.4
+ */
+ public static String encodeBytes( byte[] source, int off, int len )
+ {
+ return encodeBytes( source, off, len, NO_OPTIONS );
+ } // end encodeBytes
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * <p>
+ * Valid options:<pre>
+ * GZIP: gzip-compresses object before encoding it.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>
+ * </pre>
+ * <p>
+ * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
+ * <p>
+ * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
+ *
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @param options Specified options; alphabet type is pulled from this (standard, url-safe, ordered)
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeBytes( byte[] source, int off, int len, int options )
+ {
+ // Isolate options
+ int dontBreakLines = ( options & DONT_BREAK_LINES );
+ int gzip = ( options & GZIP );
+
+ // Compress?
+ if( gzip == GZIP )
+ {
+ java.io.ByteArrayOutputStream baos = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+ Base64.OutputStream b64os = null;
+
+
+ try
+ {
+ // GZip -> Base64 -> ByteArray
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream( baos, ENCODE | options );
+ gzos = new java.util.zip.GZIPOutputStream( b64os );
+
+ gzos.write( source, off, len );
+ gzos.close();
+ } // end try
+ catch( java.io.IOException e )
+ {
+ e.printStackTrace();
+ return null;
+ } // end catch
+ finally
+ {
+ try{ gzos.close(); } catch( Exception e ){}
+ try{ b64os.close(); } catch( Exception e ){}
+ try{ baos.close(); } catch( Exception e ){}
+ } // end finally
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String( baos.toByteArray(), PREFERRED_ENCODING );
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ return new String( baos.toByteArray() );
+ } // end catch
+ } // end if: compress
+
+ // Else, don't compress. Better not to use streams at all then.
+ else
+ {
+ // Convert option to boolean in way that code likes it.
+ boolean breakLines = dontBreakLines == 0;
+
+ int len43 = len * 4 / 3;
+ byte[] outBuff = new byte[ ( len43 ) // Main 4:3
+ + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
+ + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
+ int d = 0;
+ int e = 0;
+ int len2 = len - 2;
+ int lineLength = 0;
+ for( ; d < len2; d+=3, e+=4 )
+ {
+ encode3to4( source, d+off, 3, outBuff, e, options );
+
+ lineLength += 4;
+ if( breakLines && lineLength == MAX_LINE_LENGTH )
+ {
+ outBuff[e+4] = NEW_LINE;
+ e++;
+ lineLength = 0;
+ } // end if: end of line
+ } // en dfor: each piece of array
+
+ if( d < len )
+ {
+ encode3to4( source, d+off, len - d, outBuff, e, options );
+ e += 4;
+ } // end if: some padding needed
+
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String( outBuff, 0, e, PREFERRED_ENCODING );
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ return new String( outBuff, 0, e );
+ } // end catch
+
+ } // end else: don't compress
+
+ } // end encodeBytes
+
+
+
+
+
+/* ******** D E C O D I N G M E T H O D S ******** */
+
+
+ /**
+ * Decodes four bytes from array <var>source</var>
+ * and writes the resulting bytes (up to three of them)
+ * to <var>destination</var>.
+ * The source and destination arrays can be manipulated
+ * anywhere along their length by specifying
+ * <var>srcOffset</var> and <var>destOffset</var>.
+ * This method does not check to make sure your arrays
+ * are large enough to accomodate <var>srcOffset</var> + 4 for
+ * the <var>source</var> array or <var>destOffset</var> + 3 for
+ * the <var>destination</var> array.
+ * This method returns the actual number of bytes that
+ * were converted from the Base64 encoding.
+ * <p>This is the lowest level of the decoding methods with
+ * all possible parameters.</p>
+ *
+ *
+ * @param source the array to convert
+ * @param srcOffset the index where conversion begins
+ * @param destination the array to hold the conversion
+ * @param destOffset the index where output will be put
+ * @param options alphabet type is pulled from this (standard, url-safe, ordered)
+ * @return the number of decoded bytes converted
+ * @since 1.3
+ */
+ private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset, int options )
+ {
+ byte[] DECODABET = getDecodabet( options );
+
+ // Example: Dk==
+ if( source[ srcOffset + 2] == EQUALS_SIGN )
+ {
+ // Two ways to do the same thing. Don't know which way I like best.
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
+ // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
+ int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
+ | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
+
+ destination[ destOffset ] = (byte)( outBuff >>> 16 );
+ return 1;
+ }
+
+ // Example: DkL=
+ else if( source[ srcOffset + 3 ] == EQUALS_SIGN )
+ {
+ // Two ways to do the same thing. Don't know which way I like best.
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
+ // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+ // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
+ int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
+ | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
+ | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 );
+
+ destination[ destOffset ] = (byte)( outBuff >>> 16 );
+ destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 );
+ return 2;
+ }
+
+ // Example: DkLE
+ else
+ {
+ try{
+ // Two ways to do the same thing. Don't know which way I like best.
+ //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
+ // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+ // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
+ // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
+ int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
+ | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
+ | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6)
+ | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) );
+
+
+ destination[ destOffset ] = (byte)( outBuff >> 16 );
+ destination[ destOffset + 1 ] = (byte)( outBuff >> 8 );
+ destination[ destOffset + 2 ] = (byte)( outBuff );
+
+ return 3;
+ }catch( Exception e){
+ System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) );
+ System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) );
+ System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) );
+ System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) );
+ return -1;
+ } // end catch
+ }
+ } // end decodeToBytes
+
+
+
+
+ /**
+ * Very low-level access to decoding ASCII characters in
+ * the form of a byte array. Does not support automatically
+ * gunzipping or any other "fancy" features.
+ *
+ * @param source The Base64 encoded data
+ * @param off The offset of where to begin decoding
+ * @param len The length of characters to decode
+ * @return decoded data
+ * @since 1.3
+ */
+ public static byte[] decode( byte[] source, int off, int len, int options )
+ {
+ byte[] DECODABET = getDecodabet( options );
+
+ int len34 = len * 3 / 4;
+ byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
+ int outBuffPosn = 0;
+
+ byte[] b4 = new byte[4];
+ int b4Posn = 0;
+ int i = 0;
+ byte sbiCrop = 0;
+ byte sbiDecode = 0;
+ for( i = off; i < off+len; i++ )
+ {
+ sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
+ sbiDecode = DECODABET[ sbiCrop ];
+
+ if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better
+ {
+ if( sbiDecode >= EQUALS_SIGN_ENC )
+ {
+ b4[ b4Posn++ ] = sbiCrop;
+ if( b4Posn > 3 )
+ {
+ outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
+ b4Posn = 0;
+
+ // If that was the equals sign, break out of 'for' loop
+ if( sbiCrop == EQUALS_SIGN )
+ break;
+ } // end if: quartet built
+
+ } // end if: equals sign or better
+
+ } // end if: white space, equals sign or better
+ else
+ {
+ System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" );
+ return null;
+ } // end else:
+ } // each input character
+
+ byte[] out = new byte[ outBuffPosn ];
+ System.arraycopy( outBuff, 0, out, 0, outBuffPosn );
+ return out;
+ } // end decode
+
+
+
+
+ /**
+ * Decodes data from Base64 notation, automatically
+ * detecting gzip-compressed data and decompressing it.
+ *
+ * @param s the string to decode
+ * @return the decoded data
+ * @since 1.4
+ */
+ public static byte[] decode( String s )
+ {
+ return decode( s, NO_OPTIONS );
+ }
+
+
+ /**
+ * Decodes data from Base64 notation, automatically
+ * detecting gzip-compressed data and decompressing it.
+ *
+ * @param s the string to decode
+ * @param options encode options such as URL_SAFE
+ * @return the decoded data
+ * @since 1.4
+ */
+ public static byte[] decode( String s, int options )
+ {
+ byte[] bytes;
+ try
+ {
+ bytes = s.getBytes( PREFERRED_ENCODING );
+ } // end try
+ catch( java.io.UnsupportedEncodingException uee )
+ {
+ bytes = s.getBytes();
+ } // end catch
+ //</change>
+
+ // Decode
+ bytes = decode( bytes, 0, bytes.length, options );
+
+
+ // Check to see if it's gzip-compressed
+ // GZIP Magic Two-Byte Number: 0x8b1f (35615)
+ if( bytes != null && bytes.length >= 4 )
+ {
+
+ int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
+ if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head )
+ {
+ java.io.ByteArrayInputStream bais = null;
+ java.util.zip.GZIPInputStream gzis = null;
+ java.io.ByteArrayOutputStream baos = null;
+ byte[] buffer = new byte[2048];
+ int length = 0;
+
+ try
+ {
+ baos = new java.io.ByteArrayOutputStream();
+ bais = new java.io.ByteArrayInputStream( bytes );
+ gzis = new java.util.zip.GZIPInputStream( bais );
+
+ while( ( length = gzis.read( buffer ) ) >= 0 )
+ {
+ baos.write(buffer,0,length);
+ } // end while: reading input
+
+ // No error? Get new bytes.
+ bytes = baos.toByteArray();
+
+ } // end try
+ catch( java.io.IOException e )
+ {
+ // Just return originally-decoded bytes
+ } // end catch
+ finally
+ {
+ try{ baos.close(); } catch( Exception e ){}
+ try{ gzis.close(); } catch( Exception e ){}
+ try{ bais.close(); } catch( Exception e ){}
+ } // end finally
+
+ } // end if: gzipped
+ } // end if: bytes.length >= 2
+
+ return bytes;
+ } // end decode
+
+
+
+
+ /**
+ * Attempts to decode Base64 data and deserialize a Java
+ * Object within. Returns <tt>null</tt> if there was an error.
+ *
+ * @param encodedObject The Base64 data to decode
+ * @return The decoded and deserialized object
+ * @since 1.5
+ */
+ public static Object decodeToObject( String encodedObject )
+ {
+ // Decode and gunzip if necessary
+ byte[] objBytes = decode( encodedObject );
+
+ java.io.ByteArrayInputStream bais = null;
+ java.io.ObjectInputStream ois = null;
+ Object obj = null;
+
+ try
+ {
+ bais = new java.io.ByteArrayInputStream( objBytes );
+ ois = new java.io.ObjectInputStream( bais );
+
+ obj = ois.readObject();
+ } // end try
+ catch( java.io.IOException e )
+ {
+ e.printStackTrace();
+ obj = null;
+ } // end catch
+ catch( java.lang.ClassNotFoundException e )
+ {
+ e.printStackTrace();
+ obj = null;
+ } // end catch
+ finally
+ {
+ try{ bais.close(); } catch( Exception e ){}
+ try{ ois.close(); } catch( Exception e ){}
+ } // end finally
+
+ return obj;
+ } // end decodeObject
+
+
+
+ /**
+ * Convenience method for encoding data to a file.
+ *
+ * @param dataToEncode byte array of data to encode in base64 form
+ * @param filename Filename for saving encoded data
+ * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
+ *
+ * @since 2.1
+ */
+ public static boolean encodeToFile( byte[] dataToEncode, String filename )
+ {
+ boolean success = false;
+ Base64.OutputStream bos = null;
+ try
+ {
+ bos = new Base64.OutputStream(
+ new java.io.FileOutputStream( filename ), Base64.ENCODE );
+ bos.write( dataToEncode );
+ success = true;
+ } // end try
+ catch( java.io.IOException e )
+ {
+
+ success = false;
+ } // end catch: IOException
+ finally
+ {
+ try{ bos.close(); } catch( Exception e ){}
+ } // end finally
+
+ return success;
+ } // end encodeToFile
+
+
+ /**
+ * Convenience method for decoding data to a file.
+ *
+ * @param dataToDecode Base64-encoded data as a string
+ * @param filename Filename for saving decoded data
+ * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
+ *
+ * @since 2.1
+ */
+ public static boolean decodeToFile( String dataToDecode, String filename )
+ {
+ boolean success = false;
+ Base64.OutputStream bos = null;
+ try
+ {
+ bos = new Base64.OutputStream(
+ new java.io.FileOutputStream( filename ), Base64.DECODE );
+ bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) );
+ success = true;
+ } // end try
+ catch( java.io.IOException e )
+ {
+ success = false;
+ } // end catch: IOException
+ finally
+ {
+ try{ bos.close(); } catch( Exception e ){}
+ } // end finally
+
+ return success;
+ } // end decodeToFile
+
+
+
+
+ /**
+ * Convenience method for reading a base64-encoded
+ * file and decoding it.
+ *
+ * @param filename Filename for reading encoded data
+ * @return decoded byte array or null if unsuccessful
+ *
+ * @since 2.1
+ */
+ public static byte[] decodeFromFile( String filename )
+ {
+ byte[] decodedData = null;
+ Base64.InputStream bis = null;
+ try
+ {
+ // Set up some useful variables
+ java.io.File file = new java.io.File( filename );
+ byte[] buffer = null;
+ int length = 0;
+ int numBytes = 0;
+
+ // Check for size of file
+ if( file.length() > Integer.MAX_VALUE )
+ {
+ System.err.println( "File is too big for this convenience method (" + file.length() + " bytes)." );
+ return null;
+ } // end if: file too big for int index
+ buffer = new byte[ (int)file.length() ];
+
+ // Open a stream
+ bis = new Base64.InputStream(
+ new java.io.BufferedInputStream(
+ new java.io.FileInputStream( file ) ), Base64.DECODE );
+
+ // Read until done
+ while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 )
+ length += numBytes;
+
+ // Save in a variable to return
+ decodedData = new byte[ length ];
+ System.arraycopy( buffer, 0, decodedData, 0, length );
+
+ } // end try
+ catch( java.io.IOException e )
+ {
+ System.err.println( "Error decoding from file " + filename );
+ } // end catch: IOException
+ finally
+ {
+ try{ bis.close(); } catch( Exception e) {}
+ } // end finally
+
+ return decodedData;
+ } // end decodeFromFile
+
+
+
+ /**
+ * Convenience method for reading a binary file
+ * and base64-encoding it.
+ *
+ * @param filename Filename for reading binary data
+ * @return base64-encoded string or null if unsuccessful
+ *
+ * @since 2.1
+ */
+ public static String encodeFromFile( String filename )
+ {
+ String encodedData = null;
+ Base64.InputStream bis = null;
+ try
+ {
+ // Set up some useful variables
+ java.io.File file = new java.io.File( filename );
+ byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4),40) ]; // Need max() for math on small files (v2.2.1)
+ int length = 0;
+ int numBytes = 0;
+
+ // Open a stream
+ bis = new Base64.InputStream(
+ new java.io.BufferedInputStream(
+ new java.io.FileInputStream( file ) ), Base64.ENCODE );
+
+ // Read until done
+ while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 )
+ length += numBytes;
+
+ // Save in a variable to return
+ encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING );
+
+ } // end try
+ catch( java.io.IOException e )
+ {
+ System.err.println( "Error encoding from file " + filename );
+ } // end catch: IOException
+ finally
+ {
+ try{ bis.close(); } catch( Exception e) {}
+ } // end finally
+
+ return encodedData;
+ } // end encodeFromFile
+
+ /**
+ * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.
+ *
+ * @param infile Input file
+ * @param outfile Output file
+ * @since 2.2
+ */
+ public static void encodeFileToFile( String infile, String outfile )
+ {
+ String encoded = Base64.encodeFromFile( infile );
+ java.io.OutputStream out = null;
+ try{
+ out = new java.io.BufferedOutputStream(
+ new java.io.FileOutputStream( outfile ) );
+ out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output.
+ } // end try
+ catch( java.io.IOException ex ) {
+ ex.printStackTrace();
+ } // end catch
+ finally {
+ try { out.close(); }
+ catch( Exception ex ){}
+ } // end finally
+ } // end encodeFileToFile
+
+
+ /**
+ * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.
+ *
+ * @param infile Input file
+ * @param outfile Output file
+ * @since 2.2
+ */
+ public static void decodeFileToFile( String infile, String outfile )
+ {
+ byte[] decoded = Base64.decodeFromFile( infile );
+ java.io.OutputStream out = null;
+ try{
+ out = new java.io.BufferedOutputStream(
+ new java.io.FileOutputStream( outfile ) );
+ out.write( decoded );
+ } // end try
+ catch( java.io.IOException ex ) {
+ ex.printStackTrace();
+ } // end catch
+ finally {
+ try { out.close(); }
+ catch( Exception ex ){}
+ } // end finally
+ } // end decodeFileToFile
+
+
+ /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */
+
+
+
+ /**
+ * A {@link Base64.InputStream} will read data from another
+ * <tt>java.io.InputStream</tt>, given in the constructor,
+ * and encode/decode to/from Base64 notation on the fly.
+ *
+ * @see Base64
+ * @since 1.3
+ */
+ public static class InputStream extends java.io.FilterInputStream
+ {
+ private boolean encode; // Encoding or decoding
+ private int position; // Current position in the buffer
+ private byte[] buffer; // Small buffer holding converted data
+ private int bufferLength; // Length of buffer (3 or 4)
+ private int numSigBytes; // Number of meaningful bytes in the buffer
+ private int lineLength;
+ private boolean breakLines; // Break lines at less than 80 characters
+ private int options; // Record options used to create the stream.
+ private byte[] alphabet; // Local copies to avoid extra method calls
+ private byte[] decodabet; // Local copies to avoid extra method calls
+
+
+ /**
+ * Constructs a {@link Base64.InputStream} in DECODE mode.
+ *
+ * @param in the <tt>java.io.InputStream</tt> from which to read data.
+ * @since 1.3
+ */
+ public InputStream( java.io.InputStream in )
+ {
+ this( in, DECODE );
+ } // end constructor
+
+
+ /**
+ * Constructs a {@link Base64.InputStream} in
+ * either ENCODE or DECODE mode.
+ * <p>
+ * Valid options:<pre>
+ * ENCODE or DECODE: Encode or Decode as data is read.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * (only meaningful when encoding)
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>
+ * </pre>
+ * <p>
+ * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
+ *
+ *
+ * @param in the <tt>java.io.InputStream</tt> from which to read data.
+ * @param options Specified options
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public InputStream( java.io.InputStream in, int options )
+ {
+ super( in );
+ this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
+ this.encode = (options & ENCODE) == ENCODE;
+ this.bufferLength = encode ? 4 : 3;
+ this.buffer = new byte[ bufferLength ];
+ this.position = -1;
+ this.lineLength = 0;
+ this.options = options; // Record for later, mostly to determine which alphabet to use
+ this.alphabet = getAlphabet(options);
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+ /**
+ * Reads enough of the input stream to convert
+ * to/from Base64 and returns the next byte.
+ *
+ * @return next byte
+ * @since 1.3
+ */
+ public int read() throws java.io.IOException
+ {
+ // Do we need to get data?
+ if( position < 0 )
+ {
+ if( encode )
+ {
+ byte[] b3 = new byte[3];
+ int numBinaryBytes = 0;
+ for( int i = 0; i < 3; i++ )
+ {
+ try
+ {
+ int b = in.read();
+
+ // If end of stream, b is -1.
+ if( b >= 0 )
+ {
+ b3[i] = (byte)b;
+ numBinaryBytes++;
+ } // end if: not end of stream
+
+ } // end try: read
+ catch( java.io.IOException e )
+ {
+ // Only a problem if we got no data at all.
+ if( i == 0 )
+ throw e;
+
+ } // end catch
+ } // end for: each needed input byte
+
+ if( numBinaryBytes > 0 )
+ {
+ encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
+ position = 0;
+ numSigBytes = 4;
+ } // end if: got data
+ else
+ {
+ return -1;
+ } // end else
+ } // end if: encoding
+
+ // Else decoding
+ else
+ {
+ byte[] b4 = new byte[4];
+ int i = 0;
+ for( i = 0; i < 4; i++ )
+ {
+ // Read four "meaningful" bytes:
+ int b = 0;
+ do{ b = in.read(); }
+ while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
+
+ if( b < 0 )
+ break; // Reads a -1 if end of stream
+
+ b4[i] = (byte)b;
+ } // end for: each needed input byte
+
+ if( i == 4 )
+ {
+ numSigBytes = decode4to3( b4, 0, buffer, 0, options );
+ position = 0;
+ } // end if: got four characters
+ else if( i == 0 ){
+ return -1;
+ } // end else if: also padded correctly
+ else
+ {
+ // Must have broken out from above.
+ throw new java.io.IOException( "Improperly padded Base64 input." );
+ } // end
+
+ } // end else: decode
+ } // end else: get data
+
+ // Got data?
+ if( position >= 0 )
+ {
+ // End of relevant data?
+ if( /*!encode &&*/ position >= numSigBytes )
+ return -1;
+
+ if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
+ {
+ lineLength = 0;
+ return '\n';
+ } // end if
+ else
+ {
+ lineLength++; // This isn't important when decoding
+ // but throwing an extra "if" seems
+ // just as wasteful.
+
+ int b = buffer[ position++ ];
+
+ if( position >= bufferLength )
+ position = -1;
+
+ return b & 0xFF; // This is how you "cast" a byte that's
+ // intended to be unsigned.
+ } // end else
+ } // end if: position >= 0
+
+ // Else error
+ else
+ {
+ // When JDK1.4 is more accepted, use an assertion here.
+ throw new java.io.IOException( "Error in Base64 code reading stream." );
+ } // end else
+ } // end read
+
+
+ /**
+ * Calls {@link #read()} repeatedly until the end of stream
+ * is reached or <var>len</var> bytes are read.
+ * Returns number of bytes read into array or -1 if
+ * end of stream is encountered.
+ *
+ * @param dest array to hold values
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @return bytes read into array or -1 if end of stream is encountered.
+ * @since 1.3
+ */
+ public int read( byte[] dest, int off, int len ) throws java.io.IOException
+ {
+ int i;
+ int b;
+ for( i = 0; i < len; i++ )
+ {
+ b = read();
+
+ //if( b < 0 && i == 0 )
+ // return -1;
+
+ if( b >= 0 )
+ dest[off + i] = (byte)b;
+ else if( i == 0 )
+ return -1;
+ else
+ break; // Out of 'for' loop
+ } // end for: each byte read
+ return i;
+ } // end read
+
+ } // end inner class InputStream
+
+
+
+
+
+
+ /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
+
+
+
+ /**
+ * A {@link Base64.OutputStream} will write data to another
+ * <tt>java.io.OutputStream</tt>, given in the constructor,
+ * and encode/decode to/from Base64 notation on the fly.
+ *
+ * @see Base64
+ * @since 1.3
+ */
+ public static class OutputStream extends java.io.FilterOutputStream
+ {
+ private boolean encode;
+ private int position;
+ private byte[] buffer;
+ private int bufferLength;
+ private int lineLength;
+ private boolean breakLines;
+ private byte[] b4; // Scratch used in a few places
+ private boolean suspendEncoding;
+ private int options; // Record for later
+ private byte[] alphabet; // Local copies to avoid extra method calls
+ private byte[] decodabet; // Local copies to avoid extra method calls
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in ENCODE mode.
+ *
+ * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
+ * @since 1.3
+ */
+ public OutputStream( java.io.OutputStream out )
+ {
+ this( out, ENCODE );
+ } // end constructor
+
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in
+ * either ENCODE or DECODE mode.
+ * <p>
+ * Valid options:<pre>
+ * ENCODE or DECODE: Encode or Decode as data is read.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * (only meaningful when encoding)
+ * <i>Note: Technically, this makes your encoding non-compliant.</i>
+ * </pre>
+ * <p>
+ * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
+ *
+ * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
+ * @param options Specified options.
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DONT_BREAK_LINES
+ * @since 1.3
+ */
+ public OutputStream( java.io.OutputStream out, int options )
+ {
+ super( out );
+ this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
+ this.encode = (options & ENCODE) == ENCODE;
+ this.bufferLength = encode ? 3 : 4;
+ this.buffer = new byte[ bufferLength ];
+ this.position = 0;
+ this.lineLength = 0;
+ this.suspendEncoding = false;
+ this.b4 = new byte[4];
+ this.options = options;
+ this.alphabet = getAlphabet(options);
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+
+ /**
+ * Writes the byte to the output stream after
+ * converting to/from Base64 notation.
+ * When encoding, bytes are buffered three
+ * at a time before the output stream actually
+ * gets a write() call.
+ * When decoding, bytes are buffered four
+ * at a time.
+ *
+ * @param theByte the byte to write
+ * @since 1.3
+ */
+ public void write(int theByte) throws java.io.IOException
+ {
+ // Encoding suspended?
+ if( suspendEncoding )
+ {
+ super.out.write( theByte );
+ return;
+ } // end if: supsended
+
+ // Encode?
+ if( encode )
+ {
+ buffer[ position++ ] = (byte)theByte;
+ if( position >= bufferLength ) // Enough to encode.
+ {
+ out.write( encode3to4( b4, buffer, bufferLength, options ) );
+
+ lineLength += 4;
+ if( breakLines && lineLength >= MAX_LINE_LENGTH )
+ {
+ out.write( NEW_LINE );
+ lineLength = 0;
+ } // end if: end of line
+
+ position = 0;
+ } // end if: enough to output
+ } // end if: encoding
+
+ // Else, Decoding
+ else
+ {
+ // Meaningful Base64 character?
+ if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC )
+ {
+ buffer[ position++ ] = (byte)theByte;
+ if( position >= bufferLength ) // Enough to output.
+ {
+ int len = Base64.decode4to3( buffer, 0, b4, 0, options );
+ out.write( b4, 0, len );
+ //out.write( Base64.decode4to3( buffer ) );
+ position = 0;
+ } // end if: enough to output
+ } // end if: meaningful base64 character
+ else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC )
+ {
+ throw new java.io.IOException( "Invalid character in Base64 data." );
+ } // end else: not white space either
+ } // end else: decoding
+ } // end write
+
+
+
+ /**
+ * Calls {@link #write(int)} repeatedly until <var>len</var>
+ * bytes are written.
+ *
+ * @param theBytes array from which to read bytes
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @since 1.3
+ */
+ public void write( byte[] theBytes, int off, int len ) throws java.io.IOException
+ {
+ // Encoding suspended?
+ if( suspendEncoding )
+ {
+ super.out.write( theBytes, off, len );
+ return;
+ } // end if: supsended
+
+ for( int i = 0; i < len; i++ )
+ {
+ write( theBytes[ off + i ] );
+ } // end for: each byte written
+
+ } // end write
+
+
+
+ /**
+ * Method added by PHIL. [Thanks, PHIL. -Rob]
+ * This pads the buffer without closing the stream.
+ */
+ public void flushBase64() throws java.io.IOException
+ {
+ if( position > 0 )
+ {
+ if( encode )
+ {
+ out.write( encode3to4( b4, buffer, position, options ) );
+ position = 0;
+ } // end if: encoding
+ else
+ {
+ throw new java.io.IOException( "Base64 input not properly padded." );
+ } // end else: decoding
+ } // end if: buffer partially full
+
+ } // end flush
+
+
+ /**
+ * Flushes and closes (I think, in the superclass) the stream.
+ *
+ * @since 1.3
+ */
+ public void close() throws java.io.IOException
+ {
+ // 1. Ensure that pending characters are written
+ flushBase64();
+
+ // 2. Actually close the stream
+ // Base class both flushes and closes.
+ super.close();
+
+ buffer = null;
+ out = null;
+ } // end close
+
+
+
+ /**
+ * Suspends encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base640-encoded data in a stream.
+ *
+ * @since 1.5.1
+ */
+ public void suspendEncoding() throws java.io.IOException
+ {
+ flushBase64();
+ this.suspendEncoding = true;
+ } // end suspendEncoding
+
+
+ /**
+ * Resumes encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base640-encoded data in a stream.
+ *
+ * @since 1.5.1
+ */
+ public void resumeEncoding()
+ {
+ this.suspendEncoding = false;
+ } // end resumeEncoding
+
+
+
+ } // end inner class OutputStream
+
+
+} // end class Base64
+
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/SyncPacketSend.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/SyncPacketSend.java
index 6506cbd88..58cf1f85f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/SyncPacketSend.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smack/util/SyncPacketSend.java
@@ -1,64 +1,64 @@
-/**
- * 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;
-
-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;
-import org.jivesoftware.smack.packet.Packet;
-
-/**
- * Utility class for doing synchronous calls to the server. Provides several
- * methods for sending a packet to the server and waiting for the reply.
- *
- * @author Robin Collier
- */
-final public class SyncPacketSend
-{
- private SyncPacketSend()
- { }
-
- static public Packet getReply(Connection connection, Packet packet, long timeout)
- throws XMPPException
- {
- PacketFilter responseFilter = new PacketIDFilter(packet.getPacketID());
- PacketCollector response = connection.createPacketCollector(responseFilter);
-
- connection.sendPacket(packet);
-
- // Wait up to a certain number of seconds for a reply.
- Packet result = response.nextResult(timeout);
-
- // Stop queuing results
- response.cancel();
-
- if (result == null) {
- throw new XMPPException(SmackError.NO_RESPONSE_FROM_SERVER);
- }
- else if (result.getError() != null) {
- throw new XMPPException(result.getError());
- }
- return result;
- }
-
- static public Packet getReply(Connection connection, Packet packet)
- throws XMPPException
- {
- return getReply(connection, packet, SmackConfiguration.getPacketReplyTimeout());
- }
-}
+/**
+ * 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;
+
+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;
+import org.jivesoftware.smack.packet.Packet;
+
+/**
+ * Utility class for doing synchronous calls to the server. Provides several
+ * methods for sending a packet to the server and waiting for the reply.
+ *
+ * @author Robin Collier
+ */
+final public class SyncPacketSend
+{
+ private SyncPacketSend()
+ { }
+
+ static public Packet getReply(Connection connection, Packet packet, long timeout)
+ throws XMPPException
+ {
+ PacketFilter responseFilter = new PacketIDFilter(packet.getPacketID());
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+
+ connection.sendPacket(packet);
+
+ // Wait up to a certain number of seconds for a reply.
+ Packet result = response.nextResult(timeout);
+
+ // Stop queuing results
+ response.cancel();
+
+ if (result == null) {
+ throw new XMPPException(SmackError.NO_RESPONSE_FROM_SERVER);
+ }
+ else if (result.getError() != null) {
+ throw new XMPPException(result.getError());
+ }
+ return result;
+ }
+
+ static public Packet getReply(Connection connection, Packet packet)
+ throws XMPPException
+ {
+ return getReply(connection, packet, SmackConfiguration.getPacketReplyTimeout());
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/LastActivityManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/LastActivityManager.java
index a9d1f12b8..7729bc07a 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/LastActivityManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/LastActivityManager.java
@@ -1,230 +1,230 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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;
-
-import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.IQTypeFilter;
-import org.jivesoftware.smack.filter.PacketIDFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Message;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.Presence;
-import org.jivesoftware.smackx.packet.DiscoverInfo;
-import org.jivesoftware.smackx.packet.LastActivity;
-
-/**
- * A last activity manager for handling information about the last activity
- * associated with a Jabber ID. A manager handles incoming LastActivity requests
- * of existing Connections. It also allows to request last activity information
- * of other users.
- * <p>
- *
- * LastActivity (XEP-0012) based on the sending JID's type allows for retrieval
- * of:
- * <ol>
- * <li>How long a particular user has been idle
- * <li>How long a particular user has been logged-out and the message the
- * specified when doing so.
- * <li>How long a host has been up.
- * </ol>
- * <p/>
- *
- * For example to get the idle time of a user logged in a resource, simple send
- * the LastActivity packet to them, as in the following code:
- * <p>
- *
- * <pre>
- * Connection con = new XMPPConnection(&quot;jabber.org&quot;);
- * con.login(&quot;john&quot;, &quot;doe&quot;);
- * LastActivity activity = LastActivity.getLastActivity(con, &quot;xray@jabber.org/Smack&quot;);
- * </pre>
- *
- * To get the lapsed time since the last user logout is the same as above but
- * with out the resource:
- *
- * <pre>
- * LastActivity activity = LastActivity.getLastActivity(con, &quot;xray@jabber.org&quot;);
- * </pre>
- *
- * To get the uptime of a host, you simple send the LastActivity packet to it,
- * as in the following code example:
- * <p>
- *
- * <pre>
- * LastActivity activity = LastActivity.getLastActivity(con, &quot;jabber.org&quot;);
- * </pre>
- *
- * @author Gabriel Guardincerri
- * @see <a href="http://xmpp.org/extensions/xep-0012.html">XEP-0012: Last
- * Activity</a>
- */
-
-public class LastActivityManager {
-
- private long lastMessageSent;
-
- private Connection connection;
-
- // Enable the LastActivity support on every established connection
- static {
- Connection.addConnectionCreationListener(new ConnectionCreationListener() {
- public void connectionCreated(Connection connection) {
- new LastActivityManager(connection);
- }
- });
- }
-
- /**
- * Creates a last activity manager to response last activity requests.
- *
- * @param connection
- * The Connection that the last activity requests will use.
- */
- private LastActivityManager(Connection connection) {
- this.connection = connection;
-
- // Listen to all the sent messages to reset the idle time on each one
- connection.addPacketSendingListener(new PacketListener() {
- public void processPacket(Packet packet) {
- Presence presence = (Presence) packet;
- Presence.Mode mode = presence.getMode();
- if (mode == null) return;
- switch (mode) {
- case available:
- case chat:
- // We assume that only a switch to available and chat indicates user activity
- // since other mode changes could be also a result of some sort of automatism
- resetIdleTime();
- }
- }
- }, new PacketTypeFilter(Presence.class));
-
- connection.addPacketListener(new PacketListener() {
- @Override
- public void processPacket(Packet packet) {
- Message message = (Message) packet;
- // if it's not an error message, reset the idle time
- if (message.getType() == Message.Type.error) return;
- resetIdleTime();
- }
- }, new PacketTypeFilter(Message.class));
-
- // Register a listener for a last activity query
- connection.addPacketListener(new PacketListener() {
-
- public void processPacket(Packet packet) {
- LastActivity message = new LastActivity();
- message.setType(IQ.Type.RESULT);
- message.setTo(packet.getFrom());
- message.setFrom(packet.getTo());
- message.setPacketID(packet.getPacketID());
- message.setLastActivity(getIdleTime());
-
- LastActivityManager.this.connection.sendPacket(message);
- }
-
- }, new AndFilter(new IQTypeFilter(IQ.Type.GET), new PacketTypeFilter(LastActivity.class)));
- ServiceDiscoveryManager.getInstanceFor(connection).addFeature(LastActivity.NAMESPACE);
- resetIdleTime();
- }
-
- /**
- * Resets the idle time to 0, this should be invoked when a new message is
- * sent.
- */
- private void resetIdleTime() {
- long now = System.currentTimeMillis();
- synchronized (this) {
- lastMessageSent = now;
- }
- }
-
- /**
- * The idle time is the lapsed time between the last message sent and now.
- *
- * @return the lapsed time between the last message sent and now.
- */
- private long getIdleTime() {
- long lms;
- long now = System.currentTimeMillis();
- synchronized (this) {
- lms = lastMessageSent;
- }
- return ((now - lms) / 1000);
- }
-
- /**
- * Returns the last activity of a particular jid. If the jid is a full JID
- * (i.e., a JID of the form of 'user@host/resource') then the last activity
- * is the idle time of that connected resource. On the other hand, when the
- * jid is a bare JID (e.g. 'user@host') then the last activity is the lapsed
- * time since the last logout or 0 if the user is currently logged in.
- * Moreover, when the jid is a server or component (e.g., a JID of the form
- * 'host') the last activity is the uptime.
- *
- * @param con
- * the current Connection.
- * @param jid
- * the JID of the user.
- * @return the LastActivity packet of the jid.
- * @throws XMPPException
- * thrown if a server error has occured.
- */
- public static LastActivity getLastActivity(Connection con, String jid) throws XMPPException {
- LastActivity activity = new LastActivity();
- activity.setTo(jid);
-
- PacketCollector collector = con.createPacketCollector(new PacketIDFilter(activity.getPacketID()));
- con.sendPacket(activity);
-
- LastActivity response = (LastActivity) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * Returns true if Last Activity (XEP-0012) is supported by a given JID
- *
- * @param connection the connection to be used
- * @param jid a JID to be tested for Last Activity support
- * @return true if Last Activity is supported, otherwise false
- */
- public static boolean isLastActivitySupported(Connection connection, String jid) {
- try {
- DiscoverInfo result =
- ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
- return result.containsFeature(LastActivity.NAMESPACE);
- }
- catch (XMPPException e) {
- return false;
- }
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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;
+
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.IQTypeFilter;
+import org.jivesoftware.smack.filter.PacketIDFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.Presence;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
+import org.jivesoftware.smackx.packet.LastActivity;
+
+/**
+ * A last activity manager for handling information about the last activity
+ * associated with a Jabber ID. A manager handles incoming LastActivity requests
+ * of existing Connections. It also allows to request last activity information
+ * of other users.
+ * <p>
+ *
+ * LastActivity (XEP-0012) based on the sending JID's type allows for retrieval
+ * of:
+ * <ol>
+ * <li>How long a particular user has been idle
+ * <li>How long a particular user has been logged-out and the message the
+ * specified when doing so.
+ * <li>How long a host has been up.
+ * </ol>
+ * <p/>
+ *
+ * For example to get the idle time of a user logged in a resource, simple send
+ * the LastActivity packet to them, as in the following code:
+ * <p>
+ *
+ * <pre>
+ * Connection con = new XMPPConnection(&quot;jabber.org&quot;);
+ * con.login(&quot;john&quot;, &quot;doe&quot;);
+ * LastActivity activity = LastActivity.getLastActivity(con, &quot;xray@jabber.org/Smack&quot;);
+ * </pre>
+ *
+ * To get the lapsed time since the last user logout is the same as above but
+ * with out the resource:
+ *
+ * <pre>
+ * LastActivity activity = LastActivity.getLastActivity(con, &quot;xray@jabber.org&quot;);
+ * </pre>
+ *
+ * To get the uptime of a host, you simple send the LastActivity packet to it,
+ * as in the following code example:
+ * <p>
+ *
+ * <pre>
+ * LastActivity activity = LastActivity.getLastActivity(con, &quot;jabber.org&quot;);
+ * </pre>
+ *
+ * @author Gabriel Guardincerri
+ * @see <a href="http://xmpp.org/extensions/xep-0012.html">XEP-0012: Last
+ * Activity</a>
+ */
+
+public class LastActivityManager {
+
+ private long lastMessageSent;
+
+ private Connection connection;
+
+ // Enable the LastActivity support on every established connection
+ static {
+ Connection.addConnectionCreationListener(new ConnectionCreationListener() {
+ public void connectionCreated(Connection connection) {
+ new LastActivityManager(connection);
+ }
+ });
+ }
+
+ /**
+ * Creates a last activity manager to response last activity requests.
+ *
+ * @param connection
+ * The Connection that the last activity requests will use.
+ */
+ private LastActivityManager(Connection connection) {
+ this.connection = connection;
+
+ // Listen to all the sent messages to reset the idle time on each one
+ connection.addPacketSendingListener(new PacketListener() {
+ public void processPacket(Packet packet) {
+ Presence presence = (Presence) packet;
+ Presence.Mode mode = presence.getMode();
+ if (mode == null) return;
+ switch (mode) {
+ case available:
+ case chat:
+ // We assume that only a switch to available and chat indicates user activity
+ // since other mode changes could be also a result of some sort of automatism
+ resetIdleTime();
+ }
+ }
+ }, new PacketTypeFilter(Presence.class));
+
+ connection.addPacketListener(new PacketListener() {
+ @Override
+ public void processPacket(Packet packet) {
+ Message message = (Message) packet;
+ // if it's not an error message, reset the idle time
+ if (message.getType() == Message.Type.error) return;
+ resetIdleTime();
+ }
+ }, new PacketTypeFilter(Message.class));
+
+ // Register a listener for a last activity query
+ connection.addPacketListener(new PacketListener() {
+
+ public void processPacket(Packet packet) {
+ LastActivity message = new LastActivity();
+ message.setType(IQ.Type.RESULT);
+ message.setTo(packet.getFrom());
+ message.setFrom(packet.getTo());
+ message.setPacketID(packet.getPacketID());
+ message.setLastActivity(getIdleTime());
+
+ LastActivityManager.this.connection.sendPacket(message);
+ }
+
+ }, new AndFilter(new IQTypeFilter(IQ.Type.GET), new PacketTypeFilter(LastActivity.class)));
+ ServiceDiscoveryManager.getInstanceFor(connection).addFeature(LastActivity.NAMESPACE);
+ resetIdleTime();
+ }
+
+ /**
+ * Resets the idle time to 0, this should be invoked when a new message is
+ * sent.
+ */
+ private void resetIdleTime() {
+ long now = System.currentTimeMillis();
+ synchronized (this) {
+ lastMessageSent = now;
+ }
+ }
+
+ /**
+ * The idle time is the lapsed time between the last message sent and now.
+ *
+ * @return the lapsed time between the last message sent and now.
+ */
+ private long getIdleTime() {
+ long lms;
+ long now = System.currentTimeMillis();
+ synchronized (this) {
+ lms = lastMessageSent;
+ }
+ return ((now - lms) / 1000);
+ }
+
+ /**
+ * Returns the last activity of a particular jid. If the jid is a full JID
+ * (i.e., a JID of the form of 'user@host/resource') then the last activity
+ * is the idle time of that connected resource. On the other hand, when the
+ * jid is a bare JID (e.g. 'user@host') then the last activity is the lapsed
+ * time since the last logout or 0 if the user is currently logged in.
+ * Moreover, when the jid is a server or component (e.g., a JID of the form
+ * 'host') the last activity is the uptime.
+ *
+ * @param con
+ * the current Connection.
+ * @param jid
+ * the JID of the user.
+ * @return the LastActivity packet of the jid.
+ * @throws XMPPException
+ * thrown if a server error has occured.
+ */
+ public static LastActivity getLastActivity(Connection con, String jid) throws XMPPException {
+ LastActivity activity = new LastActivity();
+ activity.setTo(jid);
+
+ PacketCollector collector = con.createPacketCollector(new PacketIDFilter(activity.getPacketID()));
+ con.sendPacket(activity);
+
+ LastActivity response = (LastActivity) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * Returns true if Last Activity (XEP-0012) is supported by a given JID
+ *
+ * @param connection the connection to be used
+ * @param jid a JID to be tested for Last Activity support
+ * @return true if Last Activity is supported, otherwise false
+ */
+ public static boolean isLastActivitySupported(Connection connection, String jid) {
+ try {
+ DiscoverInfo result =
+ ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
+ return result.containsFeature(LastActivity.NAMESPACE);
+ }
+ catch (XMPPException e) {
+ return false;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/SharedGroupManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/SharedGroupManager.java
index 76cd527c5..44ab67070 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/SharedGroupManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/SharedGroupManager.java
@@ -17,56 +17,56 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smackx;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.PacketCollector;
-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.smackx.packet.SharedGroupsInfo;
-
-import java.util.List;
-
-/**
- * A SharedGroupManager provides services for discovering the shared groups where a user belongs.<p>
- *
- * Important note: This functionality is not part of the XMPP spec and it will only work
- * with Wildfire.
- *
- * @author Gaston Dombiak
- */
-public class SharedGroupManager {
-
- /**
- * Returns the collection that will contain the name of the shared groups where the user
- * logged in with the specified session belongs.
- *
- * @param connection connection to use to get the user's shared groups.
- * @return collection with the shared groups' name of the logged user.
- */
- public static List<String> getSharedGroups(Connection connection) throws XMPPException {
- // Discover the shared groups of the logged user
- SharedGroupsInfo info = new SharedGroupsInfo();
- info.setType(IQ.Type.GET);
-
- // Create a packet collector to listen for a response.
- PacketCollector collector =
- connection.createPacketCollector(new PacketIDFilter(info.getPacketID()));
-
- connection.sendPacket(info);
-
- // Wait up to 5 seconds for a result.
- IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- // Stop queuing results
- collector.cancel();
- if (result == null) {
- throw new XMPPException("No response from the server.");
- }
- if (result.getType() == IQ.Type.ERROR) {
- throw new XMPPException(result.getError());
- }
- return ((SharedGroupsInfo) result).getGroups();
- }
-}
+package org.jivesoftware.smackx;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.PacketCollector;
+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.smackx.packet.SharedGroupsInfo;
+
+import java.util.List;
+
+/**
+ * A SharedGroupManager provides services for discovering the shared groups where a user belongs.<p>
+ *
+ * Important note: This functionality is not part of the XMPP spec and it will only work
+ * with Wildfire.
+ *
+ * @author Gaston Dombiak
+ */
+public class SharedGroupManager {
+
+ /**
+ * Returns the collection that will contain the name of the shared groups where the user
+ * logged in with the specified session belongs.
+ *
+ * @param connection connection to use to get the user's shared groups.
+ * @return collection with the shared groups' name of the logged user.
+ */
+ public static List<String> getSharedGroups(Connection connection) throws XMPPException {
+ // Discover the shared groups of the logged user
+ SharedGroupsInfo info = new SharedGroupsInfo();
+ info.setType(IQ.Type.GET);
+
+ // Create a packet collector to listen for a response.
+ PacketCollector collector =
+ connection.createPacketCollector(new PacketIDFilter(info.getPacketID()));
+
+ connection.sendPacket(info);
+
+ // Wait up to 5 seconds for a result.
+ IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+ // Stop queuing results
+ collector.cancel();
+ if (result == null) {
+ throw new XMPPException("No response from the server.");
+ }
+ if (result.getType() == IQ.Type.ERROR) {
+ throw new XMPPException(result.getError());
+ }
+ return ((SharedGroupsInfo) result).getGroups();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamListener.java
index be78255d5..87ab2f5ee 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamListener.java
@@ -1,47 +1,47 @@
-/**
- * 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.bytestreams;
-
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamListener;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
-
-/**
- * BytestreamListener are notified if a remote user wants to initiate a bytestream. Implement this
- * interface to handle incoming bytestream requests.
- * <p>
- * BytestreamListener can be registered at the {@link Socks5BytestreamManager} or the
- * {@link InBandBytestreamManager}.
- * <p>
- * There are two ways to add this listener. See
- * {@link BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
- * {@link BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for further
- * details.
- * <p>
- * {@link Socks5BytestreamListener} or {@link InBandBytestreamListener} provide a more specific
- * interface of the BytestreamListener.
- *
- * @author Henning Staib
- */
-public interface BytestreamListener {
-
- /**
- * This listener is notified if a bytestream request from another user has been received.
- *
- * @param request the incoming bytestream request
- */
- public void incomingBytestreamRequest(BytestreamRequest request);
-
-}
+/**
+ * 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.bytestreams;
+
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamListener;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
+
+/**
+ * BytestreamListener are notified if a remote user wants to initiate a bytestream. Implement this
+ * interface to handle incoming bytestream requests.
+ * <p>
+ * BytestreamListener can be registered at the {@link Socks5BytestreamManager} or the
+ * {@link InBandBytestreamManager}.
+ * <p>
+ * There are two ways to add this listener. See
+ * {@link BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
+ * {@link BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for further
+ * details.
+ * <p>
+ * {@link Socks5BytestreamListener} or {@link InBandBytestreamListener} provide a more specific
+ * interface of the BytestreamListener.
+ *
+ * @author Henning Staib
+ */
+public interface BytestreamListener {
+
+ /**
+ * This listener is notified if a bytestream request from another user has been received.
+ *
+ * @param request the incoming bytestream request
+ */
+ public void incomingBytestreamRequest(BytestreamRequest request);
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamManager.java
index ca6bbc602..232af2a2a 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamManager.java
@@ -1,114 +1,114 @@
-/**
- * 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.bytestreams;
-
-import java.io.IOException;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
-
-/**
- * BytestreamManager provides a generic interface for bytestream managers.
- * <p>
- * There are two implementations of the interface. See {@link Socks5BytestreamManager} and
- * {@link InBandBytestreamManager}.
- *
- * @author Henning Staib
- */
-public interface BytestreamManager {
-
- /**
- * Adds {@link BytestreamListener} that is called for every incoming bytestream request unless
- * there is a user specific {@link BytestreamListener} registered.
- * <p>
- * See {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
- * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener)} for further
- * details.
- *
- * @param listener the listener to register
- */
- public void addIncomingBytestreamListener(BytestreamListener listener);
-
- /**
- * Removes the given listener from the list of listeners for all incoming bytestream requests.
- *
- * @param listener the listener to remove
- */
- public void removeIncomingBytestreamListener(BytestreamListener listener);
-
- /**
- * Adds {@link BytestreamListener} that is called for every incoming bytestream request unless
- * there is a user specific {@link BytestreamListener} registered.
- * <p>
- * Use this method if you are awaiting an incoming bytestream request from a specific user.
- * <p>
- * See {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)}
- * and {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)}
- * for further details.
- *
- * @param listener the listener to register
- * @param initiatorJID the JID of the user that wants to establish a bytestream
- */
- public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID);
-
- /**
- * Removes the listener for the given user.
- *
- * @param initiatorJID the JID of the user the listener should be removed
- */
- public void removeIncomingBytestreamListener(String initiatorJID);
-
- /**
- * Establishes a bytestream with the given user and returns the session to send/receive data
- * to/from the user.
- * <p>
- * Use this method to establish bytestreams to users accepting all incoming bytestream requests
- * since this method doesn't provide a way to tell the user something about the data to be sent.
- * <p>
- * To establish a bytestream after negotiation the kind of data to be sent (e.g. file transfer)
- * use {@link #establishSession(String, String)}.
- * <p>
- * See {@link Socks5BytestreamManager#establishSession(String)} and
- * {@link InBandBytestreamManager#establishSession(String)} for further details.
- *
- * @param targetJID the JID of the user a bytestream should be established
- * @return the session to send/receive data to/from the user
- * @throws XMPPException if an error occurred while establishing the session
- * @throws IOException if an IO error occurred while establishing the session
- * @throws InterruptedException if the thread was interrupted while waiting in a blocking
- * operation
- */
- public BytestreamSession establishSession(String targetJID) throws XMPPException, IOException,
- InterruptedException;
-
- /**
- * Establishes a bytestream with the given user and returns the session to send/receive data
- * to/from the user.
- * <p>
- * See {@link Socks5BytestreamManager#establishSession(String)} and
- * {@link InBandBytestreamManager#establishSession(String)} for further details.
- *
- * @param targetJID the JID of the user a bytestream should be established
- * @param sessionID the session ID for the bytestream request
- * @return the session to send/receive data to/from the user
- * @throws XMPPException if an error occurred while establishing the session
- * @throws IOException if an IO error occurred while establishing the session
- * @throws InterruptedException if the thread was interrupted while waiting in a blocking
- * operation
- */
- public BytestreamSession establishSession(String targetJID, String sessionID)
- throws XMPPException, IOException, InterruptedException;
-
-}
+/**
+ * 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.bytestreams;
+
+import java.io.IOException;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
+
+/**
+ * BytestreamManager provides a generic interface for bytestream managers.
+ * <p>
+ * There are two implementations of the interface. See {@link Socks5BytestreamManager} and
+ * {@link InBandBytestreamManager}.
+ *
+ * @author Henning Staib
+ */
+public interface BytestreamManager {
+
+ /**
+ * Adds {@link BytestreamListener} that is called for every incoming bytestream request unless
+ * there is a user specific {@link BytestreamListener} registered.
+ * <p>
+ * See {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
+ * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener)} for further
+ * details.
+ *
+ * @param listener the listener to register
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener);
+
+ /**
+ * Removes the given listener from the list of listeners for all incoming bytestream requests.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeIncomingBytestreamListener(BytestreamListener listener);
+
+ /**
+ * Adds {@link BytestreamListener} that is called for every incoming bytestream request unless
+ * there is a user specific {@link BytestreamListener} registered.
+ * <p>
+ * Use this method if you are awaiting an incoming bytestream request from a specific user.
+ * <p>
+ * See {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)}
+ * and {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)}
+ * for further details.
+ *
+ * @param listener the listener to register
+ * @param initiatorJID the JID of the user that wants to establish a bytestream
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID);
+
+ /**
+ * Removes the listener for the given user.
+ *
+ * @param initiatorJID the JID of the user the listener should be removed
+ */
+ public void removeIncomingBytestreamListener(String initiatorJID);
+
+ /**
+ * Establishes a bytestream with the given user and returns the session to send/receive data
+ * to/from the user.
+ * <p>
+ * Use this method to establish bytestreams to users accepting all incoming bytestream requests
+ * since this method doesn't provide a way to tell the user something about the data to be sent.
+ * <p>
+ * To establish a bytestream after negotiation the kind of data to be sent (e.g. file transfer)
+ * use {@link #establishSession(String, String)}.
+ * <p>
+ * See {@link Socks5BytestreamManager#establishSession(String)} and
+ * {@link InBandBytestreamManager#establishSession(String)} for further details.
+ *
+ * @param targetJID the JID of the user a bytestream should be established
+ * @return the session to send/receive data to/from the user
+ * @throws XMPPException if an error occurred while establishing the session
+ * @throws IOException if an IO error occurred while establishing the session
+ * @throws InterruptedException if the thread was interrupted while waiting in a blocking
+ * operation
+ */
+ public BytestreamSession establishSession(String targetJID) throws XMPPException, IOException,
+ InterruptedException;
+
+ /**
+ * Establishes a bytestream with the given user and returns the session to send/receive data
+ * to/from the user.
+ * <p>
+ * See {@link Socks5BytestreamManager#establishSession(String)} and
+ * {@link InBandBytestreamManager#establishSession(String)} for further details.
+ *
+ * @param targetJID the JID of the user a bytestream should be established
+ * @param sessionID the session ID for the bytestream request
+ * @return the session to send/receive data to/from the user
+ * @throws XMPPException if an error occurred while establishing the session
+ * @throws IOException if an IO error occurred while establishing the session
+ * @throws InterruptedException if the thread was interrupted while waiting in a blocking
+ * operation
+ */
+ public BytestreamSession establishSession(String targetJID, String sessionID)
+ throws XMPPException, IOException, InterruptedException;
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java
index e368bad99..e16474b0f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java
@@ -1,59 +1,59 @@
-/**
- * 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.bytestreams;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
-
-/**
- * BytestreamRequest provides an interface to handle incoming bytestream requests.
- * <p>
- * There are two implementations of the interface. See {@link Socks5BytestreamRequest} and
- * {@link InBandBytestreamRequest}.
- *
- * @author Henning Staib
- */
-public interface BytestreamRequest {
-
- /**
- * Returns the sender of the bytestream open request.
- *
- * @return the sender of the bytestream open request
- */
- public String getFrom();
-
- /**
- * Returns the session ID of the bytestream open request.
- *
- * @return the session ID of the bytestream open request
- */
- public String getSessionID();
-
- /**
- * Accepts the bytestream open request and returns the session to send/receive data.
- *
- * @return the session to send/receive data
- * @throws XMPPException if an error occurred while accepting the bytestream request
- * @throws InterruptedException if the thread was interrupted while waiting in a blocking
- * operation
- */
- public BytestreamSession accept() throws XMPPException, InterruptedException;
-
- /**
- * Rejects the bytestream request by sending a reject error to the initiator.
- */
- public void reject();
-
-}
+/**
+ * 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.bytestreams;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
+
+/**
+ * BytestreamRequest provides an interface to handle incoming bytestream requests.
+ * <p>
+ * There are two implementations of the interface. See {@link Socks5BytestreamRequest} and
+ * {@link InBandBytestreamRequest}.
+ *
+ * @author Henning Staib
+ */
+public interface BytestreamRequest {
+
+ /**
+ * Returns the sender of the bytestream open request.
+ *
+ * @return the sender of the bytestream open request
+ */
+ public String getFrom();
+
+ /**
+ * Returns the session ID of the bytestream open request.
+ *
+ * @return the session ID of the bytestream open request
+ */
+ public String getSessionID();
+
+ /**
+ * Accepts the bytestream open request and returns the session to send/receive data.
+ *
+ * @return the session to send/receive data
+ * @throws XMPPException if an error occurred while accepting the bytestream request
+ * @throws InterruptedException if the thread was interrupted while waiting in a blocking
+ * operation
+ */
+ public BytestreamSession accept() throws XMPPException, InterruptedException;
+
+ /**
+ * Rejects the bytestream request by sending a reject error to the initiator.
+ */
+ public void reject();
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamSession.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamSession.java
index 7aafc3513..3041d77c7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamSession.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/BytestreamSession.java
@@ -1,81 +1,81 @@
-/**
- * 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.bytestreams;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
-
-/**
- * BytestreamSession provides an interface for established bytestream sessions.
- * <p>
- * There are two implementations of the interface. See {@link Socks5BytestreamSession} and
- * {@link InBandBytestreamSession}.
- *
- * @author Henning Staib
- */
-public interface BytestreamSession {
-
- /**
- * Returns the InputStream associated with this session to send data.
- *
- * @return the InputStream associated with this session to send data
- * @throws IOException if an error occurs while retrieving the input stream
- */
- public InputStream getInputStream() throws IOException;
-
- /**
- * Returns the OutputStream associated with this session to receive data.
- *
- * @return the OutputStream associated with this session to receive data
- * @throws IOException if an error occurs while retrieving the output stream
- */
- public OutputStream getOutputStream() throws IOException;
-
- /**
- * Closes the bytestream session.
- * <p>
- * Closing the session will also close the input stream and the output stream associated to this
- * session.
- *
- * @throws IOException if an error occurs while closing the session
- */
- public void close() throws IOException;
-
- /**
- * Returns the timeout for read operations of the input stream associated with this session. 0
- * returns implies that the option is disabled (i.e., timeout of infinity). Default is 0.
- *
- * @return the timeout for read operations
- * @throws IOException if there is an error in the underlying protocol
- */
- public int getReadTimeout() throws IOException;
-
- /**
- * Sets the specified timeout, in milliseconds. With this option set to a non-zero timeout, a
- * read() call on the input stream associated with this session will block for only this amount
- * of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the
- * session is still valid. The option must be enabled prior to entering the blocking operation
- * to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite
- * timeout. Default is 0.
- *
- * @param timeout the specified timeout, in milliseconds
- * @throws IOException if there is an error in the underlying protocol
- */
- public void setReadTimeout(int timeout) throws IOException;
-
-}
+/**
+ * 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.bytestreams;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
+
+/**
+ * BytestreamSession provides an interface for established bytestream sessions.
+ * <p>
+ * There are two implementations of the interface. See {@link Socks5BytestreamSession} and
+ * {@link InBandBytestreamSession}.
+ *
+ * @author Henning Staib
+ */
+public interface BytestreamSession {
+
+ /**
+ * Returns the InputStream associated with this session to send data.
+ *
+ * @return the InputStream associated with this session to send data
+ * @throws IOException if an error occurs while retrieving the input stream
+ */
+ public InputStream getInputStream() throws IOException;
+
+ /**
+ * Returns the OutputStream associated with this session to receive data.
+ *
+ * @return the OutputStream associated with this session to receive data
+ * @throws IOException if an error occurs while retrieving the output stream
+ */
+ public OutputStream getOutputStream() throws IOException;
+
+ /**
+ * Closes the bytestream session.
+ * <p>
+ * Closing the session will also close the input stream and the output stream associated to this
+ * session.
+ *
+ * @throws IOException if an error occurs while closing the session
+ */
+ public void close() throws IOException;
+
+ /**
+ * Returns the timeout for read operations of the input stream associated with this session. 0
+ * returns implies that the option is disabled (i.e., timeout of infinity). Default is 0.
+ *
+ * @return the timeout for read operations
+ * @throws IOException if there is an error in the underlying protocol
+ */
+ public int getReadTimeout() throws IOException;
+
+ /**
+ * Sets the specified timeout, in milliseconds. With this option set to a non-zero timeout, a
+ * read() call on the input stream associated with this session will block for only this amount
+ * of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the
+ * session is still valid. The option must be enabled prior to entering the blocking operation
+ * to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite
+ * timeout. Default is 0.
+ *
+ * @param timeout the specified timeout, in milliseconds
+ * @throws IOException if there is an error in the underlying protocol
+ */
+ public void setReadTimeout(int timeout) throws IOException;
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java
index 7690e9537..83ca51c51 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java
@@ -1,75 +1,75 @@
-/**
- * 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.bytestreams.ibb;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.IQTypeFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
-
-/**
- * CloseListener handles all In-Band Bytestream close requests.
- * <p>
- * If a close request is received it looks if a stored In-Band Bytestream
- * session exists and closes it. If no session with the given session ID exists
- * an &lt;item-not-found/&gt; error is returned to the sender.
- *
- * @author Henning Staib
- */
-class CloseListener implements PacketListener {
-
- /* manager containing the listeners and the XMPP connection */
- private final InBandBytestreamManager manager;
-
- /* packet filter for all In-Band Bytestream close requests */
- private final PacketFilter closeFilter = new AndFilter(new PacketTypeFilter(
- Close.class), new IQTypeFilter(IQ.Type.SET));
-
- /**
- * Constructor.
- *
- * @param manager the In-Band Bytestream manager
- */
- protected CloseListener(InBandBytestreamManager manager) {
- this.manager = manager;
- }
-
- public void processPacket(Packet packet) {
- Close closeRequest = (Close) packet;
- InBandBytestreamSession ibbSession = this.manager.getSessions().get(
- closeRequest.getSessionID());
- if (ibbSession == null) {
- this.manager.replyItemNotFoundPacket(closeRequest);
- }
- else {
- ibbSession.closeByPeer(closeRequest);
- this.manager.getSessions().remove(closeRequest.getSessionID());
- }
-
- }
-
- /**
- * Returns the packet filter for In-Band Bytestream close requests.
- *
- * @return the packet filter for In-Band Bytestream close requests
- */
- protected PacketFilter getFilter() {
- return this.closeFilter;
- }
-
-}
+/**
+ * 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.bytestreams.ibb;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.IQTypeFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
+
+/**
+ * CloseListener handles all In-Band Bytestream close requests.
+ * <p>
+ * If a close request is received it looks if a stored In-Band Bytestream
+ * session exists and closes it. If no session with the given session ID exists
+ * an &lt;item-not-found/&gt; error is returned to the sender.
+ *
+ * @author Henning Staib
+ */
+class CloseListener implements PacketListener {
+
+ /* manager containing the listeners and the XMPP connection */
+ private final InBandBytestreamManager manager;
+
+ /* packet filter for all In-Band Bytestream close requests */
+ private final PacketFilter closeFilter = new AndFilter(new PacketTypeFilter(
+ Close.class), new IQTypeFilter(IQ.Type.SET));
+
+ /**
+ * Constructor.
+ *
+ * @param manager the In-Band Bytestream manager
+ */
+ protected CloseListener(InBandBytestreamManager manager) {
+ this.manager = manager;
+ }
+
+ public void processPacket(Packet packet) {
+ Close closeRequest = (Close) packet;
+ InBandBytestreamSession ibbSession = this.manager.getSessions().get(
+ closeRequest.getSessionID());
+ if (ibbSession == null) {
+ this.manager.replyItemNotFoundPacket(closeRequest);
+ }
+ else {
+ ibbSession.closeByPeer(closeRequest);
+ this.manager.getSessions().remove(closeRequest.getSessionID());
+ }
+
+ }
+
+ /**
+ * Returns the packet filter for In-Band Bytestream close requests.
+ *
+ * @return the packet filter for In-Band Bytestream close requests
+ */
+ protected PacketFilter getFilter() {
+ return this.closeFilter;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java
index 166c14647..6ef759c5d 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java
@@ -1,73 +1,73 @@
-/**
- * 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.bytestreams.ibb;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
-
-/**
- * DataListener handles all In-Band Bytestream IQ stanzas containing a data
- * packet extension that don't belong to an existing session.
- * <p>
- * If a data packet is received it looks if a stored In-Band Bytestream session
- * exists. If no session with the given session ID exists an
- * &lt;item-not-found/&gt; error is returned to the sender.
- * <p>
- * Data packets belonging to a running In-Band Bytestream session are processed
- * by more specific listeners registered when an {@link InBandBytestreamSession}
- * is created.
- *
- * @author Henning Staib
- */
-class DataListener implements PacketListener {
-
- /* manager containing the listeners and the XMPP connection */
- private final InBandBytestreamManager manager;
-
- /* packet filter for all In-Band Bytestream data packets */
- private final PacketFilter dataFilter = new AndFilter(
- new PacketTypeFilter(Data.class));
-
- /**
- * Constructor.
- *
- * @param manager the In-Band Bytestream manager
- */
- public DataListener(InBandBytestreamManager manager) {
- this.manager = manager;
- }
-
- public void processPacket(Packet packet) {
- Data data = (Data) packet;
- InBandBytestreamSession ibbSession = this.manager.getSessions().get(
- data.getDataPacketExtension().getSessionID());
- if (ibbSession == null) {
- this.manager.replyItemNotFoundPacket(data);
- }
- }
-
- /**
- * Returns the packet filter for In-Band Bytestream data packets.
- *
- * @return the packet filter for In-Band Bytestream data packets
- */
- protected PacketFilter getFilter() {
- return this.dataFilter;
- }
-
-}
+/**
+ * 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.bytestreams.ibb;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
+
+/**
+ * DataListener handles all In-Band Bytestream IQ stanzas containing a data
+ * packet extension that don't belong to an existing session.
+ * <p>
+ * If a data packet is received it looks if a stored In-Band Bytestream session
+ * exists. If no session with the given session ID exists an
+ * &lt;item-not-found/&gt; error is returned to the sender.
+ * <p>
+ * Data packets belonging to a running In-Band Bytestream session are processed
+ * by more specific listeners registered when an {@link InBandBytestreamSession}
+ * is created.
+ *
+ * @author Henning Staib
+ */
+class DataListener implements PacketListener {
+
+ /* manager containing the listeners and the XMPP connection */
+ private final InBandBytestreamManager manager;
+
+ /* packet filter for all In-Band Bytestream data packets */
+ private final PacketFilter dataFilter = new AndFilter(
+ new PacketTypeFilter(Data.class));
+
+ /**
+ * Constructor.
+ *
+ * @param manager the In-Band Bytestream manager
+ */
+ public DataListener(InBandBytestreamManager manager) {
+ this.manager = manager;
+ }
+
+ public void processPacket(Packet packet) {
+ Data data = (Data) packet;
+ InBandBytestreamSession ibbSession = this.manager.getSessions().get(
+ data.getDataPacketExtension().getSessionID());
+ if (ibbSession == null) {
+ this.manager.replyItemNotFoundPacket(data);
+ }
+ }
+
+ /**
+ * Returns the packet filter for In-Band Bytestream data packets.
+ *
+ * @return the packet filter for In-Band Bytestream data packets
+ */
+ protected PacketFilter getFilter() {
+ return this.dataFilter;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java
index 68791a6f3..6c84013c2 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java
@@ -1,46 +1,46 @@
-/**
- * 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.bytestreams.ibb;
-
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
-
-/**
- * InBandBytestreamListener are informed if a remote user wants to initiate an In-Band Bytestream.
- * Implement this interface to handle incoming In-Band Bytestream requests.
- * <p>
- * There are two ways to add this listener. See
- * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
- * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for
- * further details.
- *
- * @author Henning Staib
- */
-public abstract class InBandBytestreamListener implements BytestreamListener {
-
-
-
- public void incomingBytestreamRequest(BytestreamRequest request) {
- incomingBytestreamRequest((InBandBytestreamRequest) request);
- }
-
- /**
- * This listener is notified if an In-Band Bytestream request from another user has been
- * received.
- *
- * @param request the incoming In-Band Bytestream request
- */
- public abstract void incomingBytestreamRequest(InBandBytestreamRequest request);
-
-}
+/**
+ * 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.bytestreams.ibb;
+
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
+
+/**
+ * InBandBytestreamListener are informed if a remote user wants to initiate an In-Band Bytestream.
+ * Implement this interface to handle incoming In-Band Bytestream requests.
+ * <p>
+ * There are two ways to add this listener. See
+ * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
+ * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for
+ * further details.
+ *
+ * @author Henning Staib
+ */
+public abstract class InBandBytestreamListener implements BytestreamListener {
+
+
+
+ public void incomingBytestreamRequest(BytestreamRequest request) {
+ incomingBytestreamRequest((InBandBytestreamRequest) request);
+ }
+
+ /**
+ * This listener is notified if an In-Band Bytestream request from another user has been
+ * received.
+ *
+ * @param request the incoming In-Band Bytestream request
+ */
+ public abstract void incomingBytestreamRequest(InBandBytestreamRequest request);
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java
index ef5253154..a4f3592e1 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java
@@ -1,546 +1,546 @@
-/**
- * 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.bytestreams.ibb;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.jivesoftware.smack.AbstractConnectionListener;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.ConnectionCreationListener;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.util.SyncPacketSend;
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.BytestreamManager;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
-import org.jivesoftware.smackx.filetransfer.FileTransferManager;
-
-/**
- * The InBandBytestreamManager class handles establishing In-Band Bytestreams as specified in the <a
- * href="http://xmpp.org/extensions/xep-0047.html">XEP-0047</a>.
- * <p>
- * The In-Band Bytestreams (IBB) enables two entities to establish a virtual bytestream over which
- * they can exchange Base64-encoded chunks of data over XMPP itself. It is the fall-back mechanism
- * in case the Socks5 bytestream method of transferring data is not available.
- * <p>
- * There are two ways to send data over an In-Band Bytestream. It could either use IQ stanzas to
- * send data packets or message stanzas. If IQ stanzas are used every data packet is acknowledged by
- * the receiver. This is the recommended way to avoid possible rate-limiting penalties. Message
- * stanzas are not acknowledged because most XMPP server implementation don't support stanza
- * flow-control method like <a href="http://xmpp.org/extensions/xep-0079.html">Advanced Message
- * Processing</a>. To set the stanza that should be used invoke {@link #setStanza(StanzaType)}.
- * <p>
- * To establish an In-Band Bytestream invoke the {@link #establishSession(String)} method. This will
- * negotiate an in-band bytestream with the given target JID and return a session.
- * <p>
- * If a session ID for the In-Band Bytestream was already negotiated (e.g. while negotiating a file
- * transfer) invoke {@link #establishSession(String, String)}.
- * <p>
- * To handle incoming In-Band Bytestream requests add an {@link InBandBytestreamListener} to the
- * manager. There are two ways to add this listener. If you want to be informed about incoming
- * In-Band Bytestreams from a specific user add the listener by invoking
- * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should
- * respond to all In-Band Bytestream requests invoke
- * {@link #addIncomingBytestreamListener(BytestreamListener)}.
- * <p>
- * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
- * In-Band bytestream requests sent in the context of <a
- * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
- * {@link FileTransferManager})
- * <p>
- * If no {@link InBandBytestreamListener}s are registered, all incoming In-Band bytestream requests
- * will be rejected by returning a &lt;not-acceptable/&gt; error to the initiator.
- *
- * @author Henning Staib
- */
-public class InBandBytestreamManager implements BytestreamManager {
-
- /**
- * Stanzas that can be used to encapsulate In-Band Bytestream data packets.
- */
- public enum StanzaType {
-
- /**
- * IQ stanza.
- */
- IQ,
-
- /**
- * Message stanza.
- */
- MESSAGE
- }
-
- /*
- * create a new InBandBytestreamManager and register its shutdown listener on every established
- * connection
- */
- static {
- Connection.addConnectionCreationListener(new ConnectionCreationListener() {
- public void connectionCreated(Connection connection) {
- final InBandBytestreamManager manager;
- manager = InBandBytestreamManager.getByteStreamManager(connection);
-
- // register shutdown listener
- connection.addConnectionListener(new AbstractConnectionListener() {
-
- public void connectionClosed() {
- manager.disableService();
- }
-
- });
-
- }
- });
- }
-
- /**
- * The XMPP namespace of the In-Band Bytestream
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/ibb";
-
- /**
- * Maximum block size that is allowed for In-Band Bytestreams
- */
- public static final int MAXIMUM_BLOCK_SIZE = 65535;
-
- /* prefix used to generate session IDs */
- private static final String SESSION_ID_PREFIX = "jibb_";
-
- /* random generator to create session IDs */
- private final static Random randomGenerator = new Random();
-
- /* stores one InBandBytestreamManager for each XMPP connection */
- private final static Map<Connection, InBandBytestreamManager> managers = new HashMap<Connection, InBandBytestreamManager>();
-
- /* XMPP connection */
- private final Connection connection;
-
- /*
- * assigns a user to a listener that is informed if an In-Band Bytestream request for this user
- * is received
- */
- private final Map<String, BytestreamListener> userListeners = new ConcurrentHashMap<String, BytestreamListener>();
-
- /*
- * list of listeners that respond to all In-Band Bytestream requests if there are no user
- * specific listeners for that request
- */
- private final List<BytestreamListener> allRequestListeners = Collections.synchronizedList(new LinkedList<BytestreamListener>());
-
- /* listener that handles all incoming In-Band Bytestream requests */
- private final InitiationListener initiationListener;
-
- /* listener that handles all incoming In-Band Bytestream IQ data packets */
- private final DataListener dataListener;
-
- /* listener that handles all incoming In-Band Bytestream close requests */
- private final CloseListener closeListener;
-
- /* assigns a session ID to the In-Band Bytestream session */
- private final Map<String, InBandBytestreamSession> sessions = new ConcurrentHashMap<String, InBandBytestreamSession>();
-
- /* block size used for new In-Band Bytestreams */
- private int defaultBlockSize = 4096;
-
- /* maximum block size allowed for this connection */
- private int maximumBlockSize = MAXIMUM_BLOCK_SIZE;
-
- /* the stanza used to send data packets */
- private StanzaType stanza = StanzaType.IQ;
-
- /*
- * list containing session IDs of In-Band Bytestream open packets that should be ignored by the
- * InitiationListener
- */
- private List<String> ignoredBytestreamRequests = Collections.synchronizedList(new LinkedList<String>());
-
- /**
- * Returns the InBandBytestreamManager to handle In-Band Bytestreams for a given
- * {@link Connection}.
- *
- * @param connection the XMPP connection
- * @return the InBandBytestreamManager for the given XMPP connection
- */
- public static synchronized InBandBytestreamManager getByteStreamManager(Connection connection) {
- if (connection == null)
- return null;
- InBandBytestreamManager manager = managers.get(connection);
- if (manager == null) {
- manager = new InBandBytestreamManager(connection);
- managers.put(connection, manager);
- }
- return manager;
- }
-
- /**
- * Constructor.
- *
- * @param connection the XMPP connection
- */
- private InBandBytestreamManager(Connection connection) {
- this.connection = connection;
-
- // register bytestream open packet listener
- this.initiationListener = new InitiationListener(this);
- this.connection.addPacketListener(this.initiationListener,
- this.initiationListener.getFilter());
-
- // register bytestream data packet listener
- this.dataListener = new DataListener(this);
- this.connection.addPacketListener(this.dataListener, this.dataListener.getFilter());
-
- // register bytestream close packet listener
- this.closeListener = new CloseListener(this);
- this.connection.addPacketListener(this.closeListener, this.closeListener.getFilter());
-
- }
-
- /**
- * Adds InBandBytestreamListener that is called for every incoming in-band bytestream request
- * unless there is a user specific InBandBytestreamListener registered.
- * <p>
- * If no listeners are registered all In-Band Bytestream request are rejected with a
- * &lt;not-acceptable/&gt; error.
- * <p>
- * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
- * Socks5 bytestream requests sent in the context of <a
- * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
- * {@link FileTransferManager})
- *
- * @param listener the listener to register
- */
- public void addIncomingBytestreamListener(BytestreamListener listener) {
- this.allRequestListeners.add(listener);
- }
-
- /**
- * Removes the given listener from the list of listeners for all incoming In-Band Bytestream
- * requests.
- *
- * @param listener the listener to remove
- */
- public void removeIncomingBytestreamListener(BytestreamListener listener) {
- this.allRequestListeners.remove(listener);
- }
-
- /**
- * Adds InBandBytestreamListener that is called for every incoming in-band bytestream request
- * from the given user.
- * <p>
- * Use this method if you are awaiting an incoming Socks5 bytestream request from a specific
- * user.
- * <p>
- * If no listeners are registered all In-Band Bytestream request are rejected with a
- * &lt;not-acceptable/&gt; error.
- * <p>
- * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
- * Socks5 bytestream requests sent in the context of <a
- * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
- * {@link FileTransferManager})
- *
- * @param listener the listener to register
- * @param initiatorJID the JID of the user that wants to establish an In-Band Bytestream
- */
- public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) {
- this.userListeners.put(initiatorJID, listener);
- }
-
- /**
- * Removes the listener for the given user.
- *
- * @param initiatorJID the JID of the user the listener should be removed
- */
- public void removeIncomingBytestreamListener(String initiatorJID) {
- this.userListeners.remove(initiatorJID);
- }
-
- /**
- * Use this method to ignore the next incoming In-Band Bytestream request containing the given
- * session ID. No listeners will be notified for this request and and no error will be returned
- * to the initiator.
- * <p>
- * This method should be used if you are awaiting an In-Band Bytestream request as a reply to
- * another packet (e.g. file transfer).
- *
- * @param sessionID to be ignored
- */
- public void ignoreBytestreamRequestOnce(String sessionID) {
- this.ignoredBytestreamRequests.add(sessionID);
- }
-
- /**
- * Returns the default block size that is used for all outgoing in-band bytestreams for this
- * connection.
- * <p>
- * The recommended default block size is 4096 bytes. See <a
- * href="http://xmpp.org/extensions/xep-0047.html#usage">XEP-0047</a> Section 5.
- *
- * @return the default block size
- */
- public int getDefaultBlockSize() {
- return defaultBlockSize;
- }
-
- /**
- * Sets the default block size that is used for all outgoing in-band bytestreams for this
- * connection.
- * <p>
- * The default block size must be between 1 and 65535 bytes. The recommended default block size
- * is 4096 bytes. See <a href="http://xmpp.org/extensions/xep-0047.html#usage">XEP-0047</a>
- * Section 5.
- *
- * @param defaultBlockSize the default block size to set
- */
- public void setDefaultBlockSize(int defaultBlockSize) {
- if (defaultBlockSize <= 0 || defaultBlockSize > MAXIMUM_BLOCK_SIZE) {
- throw new IllegalArgumentException("Default block size must be between 1 and "
- + MAXIMUM_BLOCK_SIZE);
- }
- this.defaultBlockSize = defaultBlockSize;
- }
-
- /**
- * Returns the maximum block size that is allowed for In-Band Bytestreams for this connection.
- * <p>
- * Incoming In-Band Bytestream open request will be rejected with an
- * &lt;resource-constraint/&gt; error if the block size is greater then the maximum allowed
- * block size.
- * <p>
- * The default maximum block size is 65535 bytes.
- *
- * @return the maximum block size
- */
- public int getMaximumBlockSize() {
- return maximumBlockSize;
- }
-
- /**
- * Sets the maximum block size that is allowed for In-Band Bytestreams for this connection.
- * <p>
- * The maximum block size must be between 1 and 65535 bytes.
- * <p>
- * Incoming In-Band Bytestream open request will be rejected with an
- * &lt;resource-constraint/&gt; error if the block size is greater then the maximum allowed
- * block size.
- *
- * @param maximumBlockSize the maximum block size to set
- */
- public void setMaximumBlockSize(int maximumBlockSize) {
- if (maximumBlockSize <= 0 || maximumBlockSize > MAXIMUM_BLOCK_SIZE) {
- throw new IllegalArgumentException("Maximum block size must be between 1 and "
- + MAXIMUM_BLOCK_SIZE);
- }
- this.maximumBlockSize = maximumBlockSize;
- }
-
- /**
- * Returns the stanza used to send data packets.
- * <p>
- * Default is {@link StanzaType#IQ}. See <a
- * href="http://xmpp.org/extensions/xep-0047.html#message">XEP-0047</a> Section 4.
- *
- * @return the stanza used to send data packets
- */
- public StanzaType getStanza() {
- return stanza;
- }
-
- /**
- * Sets the stanza used to send data packets.
- * <p>
- * The use of {@link StanzaType#IQ} is recommended. See <a
- * href="http://xmpp.org/extensions/xep-0047.html#message">XEP-0047</a> Section 4.
- *
- * @param stanza the stanza to set
- */
- public void setStanza(StanzaType stanza) {
- this.stanza = stanza;
- }
-
- /**
- * Establishes an In-Band Bytestream with the given user and returns the session to send/receive
- * data to/from the user.
- * <p>
- * Use this method to establish In-Band Bytestreams to users accepting all incoming In-Band
- * Bytestream requests since this method doesn't provide a way to tell the user something about
- * the data to be sent.
- * <p>
- * To establish an In-Band Bytestream after negotiation the kind of data to be sent (e.g. file
- * transfer) use {@link #establishSession(String, String)}.
- *
- * @param targetJID the JID of the user an In-Band Bytestream should be established
- * @return the session to send/receive data to/from the user
- * @throws XMPPException if the user doesn't support or accept in-band bytestreams, or if the
- * user prefers smaller block sizes
- */
- public InBandBytestreamSession establishSession(String targetJID) throws XMPPException {
- String sessionID = getNextSessionID();
- return establishSession(targetJID, sessionID);
- }
-
- /**
- * Establishes an In-Band Bytestream with the given user using the given session ID and returns
- * the session to send/receive data to/from the user.
- *
- * @param targetJID the JID of the user an In-Band Bytestream should be established
- * @param sessionID the session ID for the In-Band Bytestream request
- * @return the session to send/receive data to/from the user
- * @throws XMPPException if the user doesn't support or accept in-band bytestreams, or if the
- * user prefers smaller block sizes
- */
- public InBandBytestreamSession establishSession(String targetJID, String sessionID)
- throws XMPPException {
- Open byteStreamRequest = new Open(sessionID, this.defaultBlockSize, this.stanza);
- byteStreamRequest.setTo(targetJID);
-
- // sending packet will throw exception on timeout or error reply
- SyncPacketSend.getReply(this.connection, byteStreamRequest);
-
- InBandBytestreamSession inBandBytestreamSession = new InBandBytestreamSession(
- this.connection, byteStreamRequest, targetJID);
- this.sessions.put(sessionID, inBandBytestreamSession);
-
- return inBandBytestreamSession;
- }
-
- /**
- * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream is
- * not accepted.
- *
- * @param request IQ packet that should be answered with a not-acceptable error
- */
- protected void replyRejectPacket(IQ request) {
- XMPPError xmppError = new XMPPError(XMPPError.Condition.no_acceptable);
- IQ error = IQ.createErrorResponse(request, xmppError);
- this.connection.sendPacket(error);
- }
-
- /**
- * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream open
- * request is rejected because its block size is greater than the maximum allowed block size.
- *
- * @param request IQ packet that should be answered with a resource-constraint error
- */
- protected void replyResourceConstraintPacket(IQ request) {
- XMPPError xmppError = new XMPPError(XMPPError.Condition.resource_constraint);
- IQ error = IQ.createErrorResponse(request, xmppError);
- this.connection.sendPacket(error);
- }
-
- /**
- * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream
- * session could not be found.
- *
- * @param request IQ packet that should be answered with a item-not-found error
- */
- protected void replyItemNotFoundPacket(IQ request) {
- XMPPError xmppError = new XMPPError(XMPPError.Condition.item_not_found);
- IQ error = IQ.createErrorResponse(request, xmppError);
- this.connection.sendPacket(error);
- }
-
- /**
- * Returns a new unique session ID.
- *
- * @return a new unique session ID
- */
- private String getNextSessionID() {
- StringBuilder buffer = new StringBuilder();
- buffer.append(SESSION_ID_PREFIX);
- buffer.append(Math.abs(randomGenerator.nextLong()));
- return buffer.toString();
- }
-
- /**
- * Returns the XMPP connection.
- *
- * @return the XMPP connection
- */
- protected Connection getConnection() {
- return this.connection;
- }
-
- /**
- * Returns the {@link InBandBytestreamListener} that should be informed if a In-Band Bytestream
- * request from the given initiator JID is received.
- *
- * @param initiator the initiator's JID
- * @return the listener
- */
- protected BytestreamListener getUserListener(String initiator) {
- return this.userListeners.get(initiator);
- }
-
- /**
- * Returns a list of {@link InBandBytestreamListener} that are informed if there are no
- * listeners for a specific initiator.
- *
- * @return list of listeners
- */
- protected List<BytestreamListener> getAllRequestListeners() {
- return this.allRequestListeners;
- }
-
- /**
- * Returns the sessions map.
- *
- * @return the sessions map
- */
- protected Map<String, InBandBytestreamSession> getSessions() {
- return sessions;
- }
-
- /**
- * Returns the list of session IDs that should be ignored by the InitialtionListener
- *
- * @return list of session IDs
- */
- protected List<String> getIgnoredBytestreamRequests() {
- return ignoredBytestreamRequests;
- }
-
- /**
- * Disables the InBandBytestreamManager by removing its packet listeners and resetting its
- * internal status.
- */
- private void disableService() {
-
- // remove manager from static managers map
- managers.remove(connection);
-
- // remove all listeners registered by this manager
- this.connection.removePacketListener(this.initiationListener);
- this.connection.removePacketListener(this.dataListener);
- this.connection.removePacketListener(this.closeListener);
-
- // shutdown threads
- this.initiationListener.shutdown();
-
- // reset internal status
- this.userListeners.clear();
- this.allRequestListeners.clear();
- this.sessions.clear();
- this.ignoredBytestreamRequests.clear();
-
- }
-
-}
+/**
+ * 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.bytestreams.ibb;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jivesoftware.smack.AbstractConnectionListener;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.ConnectionCreationListener;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.util.SyncPacketSend;
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.BytestreamManager;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+import org.jivesoftware.smackx.filetransfer.FileTransferManager;
+
+/**
+ * The InBandBytestreamManager class handles establishing In-Band Bytestreams as specified in the <a
+ * href="http://xmpp.org/extensions/xep-0047.html">XEP-0047</a>.
+ * <p>
+ * The In-Band Bytestreams (IBB) enables two entities to establish a virtual bytestream over which
+ * they can exchange Base64-encoded chunks of data over XMPP itself. It is the fall-back mechanism
+ * in case the Socks5 bytestream method of transferring data is not available.
+ * <p>
+ * There are two ways to send data over an In-Band Bytestream. It could either use IQ stanzas to
+ * send data packets or message stanzas. If IQ stanzas are used every data packet is acknowledged by
+ * the receiver. This is the recommended way to avoid possible rate-limiting penalties. Message
+ * stanzas are not acknowledged because most XMPP server implementation don't support stanza
+ * flow-control method like <a href="http://xmpp.org/extensions/xep-0079.html">Advanced Message
+ * Processing</a>. To set the stanza that should be used invoke {@link #setStanza(StanzaType)}.
+ * <p>
+ * To establish an In-Band Bytestream invoke the {@link #establishSession(String)} method. This will
+ * negotiate an in-band bytestream with the given target JID and return a session.
+ * <p>
+ * If a session ID for the In-Band Bytestream was already negotiated (e.g. while negotiating a file
+ * transfer) invoke {@link #establishSession(String, String)}.
+ * <p>
+ * To handle incoming In-Band Bytestream requests add an {@link InBandBytestreamListener} to the
+ * manager. There are two ways to add this listener. If you want to be informed about incoming
+ * In-Band Bytestreams from a specific user add the listener by invoking
+ * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should
+ * respond to all In-Band Bytestream requests invoke
+ * {@link #addIncomingBytestreamListener(BytestreamListener)}.
+ * <p>
+ * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
+ * In-Band bytestream requests sent in the context of <a
+ * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
+ * {@link FileTransferManager})
+ * <p>
+ * If no {@link InBandBytestreamListener}s are registered, all incoming In-Band bytestream requests
+ * will be rejected by returning a &lt;not-acceptable/&gt; error to the initiator.
+ *
+ * @author Henning Staib
+ */
+public class InBandBytestreamManager implements BytestreamManager {
+
+ /**
+ * Stanzas that can be used to encapsulate In-Band Bytestream data packets.
+ */
+ public enum StanzaType {
+
+ /**
+ * IQ stanza.
+ */
+ IQ,
+
+ /**
+ * Message stanza.
+ */
+ MESSAGE
+ }
+
+ /*
+ * create a new InBandBytestreamManager and register its shutdown listener on every established
+ * connection
+ */
+ static {
+ Connection.addConnectionCreationListener(new ConnectionCreationListener() {
+ public void connectionCreated(Connection connection) {
+ final InBandBytestreamManager manager;
+ manager = InBandBytestreamManager.getByteStreamManager(connection);
+
+ // register shutdown listener
+ connection.addConnectionListener(new AbstractConnectionListener() {
+
+ public void connectionClosed() {
+ manager.disableService();
+ }
+
+ });
+
+ }
+ });
+ }
+
+ /**
+ * The XMPP namespace of the In-Band Bytestream
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/ibb";
+
+ /**
+ * Maximum block size that is allowed for In-Band Bytestreams
+ */
+ public static final int MAXIMUM_BLOCK_SIZE = 65535;
+
+ /* prefix used to generate session IDs */
+ private static final String SESSION_ID_PREFIX = "jibb_";
+
+ /* random generator to create session IDs */
+ private final static Random randomGenerator = new Random();
+
+ /* stores one InBandBytestreamManager for each XMPP connection */
+ private final static Map<Connection, InBandBytestreamManager> managers = new HashMap<Connection, InBandBytestreamManager>();
+
+ /* XMPP connection */
+ private final Connection connection;
+
+ /*
+ * assigns a user to a listener that is informed if an In-Band Bytestream request for this user
+ * is received
+ */
+ private final Map<String, BytestreamListener> userListeners = new ConcurrentHashMap<String, BytestreamListener>();
+
+ /*
+ * list of listeners that respond to all In-Band Bytestream requests if there are no user
+ * specific listeners for that request
+ */
+ private final List<BytestreamListener> allRequestListeners = Collections.synchronizedList(new LinkedList<BytestreamListener>());
+
+ /* listener that handles all incoming In-Band Bytestream requests */
+ private final InitiationListener initiationListener;
+
+ /* listener that handles all incoming In-Band Bytestream IQ data packets */
+ private final DataListener dataListener;
+
+ /* listener that handles all incoming In-Band Bytestream close requests */
+ private final CloseListener closeListener;
+
+ /* assigns a session ID to the In-Band Bytestream session */
+ private final Map<String, InBandBytestreamSession> sessions = new ConcurrentHashMap<String, InBandBytestreamSession>();
+
+ /* block size used for new In-Band Bytestreams */
+ private int defaultBlockSize = 4096;
+
+ /* maximum block size allowed for this connection */
+ private int maximumBlockSize = MAXIMUM_BLOCK_SIZE;
+
+ /* the stanza used to send data packets */
+ private StanzaType stanza = StanzaType.IQ;
+
+ /*
+ * list containing session IDs of In-Band Bytestream open packets that should be ignored by the
+ * InitiationListener
+ */
+ private List<String> ignoredBytestreamRequests = Collections.synchronizedList(new LinkedList<String>());
+
+ /**
+ * Returns the InBandBytestreamManager to handle In-Band Bytestreams for a given
+ * {@link Connection}.
+ *
+ * @param connection the XMPP connection
+ * @return the InBandBytestreamManager for the given XMPP connection
+ */
+ public static synchronized InBandBytestreamManager getByteStreamManager(Connection connection) {
+ if (connection == null)
+ return null;
+ InBandBytestreamManager manager = managers.get(connection);
+ if (manager == null) {
+ manager = new InBandBytestreamManager(connection);
+ managers.put(connection, manager);
+ }
+ return manager;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param connection the XMPP connection
+ */
+ private InBandBytestreamManager(Connection connection) {
+ this.connection = connection;
+
+ // register bytestream open packet listener
+ this.initiationListener = new InitiationListener(this);
+ this.connection.addPacketListener(this.initiationListener,
+ this.initiationListener.getFilter());
+
+ // register bytestream data packet listener
+ this.dataListener = new DataListener(this);
+ this.connection.addPacketListener(this.dataListener, this.dataListener.getFilter());
+
+ // register bytestream close packet listener
+ this.closeListener = new CloseListener(this);
+ this.connection.addPacketListener(this.closeListener, this.closeListener.getFilter());
+
+ }
+
+ /**
+ * Adds InBandBytestreamListener that is called for every incoming in-band bytestream request
+ * unless there is a user specific InBandBytestreamListener registered.
+ * <p>
+ * If no listeners are registered all In-Band Bytestream request are rejected with a
+ * &lt;not-acceptable/&gt; error.
+ * <p>
+ * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
+ * Socks5 bytestream requests sent in the context of <a
+ * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * @param listener the listener to register
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener) {
+ this.allRequestListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from the list of listeners for all incoming In-Band Bytestream
+ * requests.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeIncomingBytestreamListener(BytestreamListener listener) {
+ this.allRequestListeners.remove(listener);
+ }
+
+ /**
+ * Adds InBandBytestreamListener that is called for every incoming in-band bytestream request
+ * from the given user.
+ * <p>
+ * Use this method if you are awaiting an incoming Socks5 bytestream request from a specific
+ * user.
+ * <p>
+ * If no listeners are registered all In-Band Bytestream request are rejected with a
+ * &lt;not-acceptable/&gt; error.
+ * <p>
+ * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
+ * Socks5 bytestream requests sent in the context of <a
+ * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * @param listener the listener to register
+ * @param initiatorJID the JID of the user that wants to establish an In-Band Bytestream
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) {
+ this.userListeners.put(initiatorJID, listener);
+ }
+
+ /**
+ * Removes the listener for the given user.
+ *
+ * @param initiatorJID the JID of the user the listener should be removed
+ */
+ public void removeIncomingBytestreamListener(String initiatorJID) {
+ this.userListeners.remove(initiatorJID);
+ }
+
+ /**
+ * Use this method to ignore the next incoming In-Band Bytestream request containing the given
+ * session ID. No listeners will be notified for this request and and no error will be returned
+ * to the initiator.
+ * <p>
+ * This method should be used if you are awaiting an In-Band Bytestream request as a reply to
+ * another packet (e.g. file transfer).
+ *
+ * @param sessionID to be ignored
+ */
+ public void ignoreBytestreamRequestOnce(String sessionID) {
+ this.ignoredBytestreamRequests.add(sessionID);
+ }
+
+ /**
+ * Returns the default block size that is used for all outgoing in-band bytestreams for this
+ * connection.
+ * <p>
+ * The recommended default block size is 4096 bytes. See <a
+ * href="http://xmpp.org/extensions/xep-0047.html#usage">XEP-0047</a> Section 5.
+ *
+ * @return the default block size
+ */
+ public int getDefaultBlockSize() {
+ return defaultBlockSize;
+ }
+
+ /**
+ * Sets the default block size that is used for all outgoing in-band bytestreams for this
+ * connection.
+ * <p>
+ * The default block size must be between 1 and 65535 bytes. The recommended default block size
+ * is 4096 bytes. See <a href="http://xmpp.org/extensions/xep-0047.html#usage">XEP-0047</a>
+ * Section 5.
+ *
+ * @param defaultBlockSize the default block size to set
+ */
+ public void setDefaultBlockSize(int defaultBlockSize) {
+ if (defaultBlockSize <= 0 || defaultBlockSize > MAXIMUM_BLOCK_SIZE) {
+ throw new IllegalArgumentException("Default block size must be between 1 and "
+ + MAXIMUM_BLOCK_SIZE);
+ }
+ this.defaultBlockSize = defaultBlockSize;
+ }
+
+ /**
+ * Returns the maximum block size that is allowed for In-Band Bytestreams for this connection.
+ * <p>
+ * Incoming In-Band Bytestream open request will be rejected with an
+ * &lt;resource-constraint/&gt; error if the block size is greater then the maximum allowed
+ * block size.
+ * <p>
+ * The default maximum block size is 65535 bytes.
+ *
+ * @return the maximum block size
+ */
+ public int getMaximumBlockSize() {
+ return maximumBlockSize;
+ }
+
+ /**
+ * Sets the maximum block size that is allowed for In-Band Bytestreams for this connection.
+ * <p>
+ * The maximum block size must be between 1 and 65535 bytes.
+ * <p>
+ * Incoming In-Band Bytestream open request will be rejected with an
+ * &lt;resource-constraint/&gt; error if the block size is greater then the maximum allowed
+ * block size.
+ *
+ * @param maximumBlockSize the maximum block size to set
+ */
+ public void setMaximumBlockSize(int maximumBlockSize) {
+ if (maximumBlockSize <= 0 || maximumBlockSize > MAXIMUM_BLOCK_SIZE) {
+ throw new IllegalArgumentException("Maximum block size must be between 1 and "
+ + MAXIMUM_BLOCK_SIZE);
+ }
+ this.maximumBlockSize = maximumBlockSize;
+ }
+
+ /**
+ * Returns the stanza used to send data packets.
+ * <p>
+ * Default is {@link StanzaType#IQ}. See <a
+ * href="http://xmpp.org/extensions/xep-0047.html#message">XEP-0047</a> Section 4.
+ *
+ * @return the stanza used to send data packets
+ */
+ public StanzaType getStanza() {
+ return stanza;
+ }
+
+ /**
+ * Sets the stanza used to send data packets.
+ * <p>
+ * The use of {@link StanzaType#IQ} is recommended. See <a
+ * href="http://xmpp.org/extensions/xep-0047.html#message">XEP-0047</a> Section 4.
+ *
+ * @param stanza the stanza to set
+ */
+ public void setStanza(StanzaType stanza) {
+ this.stanza = stanza;
+ }
+
+ /**
+ * Establishes an In-Band Bytestream with the given user and returns the session to send/receive
+ * data to/from the user.
+ * <p>
+ * Use this method to establish In-Band Bytestreams to users accepting all incoming In-Band
+ * Bytestream requests since this method doesn't provide a way to tell the user something about
+ * the data to be sent.
+ * <p>
+ * To establish an In-Band Bytestream after negotiation the kind of data to be sent (e.g. file
+ * transfer) use {@link #establishSession(String, String)}.
+ *
+ * @param targetJID the JID of the user an In-Band Bytestream should be established
+ * @return the session to send/receive data to/from the user
+ * @throws XMPPException if the user doesn't support or accept in-band bytestreams, or if the
+ * user prefers smaller block sizes
+ */
+ public InBandBytestreamSession establishSession(String targetJID) throws XMPPException {
+ String sessionID = getNextSessionID();
+ return establishSession(targetJID, sessionID);
+ }
+
+ /**
+ * Establishes an In-Band Bytestream with the given user using the given session ID and returns
+ * the session to send/receive data to/from the user.
+ *
+ * @param targetJID the JID of the user an In-Band Bytestream should be established
+ * @param sessionID the session ID for the In-Band Bytestream request
+ * @return the session to send/receive data to/from the user
+ * @throws XMPPException if the user doesn't support or accept in-band bytestreams, or if the
+ * user prefers smaller block sizes
+ */
+ public InBandBytestreamSession establishSession(String targetJID, String sessionID)
+ throws XMPPException {
+ Open byteStreamRequest = new Open(sessionID, this.defaultBlockSize, this.stanza);
+ byteStreamRequest.setTo(targetJID);
+
+ // sending packet will throw exception on timeout or error reply
+ SyncPacketSend.getReply(this.connection, byteStreamRequest);
+
+ InBandBytestreamSession inBandBytestreamSession = new InBandBytestreamSession(
+ this.connection, byteStreamRequest, targetJID);
+ this.sessions.put(sessionID, inBandBytestreamSession);
+
+ return inBandBytestreamSession;
+ }
+
+ /**
+ * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream is
+ * not accepted.
+ *
+ * @param request IQ packet that should be answered with a not-acceptable error
+ */
+ protected void replyRejectPacket(IQ request) {
+ XMPPError xmppError = new XMPPError(XMPPError.Condition.no_acceptable);
+ IQ error = IQ.createErrorResponse(request, xmppError);
+ this.connection.sendPacket(error);
+ }
+
+ /**
+ * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream open
+ * request is rejected because its block size is greater than the maximum allowed block size.
+ *
+ * @param request IQ packet that should be answered with a resource-constraint error
+ */
+ protected void replyResourceConstraintPacket(IQ request) {
+ XMPPError xmppError = new XMPPError(XMPPError.Condition.resource_constraint);
+ IQ error = IQ.createErrorResponse(request, xmppError);
+ this.connection.sendPacket(error);
+ }
+
+ /**
+ * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream
+ * session could not be found.
+ *
+ * @param request IQ packet that should be answered with a item-not-found error
+ */
+ protected void replyItemNotFoundPacket(IQ request) {
+ XMPPError xmppError = new XMPPError(XMPPError.Condition.item_not_found);
+ IQ error = IQ.createErrorResponse(request, xmppError);
+ this.connection.sendPacket(error);
+ }
+
+ /**
+ * Returns a new unique session ID.
+ *
+ * @return a new unique session ID
+ */
+ private String getNextSessionID() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(SESSION_ID_PREFIX);
+ buffer.append(Math.abs(randomGenerator.nextLong()));
+ return buffer.toString();
+ }
+
+ /**
+ * Returns the XMPP connection.
+ *
+ * @return the XMPP connection
+ */
+ protected Connection getConnection() {
+ return this.connection;
+ }
+
+ /**
+ * Returns the {@link InBandBytestreamListener} that should be informed if a In-Band Bytestream
+ * request from the given initiator JID is received.
+ *
+ * @param initiator the initiator's JID
+ * @return the listener
+ */
+ protected BytestreamListener getUserListener(String initiator) {
+ return this.userListeners.get(initiator);
+ }
+
+ /**
+ * Returns a list of {@link InBandBytestreamListener} that are informed if there are no
+ * listeners for a specific initiator.
+ *
+ * @return list of listeners
+ */
+ protected List<BytestreamListener> getAllRequestListeners() {
+ return this.allRequestListeners;
+ }
+
+ /**
+ * Returns the sessions map.
+ *
+ * @return the sessions map
+ */
+ protected Map<String, InBandBytestreamSession> getSessions() {
+ return sessions;
+ }
+
+ /**
+ * Returns the list of session IDs that should be ignored by the InitialtionListener
+ *
+ * @return list of session IDs
+ */
+ protected List<String> getIgnoredBytestreamRequests() {
+ return ignoredBytestreamRequests;
+ }
+
+ /**
+ * Disables the InBandBytestreamManager by removing its packet listeners and resetting its
+ * internal status.
+ */
+ private void disableService() {
+
+ // remove manager from static managers map
+ managers.remove(connection);
+
+ // remove all listeners registered by this manager
+ this.connection.removePacketListener(this.initiationListener);
+ this.connection.removePacketListener(this.dataListener);
+ this.connection.removePacketListener(this.closeListener);
+
+ // shutdown threads
+ this.initiationListener.shutdown();
+
+ // reset internal status
+ this.userListeners.clear();
+ this.allRequestListeners.clear();
+ this.sessions.clear();
+ this.ignoredBytestreamRequests.clear();
+
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamRequest.java
index 5bc689a4a..310b844b0 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamRequest.java
@@ -1,92 +1,92 @@
-/**
- * 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.bytestreams.ibb;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
-
-/**
- * InBandBytestreamRequest class handles incoming In-Band Bytestream requests.
- *
- * @author Henning Staib
- */
-public class InBandBytestreamRequest implements BytestreamRequest {
-
- /* the bytestream initialization request */
- private final Open byteStreamRequest;
-
- /*
- * In-Band Bytestream manager containing the XMPP connection and helper
- * methods
- */
- private final InBandBytestreamManager manager;
-
- protected InBandBytestreamRequest(InBandBytestreamManager manager,
- Open byteStreamRequest) {
- this.manager = manager;
- this.byteStreamRequest = byteStreamRequest;
- }
-
- /**
- * Returns the sender of the In-Band Bytestream open request.
- *
- * @return the sender of the In-Band Bytestream open request
- */
- public String getFrom() {
- return this.byteStreamRequest.getFrom();
- }
-
- /**
- * Returns the session ID of the In-Band Bytestream open request.
- *
- * @return the session ID of the In-Band Bytestream open request
- */
- public String getSessionID() {
- return this.byteStreamRequest.getSessionID();
- }
-
- /**
- * Accepts the In-Band Bytestream open request and returns the session to
- * send/receive data.
- *
- * @return the session to send/receive data
- * @throws XMPPException if stream is invalid.
- */
- public InBandBytestreamSession accept() throws XMPPException {
- Connection connection = this.manager.getConnection();
-
- // create In-Band Bytestream session and store it
- InBandBytestreamSession ibbSession = new InBandBytestreamSession(connection,
- this.byteStreamRequest, this.byteStreamRequest.getFrom());
- this.manager.getSessions().put(this.byteStreamRequest.getSessionID(), ibbSession);
-
- // acknowledge request
- IQ resultIQ = IQ.createResultIQ(this.byteStreamRequest);
- connection.sendPacket(resultIQ);
-
- return ibbSession;
- }
-
- /**
- * Rejects the In-Band Bytestream request by sending a reject error to the
- * initiator.
- */
- public void reject() {
- this.manager.replyRejectPacket(this.byteStreamRequest);
- }
-
-}
+/**
+ * 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.bytestreams.ibb;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+
+/**
+ * InBandBytestreamRequest class handles incoming In-Band Bytestream requests.
+ *
+ * @author Henning Staib
+ */
+public class InBandBytestreamRequest implements BytestreamRequest {
+
+ /* the bytestream initialization request */
+ private final Open byteStreamRequest;
+
+ /*
+ * In-Band Bytestream manager containing the XMPP connection and helper
+ * methods
+ */
+ private final InBandBytestreamManager manager;
+
+ protected InBandBytestreamRequest(InBandBytestreamManager manager,
+ Open byteStreamRequest) {
+ this.manager = manager;
+ this.byteStreamRequest = byteStreamRequest;
+ }
+
+ /**
+ * Returns the sender of the In-Band Bytestream open request.
+ *
+ * @return the sender of the In-Band Bytestream open request
+ */
+ public String getFrom() {
+ return this.byteStreamRequest.getFrom();
+ }
+
+ /**
+ * Returns the session ID of the In-Band Bytestream open request.
+ *
+ * @return the session ID of the In-Band Bytestream open request
+ */
+ public String getSessionID() {
+ return this.byteStreamRequest.getSessionID();
+ }
+
+ /**
+ * Accepts the In-Band Bytestream open request and returns the session to
+ * send/receive data.
+ *
+ * @return the session to send/receive data
+ * @throws XMPPException if stream is invalid.
+ */
+ public InBandBytestreamSession accept() throws XMPPException {
+ Connection connection = this.manager.getConnection();
+
+ // create In-Band Bytestream session and store it
+ InBandBytestreamSession ibbSession = new InBandBytestreamSession(connection,
+ this.byteStreamRequest, this.byteStreamRequest.getFrom());
+ this.manager.getSessions().put(this.byteStreamRequest.getSessionID(), ibbSession);
+
+ // acknowledge request
+ IQ resultIQ = IQ.createResultIQ(this.byteStreamRequest);
+ connection.sendPacket(resultIQ);
+
+ return ibbSession;
+ }
+
+ /**
+ * Rejects the In-Band Bytestream request by sending a reject error to the
+ * initiator.
+ */
+ public void reject() {
+ this.manager.replyRejectPacket(this.byteStreamRequest);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamSession.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamSession.java
index a33682c87..6323d872d 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamSession.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamSession.java
@@ -1,795 +1,795 @@
-/**
- * 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.bytestreams.ibb;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.SocketTimeoutException;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Message;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smack.util.SyncPacketSend;
-import org.jivesoftware.smackx.bytestreams.BytestreamSession;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
-
-/**
- * InBandBytestreamSession class represents an In-Band Bytestream session.
- * <p>
- * In-band bytestreams are bidirectional and this session encapsulates the streams for both
- * directions.
- * <p>
- * Note that closing the In-Band Bytestream session will close both streams. If both streams are
- * closed individually the session will be closed automatically once the second stream is closed.
- * Use the {@link #setCloseBothStreamsEnabled(boolean)} method if both streams should be closed
- * automatically if one of them is closed.
- *
- * @author Henning Staib
- */
-public class InBandBytestreamSession implements BytestreamSession {
-
- /* XMPP connection */
- private final Connection connection;
-
- /* the In-Band Bytestream open request for this session */
- private final Open byteStreamRequest;
-
- /*
- * the input stream for this session (either IQIBBInputStream or MessageIBBInputStream)
- */
- private IBBInputStream inputStream;
-
- /*
- * the output stream for this session (either IQIBBOutputStream or MessageIBBOutputStream)
- */
- private IBBOutputStream outputStream;
-
- /* JID of the remote peer */
- private String remoteJID;
-
- /* flag to close both streams if one of them is closed */
- private boolean closeBothStreamsEnabled = false;
-
- /* flag to indicate if session is closed */
- private boolean isClosed = false;
-
- /**
- * Constructor.
- *
- * @param connection the XMPP connection
- * @param byteStreamRequest the In-Band Bytestream open request for this session
- * @param remoteJID JID of the remote peer
- */
- protected InBandBytestreamSession(Connection connection, Open byteStreamRequest,
- String remoteJID) {
- this.connection = connection;
- this.byteStreamRequest = byteStreamRequest;
- this.remoteJID = remoteJID;
-
- // initialize streams dependent to the uses stanza type
- switch (byteStreamRequest.getStanza()) {
- case IQ:
- this.inputStream = new IQIBBInputStream();
- this.outputStream = new IQIBBOutputStream();
- break;
- case MESSAGE:
- this.inputStream = new MessageIBBInputStream();
- this.outputStream = new MessageIBBOutputStream();
- break;
- }
-
- }
-
- public InputStream getInputStream() {
- return this.inputStream;
- }
-
- public OutputStream getOutputStream() {
- return this.outputStream;
- }
-
- public int getReadTimeout() {
- return this.inputStream.readTimeout;
- }
-
- public void setReadTimeout(int timeout) {
- if (timeout < 0) {
- throw new IllegalArgumentException("Timeout must be >= 0");
- }
- this.inputStream.readTimeout = timeout;
- }
-
- /**
- * Returns whether both streams should be closed automatically if one of the streams is closed.
- * Default is <code>false</code>.
- *
- * @return <code>true</code> if both streams will be closed if one of the streams is closed,
- * <code>false</code> if both streams can be closed independently.
- */
- public boolean isCloseBothStreamsEnabled() {
- return closeBothStreamsEnabled;
- }
-
- /**
- * Sets whether both streams should be closed automatically if one of the streams is closed.
- * Default is <code>false</code>.
- *
- * @param closeBothStreamsEnabled <code>true</code> if both streams should be closed if one of
- * the streams is closed, <code>false</code> if both streams should be closed
- * independently
- */
- public void setCloseBothStreamsEnabled(boolean closeBothStreamsEnabled) {
- this.closeBothStreamsEnabled = closeBothStreamsEnabled;
- }
-
- public void close() throws IOException {
- closeByLocal(true); // close input stream
- closeByLocal(false); // close output stream
- }
-
- /**
- * This method is invoked if a request to close the In-Band Bytestream has been received.
- *
- * @param closeRequest the close request from the remote peer
- */
- protected void closeByPeer(Close closeRequest) {
-
- /*
- * close streams without flushing them, because stream is already considered closed on the
- * remote peers side
- */
- this.inputStream.closeInternal();
- this.inputStream.cleanup();
- this.outputStream.closeInternal(false);
-
- // acknowledge close request
- IQ confirmClose = IQ.createResultIQ(closeRequest);
- this.connection.sendPacket(confirmClose);
-
- }
-
- /**
- * This method is invoked if one of the streams has been closed locally, if an error occurred
- * locally or if the whole session should be closed.
- *
- * @throws IOException if an error occurs while sending the close request
- */
- protected synchronized void closeByLocal(boolean in) throws IOException {
- if (this.isClosed) {
- return;
- }
-
- if (this.closeBothStreamsEnabled) {
- this.inputStream.closeInternal();
- this.outputStream.closeInternal(true);
- }
- else {
- if (in) {
- this.inputStream.closeInternal();
- }
- else {
- // close stream but try to send any data left
- this.outputStream.closeInternal(true);
- }
- }
-
- if (this.inputStream.isClosed && this.outputStream.isClosed) {
- this.isClosed = true;
-
- // send close request
- Close close = new Close(this.byteStreamRequest.getSessionID());
- close.setTo(this.remoteJID);
- try {
- SyncPacketSend.getReply(this.connection, close);
- }
- catch (XMPPException e) {
- throw new IOException("Error while closing stream: " + e.getMessage());
- }
-
- this.inputStream.cleanup();
-
- // remove session from manager
- InBandBytestreamManager.getByteStreamManager(this.connection).getSessions().remove(this);
- }
-
- }
-
- /**
- * IBBInputStream class is the base implementation of an In-Band Bytestream input stream.
- * Subclasses of this input stream must provide a packet listener along with a packet filter to
- * collect the In-Band Bytestream data packets.
- */
- private abstract class IBBInputStream extends InputStream {
-
- /* the data packet listener to fill the data queue */
- private final PacketListener dataPacketListener;
-
- /* queue containing received In-Band Bytestream data packets */
- protected final BlockingQueue<DataPacketExtension> dataQueue = new LinkedBlockingQueue<DataPacketExtension>();
-
- /* buffer containing the data from one data packet */
- private byte[] buffer;
-
- /* pointer to the next byte to read from buffer */
- private int bufferPointer = -1;
-
- /* data packet sequence (range from 0 to 65535) */
- private long seq = -1;
-
- /* flag to indicate if input stream is closed */
- private boolean isClosed = false;
-
- /* flag to indicate if close method was invoked */
- private boolean closeInvoked = false;
-
- /* timeout for read operations */
- private int readTimeout = 0;
-
- /**
- * Constructor.
- */
- public IBBInputStream() {
- // add data packet listener to connection
- this.dataPacketListener = getDataPacketListener();
- connection.addPacketListener(this.dataPacketListener, getDataPacketFilter());
- }
-
- /**
- * Returns the packet listener that processes In-Band Bytestream data packets.
- *
- * @return the data packet listener
- */
- protected abstract PacketListener getDataPacketListener();
-
- /**
- * Returns the packet filter that accepts In-Band Bytestream data packets.
- *
- * @return the data packet filter
- */
- protected abstract PacketFilter getDataPacketFilter();
-
- public synchronized int read() throws IOException {
- checkClosed();
-
- // if nothing read yet or whole buffer has been read fill buffer
- if (bufferPointer == -1 || bufferPointer >= buffer.length) {
- // if no data available and stream was closed return -1
- if (!loadBuffer()) {
- return -1;
- }
- }
-
- // return byte and increment buffer pointer
- return ((int) buffer[bufferPointer++]) & 0xff;
- }
-
- public synchronized int read(byte[] b, int off, int len) throws IOException {
- if (b == null) {
- throw new NullPointerException();
- }
- else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
- || ((off + len) < 0)) {
- throw new IndexOutOfBoundsException();
- }
- else if (len == 0) {
- return 0;
- }
-
- checkClosed();
-
- // if nothing read yet or whole buffer has been read fill buffer
- if (bufferPointer == -1 || bufferPointer >= buffer.length) {
- // if no data available and stream was closed return -1
- if (!loadBuffer()) {
- return -1;
- }
- }
-
- // if more bytes wanted than available return all available
- int bytesAvailable = buffer.length - bufferPointer;
- if (len > bytesAvailable) {
- len = bytesAvailable;
- }
-
- System.arraycopy(buffer, bufferPointer, b, off, len);
- bufferPointer += len;
- return len;
- }
-
- public synchronized int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-
- /**
- * This method blocks until a data packet is received, the stream is closed or the current
- * thread is interrupted.
- *
- * @return <code>true</code> if data was received, otherwise <code>false</code>
- * @throws IOException if data packets are out of sequence
- */
- private synchronized boolean loadBuffer() throws IOException {
-
- // wait until data is available or stream is closed
- DataPacketExtension data = null;
- try {
- if (this.readTimeout == 0) {
- while (data == null) {
- if (isClosed && this.dataQueue.isEmpty()) {
- return false;
- }
- data = this.dataQueue.poll(1000, TimeUnit.MILLISECONDS);
- }
- }
- else {
- data = this.dataQueue.poll(this.readTimeout, TimeUnit.MILLISECONDS);
- if (data == null) {
- throw new SocketTimeoutException();
- }
- }
- }
- catch (InterruptedException e) {
- // Restore the interrupted status
- Thread.currentThread().interrupt();
- return false;
- }
-
- // handle sequence overflow
- if (this.seq == 65535) {
- this.seq = -1;
- }
-
- // check if data packets sequence is successor of last seen sequence
- long seq = data.getSeq();
- if (seq - 1 != this.seq) {
- // packets out of order; close stream/session
- InBandBytestreamSession.this.close();
- throw new IOException("Packets out of sequence");
- }
- else {
- this.seq = seq;
- }
-
- // set buffer to decoded data
- buffer = data.getDecodedData();
- bufferPointer = 0;
- return true;
- }
-
- /**
- * Checks if this stream is closed and throws an IOException if necessary
- *
- * @throws IOException if stream is closed and no data should be read anymore
- */
- private void checkClosed() throws IOException {
- /* throw no exception if there is data available, but not if close method was invoked */
- if ((isClosed && this.dataQueue.isEmpty()) || closeInvoked) {
- // clear data queue in case additional data was received after stream was closed
- this.dataQueue.clear();
- throw new IOException("Stream is closed");
- }
- }
-
- public boolean markSupported() {
- return false;
- }
-
- public void close() throws IOException {
- if (isClosed) {
- return;
- }
-
- this.closeInvoked = true;
-
- InBandBytestreamSession.this.closeByLocal(true);
- }
-
- /**
- * This method sets the close flag and removes the data packet listener.
- */
- private void closeInternal() {
- if (isClosed) {
- return;
- }
- isClosed = true;
- }
-
- /**
- * Invoked if the session is closed.
- */
- private void cleanup() {
- connection.removePacketListener(this.dataPacketListener);
- }
-
- }
-
- /**
- * IQIBBInputStream class implements IBBInputStream to be used with IQ stanzas encapsulating the
- * data packets.
- */
- private class IQIBBInputStream extends IBBInputStream {
-
- protected PacketListener getDataPacketListener() {
- return new PacketListener() {
-
- private long lastSequence = -1;
-
- public void processPacket(Packet packet) {
- // get data packet extension
- DataPacketExtension data = (DataPacketExtension) packet.getExtension(
- DataPacketExtension.ELEMENT_NAME,
- InBandBytestreamManager.NAMESPACE);
-
- /*
- * check if sequence was not used already (see XEP-0047 Section 2.2)
- */
- if (data.getSeq() <= this.lastSequence) {
- IQ unexpectedRequest = IQ.createErrorResponse((IQ) packet, new XMPPError(
- XMPPError.Condition.unexpected_request));
- connection.sendPacket(unexpectedRequest);
- return;
-
- }
-
- // check if encoded data is valid (see XEP-0047 Section 2.2)
- if (data.getDecodedData() == null) {
- // data is invalid; respond with bad-request error
- IQ badRequest = IQ.createErrorResponse((IQ) packet, new XMPPError(
- XMPPError.Condition.bad_request));
- connection.sendPacket(badRequest);
- return;
- }
-
- // data is valid; add to data queue
- dataQueue.offer(data);
-
- // confirm IQ
- IQ confirmData = IQ.createResultIQ((IQ) packet);
- connection.sendPacket(confirmData);
-
- // set last seen sequence
- this.lastSequence = data.getSeq();
- if (this.lastSequence == 65535) {
- this.lastSequence = -1;
- }
-
- }
-
- };
- }
-
- protected PacketFilter getDataPacketFilter() {
- /*
- * filter all IQ stanzas having type 'SET' (represented by Data class), containing a
- * data packet extension, matching session ID and recipient
- */
- return new AndFilter(new PacketTypeFilter(Data.class), new IBBDataPacketFilter());
- }
-
- }
-
- /**
- * MessageIBBInputStream class implements IBBInputStream to be used with message stanzas
- * encapsulating the data packets.
- */
- private class MessageIBBInputStream extends IBBInputStream {
-
- protected PacketListener getDataPacketListener() {
- return new PacketListener() {
-
- public void processPacket(Packet packet) {
- // get data packet extension
- DataPacketExtension data = (DataPacketExtension) packet.getExtension(
- DataPacketExtension.ELEMENT_NAME,
- InBandBytestreamManager.NAMESPACE);
-
- // check if encoded data is valid
- if (data.getDecodedData() == null) {
- /*
- * TODO once a majority of XMPP server implementation support XEP-0079
- * Advanced Message Processing the invalid message could be answered with an
- * appropriate error. For now we just ignore the packet. Subsequent packets
- * with an increased sequence will cause the input stream to close the
- * stream/session.
- */
- return;
- }
-
- // data is valid; add to data queue
- dataQueue.offer(data);
-
- // TODO confirm packet once XMPP servers support XEP-0079
- }
-
- };
- }
-
- @Override
- protected PacketFilter getDataPacketFilter() {
- /*
- * filter all message stanzas containing a data packet extension, matching session ID
- * and recipient
- */
- return new AndFilter(new PacketTypeFilter(Message.class), new IBBDataPacketFilter());
- }
-
- }
-
- /**
- * IBBDataPacketFilter class filters all packets from the remote peer of this session,
- * containing an In-Band Bytestream data packet extension whose session ID matches this sessions
- * ID.
- */
- private class IBBDataPacketFilter implements PacketFilter {
-
- public boolean accept(Packet packet) {
- // sender equals remote peer
- if (!packet.getFrom().equalsIgnoreCase(remoteJID)) {
- return false;
- }
-
- // stanza contains data packet extension
- PacketExtension packetExtension = packet.getExtension(DataPacketExtension.ELEMENT_NAME,
- InBandBytestreamManager.NAMESPACE);
- if (packetExtension == null || !(packetExtension instanceof DataPacketExtension)) {
- return false;
- }
-
- // session ID equals this session ID
- DataPacketExtension data = (DataPacketExtension) packetExtension;
- if (!data.getSessionID().equals(byteStreamRequest.getSessionID())) {
- return false;
- }
-
- return true;
- }
-
- }
-
- /**
- * IBBOutputStream class is the base implementation of an In-Band Bytestream output stream.
- * Subclasses of this output stream must provide a method to send data over XMPP stream.
- */
- private abstract class IBBOutputStream extends OutputStream {
-
- /* buffer with the size of this sessions block size */
- protected final byte[] buffer;
-
- /* pointer to next byte to write to buffer */
- protected int bufferPointer = 0;
-
- /* data packet sequence (range from 0 to 65535) */
- protected long seq = 0;
-
- /* flag to indicate if output stream is closed */
- protected boolean isClosed = false;
-
- /**
- * Constructor.
- */
- public IBBOutputStream() {
- this.buffer = new byte[(byteStreamRequest.getBlockSize()/4)*3];
- }
-
- /**
- * Writes the given data packet to the XMPP stream.
- *
- * @param data the data packet
- * @throws IOException if an I/O error occurred while sending or if the stream is closed
- */
- protected abstract void writeToXML(DataPacketExtension data) throws IOException;
-
- public synchronized void write(int b) throws IOException {
- if (this.isClosed) {
- throw new IOException("Stream is closed");
- }
-
- // if buffer is full flush buffer
- if (bufferPointer >= buffer.length) {
- flushBuffer();
- }
-
- buffer[bufferPointer++] = (byte) b;
- }
-
- public synchronized void write(byte b[], int off, int len) throws IOException {
- if (b == null) {
- throw new NullPointerException();
- }
- else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
- || ((off + len) < 0)) {
- throw new IndexOutOfBoundsException();
- }
- else if (len == 0) {
- return;
- }
-
- if (this.isClosed) {
- throw new IOException("Stream is closed");
- }
-
- // is data to send greater than buffer size
- if (len >= buffer.length) {
-
- // "byte" off the first chunk to write out
- writeOut(b, off, buffer.length);
-
- // recursively call this method with the lesser amount
- write(b, off + buffer.length, len - buffer.length);
- }
- else {
- writeOut(b, off, len);
- }
- }
-
- public synchronized void write(byte[] b) throws IOException {
- write(b, 0, b.length);
- }
-
- /**
- * Fills the buffer with the given data and sends it over the XMPP stream if the buffers
- * capacity has been reached. This method is only called from this class so it is assured
- * that the amount of data to send is <= buffer capacity
- *
- * @param b the data
- * @param off the data
- * @param len the number of bytes to write
- * @throws IOException if an I/O error occurred while sending or if the stream is closed
- */
- private synchronized void writeOut(byte b[], int off, int len) throws IOException {
- if (this.isClosed) {
- throw new IOException("Stream is closed");
- }
-
- // set to 0 in case the next 'if' block is not executed
- int available = 0;
-
- // is data to send greater that buffer space left
- if (len > buffer.length - bufferPointer) {
- // fill buffer to capacity and send it
- available = buffer.length - bufferPointer;
- System.arraycopy(b, off, buffer, bufferPointer, available);
- bufferPointer += available;
- flushBuffer();
- }
-
- // copy the data left to buffer
- System.arraycopy(b, off + available, buffer, bufferPointer, len - available);
- bufferPointer += len - available;
- }
-
- public synchronized void flush() throws IOException {
- if (this.isClosed) {
- throw new IOException("Stream is closed");
- }
- flushBuffer();
- }
-
- private synchronized void flushBuffer() throws IOException {
-
- // do nothing if no data to send available
- if (bufferPointer == 0) {
- return;
- }
-
- // create data packet
- String enc = StringUtils.encodeBase64(buffer, 0, bufferPointer, false);
- DataPacketExtension data = new DataPacketExtension(byteStreamRequest.getSessionID(),
- this.seq, enc);
-
- // write to XMPP stream
- writeToXML(data);
-
- // reset buffer pointer
- bufferPointer = 0;
-
- // increment sequence, considering sequence overflow
- this.seq = (this.seq + 1 == 65535 ? 0 : this.seq + 1);
-
- }
-
- public void close() throws IOException {
- if (isClosed) {
- return;
- }
- InBandBytestreamSession.this.closeByLocal(false);
- }
-
- /**
- * Sets the close flag and optionally flushes the stream.
- *
- * @param flush if <code>true</code> flushes the stream
- */
- protected void closeInternal(boolean flush) {
- if (this.isClosed) {
- return;
- }
- this.isClosed = true;
-
- try {
- if (flush) {
- flushBuffer();
- }
- }
- catch (IOException e) {
- /*
- * ignore, because writeToXML() will not throw an exception if stream is already
- * closed
- */
- }
- }
-
- }
-
- /**
- * IQIBBOutputStream class implements IBBOutputStream to be used with IQ stanzas encapsulating
- * the data packets.
- */
- private class IQIBBOutputStream extends IBBOutputStream {
-
- @Override
- protected synchronized void writeToXML(DataPacketExtension data) throws IOException {
- // create IQ stanza containing data packet
- IQ iq = new Data(data);
- iq.setTo(remoteJID);
-
- try {
- SyncPacketSend.getReply(connection, iq);
- }
- catch (XMPPException e) {
- // close session unless it is already closed
- if (!this.isClosed) {
- InBandBytestreamSession.this.close();
- throw new IOException("Error while sending Data: " + e.getMessage());
- }
- }
-
- }
-
- }
-
- /**
- * MessageIBBOutputStream class implements IBBOutputStream to be used with message stanzas
- * encapsulating the data packets.
- */
- private class MessageIBBOutputStream extends IBBOutputStream {
-
- @Override
- protected synchronized void writeToXML(DataPacketExtension data) {
- // create message stanza containing data packet
- Message message = new Message(remoteJID);
- message.addExtension(data);
-
- connection.sendPacket(message);
-
- }
-
- }
-
-}
+/**
+ * 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.bytestreams.ibb;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smack.util.SyncPacketSend;
+import org.jivesoftware.smackx.bytestreams.BytestreamSession;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+
+/**
+ * InBandBytestreamSession class represents an In-Band Bytestream session.
+ * <p>
+ * In-band bytestreams are bidirectional and this session encapsulates the streams for both
+ * directions.
+ * <p>
+ * Note that closing the In-Band Bytestream session will close both streams. If both streams are
+ * closed individually the session will be closed automatically once the second stream is closed.
+ * Use the {@link #setCloseBothStreamsEnabled(boolean)} method if both streams should be closed
+ * automatically if one of them is closed.
+ *
+ * @author Henning Staib
+ */
+public class InBandBytestreamSession implements BytestreamSession {
+
+ /* XMPP connection */
+ private final Connection connection;
+
+ /* the In-Band Bytestream open request for this session */
+ private final Open byteStreamRequest;
+
+ /*
+ * the input stream for this session (either IQIBBInputStream or MessageIBBInputStream)
+ */
+ private IBBInputStream inputStream;
+
+ /*
+ * the output stream for this session (either IQIBBOutputStream or MessageIBBOutputStream)
+ */
+ private IBBOutputStream outputStream;
+
+ /* JID of the remote peer */
+ private String remoteJID;
+
+ /* flag to close both streams if one of them is closed */
+ private boolean closeBothStreamsEnabled = false;
+
+ /* flag to indicate if session is closed */
+ private boolean isClosed = false;
+
+ /**
+ * Constructor.
+ *
+ * @param connection the XMPP connection
+ * @param byteStreamRequest the In-Band Bytestream open request for this session
+ * @param remoteJID JID of the remote peer
+ */
+ protected InBandBytestreamSession(Connection connection, Open byteStreamRequest,
+ String remoteJID) {
+ this.connection = connection;
+ this.byteStreamRequest = byteStreamRequest;
+ this.remoteJID = remoteJID;
+
+ // initialize streams dependent to the uses stanza type
+ switch (byteStreamRequest.getStanza()) {
+ case IQ:
+ this.inputStream = new IQIBBInputStream();
+ this.outputStream = new IQIBBOutputStream();
+ break;
+ case MESSAGE:
+ this.inputStream = new MessageIBBInputStream();
+ this.outputStream = new MessageIBBOutputStream();
+ break;
+ }
+
+ }
+
+ public InputStream getInputStream() {
+ return this.inputStream;
+ }
+
+ public OutputStream getOutputStream() {
+ return this.outputStream;
+ }
+
+ public int getReadTimeout() {
+ return this.inputStream.readTimeout;
+ }
+
+ public void setReadTimeout(int timeout) {
+ if (timeout < 0) {
+ throw new IllegalArgumentException("Timeout must be >= 0");
+ }
+ this.inputStream.readTimeout = timeout;
+ }
+
+ /**
+ * Returns whether both streams should be closed automatically if one of the streams is closed.
+ * Default is <code>false</code>.
+ *
+ * @return <code>true</code> if both streams will be closed if one of the streams is closed,
+ * <code>false</code> if both streams can be closed independently.
+ */
+ public boolean isCloseBothStreamsEnabled() {
+ return closeBothStreamsEnabled;
+ }
+
+ /**
+ * Sets whether both streams should be closed automatically if one of the streams is closed.
+ * Default is <code>false</code>.
+ *
+ * @param closeBothStreamsEnabled <code>true</code> if both streams should be closed if one of
+ * the streams is closed, <code>false</code> if both streams should be closed
+ * independently
+ */
+ public void setCloseBothStreamsEnabled(boolean closeBothStreamsEnabled) {
+ this.closeBothStreamsEnabled = closeBothStreamsEnabled;
+ }
+
+ public void close() throws IOException {
+ closeByLocal(true); // close input stream
+ closeByLocal(false); // close output stream
+ }
+
+ /**
+ * This method is invoked if a request to close the In-Band Bytestream has been received.
+ *
+ * @param closeRequest the close request from the remote peer
+ */
+ protected void closeByPeer(Close closeRequest) {
+
+ /*
+ * close streams without flushing them, because stream is already considered closed on the
+ * remote peers side
+ */
+ this.inputStream.closeInternal();
+ this.inputStream.cleanup();
+ this.outputStream.closeInternal(false);
+
+ // acknowledge close request
+ IQ confirmClose = IQ.createResultIQ(closeRequest);
+ this.connection.sendPacket(confirmClose);
+
+ }
+
+ /**
+ * This method is invoked if one of the streams has been closed locally, if an error occurred
+ * locally or if the whole session should be closed.
+ *
+ * @throws IOException if an error occurs while sending the close request
+ */
+ protected synchronized void closeByLocal(boolean in) throws IOException {
+ if (this.isClosed) {
+ return;
+ }
+
+ if (this.closeBothStreamsEnabled) {
+ this.inputStream.closeInternal();
+ this.outputStream.closeInternal(true);
+ }
+ else {
+ if (in) {
+ this.inputStream.closeInternal();
+ }
+ else {
+ // close stream but try to send any data left
+ this.outputStream.closeInternal(true);
+ }
+ }
+
+ if (this.inputStream.isClosed && this.outputStream.isClosed) {
+ this.isClosed = true;
+
+ // send close request
+ Close close = new Close(this.byteStreamRequest.getSessionID());
+ close.setTo(this.remoteJID);
+ try {
+ SyncPacketSend.getReply(this.connection, close);
+ }
+ catch (XMPPException e) {
+ throw new IOException("Error while closing stream: " + e.getMessage());
+ }
+
+ this.inputStream.cleanup();
+
+ // remove session from manager
+ InBandBytestreamManager.getByteStreamManager(this.connection).getSessions().remove(this);
+ }
+
+ }
+
+ /**
+ * IBBInputStream class is the base implementation of an In-Band Bytestream input stream.
+ * Subclasses of this input stream must provide a packet listener along with a packet filter to
+ * collect the In-Band Bytestream data packets.
+ */
+ private abstract class IBBInputStream extends InputStream {
+
+ /* the data packet listener to fill the data queue */
+ private final PacketListener dataPacketListener;
+
+ /* queue containing received In-Band Bytestream data packets */
+ protected final BlockingQueue<DataPacketExtension> dataQueue = new LinkedBlockingQueue<DataPacketExtension>();
+
+ /* buffer containing the data from one data packet */
+ private byte[] buffer;
+
+ /* pointer to the next byte to read from buffer */
+ private int bufferPointer = -1;
+
+ /* data packet sequence (range from 0 to 65535) */
+ private long seq = -1;
+
+ /* flag to indicate if input stream is closed */
+ private boolean isClosed = false;
+
+ /* flag to indicate if close method was invoked */
+ private boolean closeInvoked = false;
+
+ /* timeout for read operations */
+ private int readTimeout = 0;
+
+ /**
+ * Constructor.
+ */
+ public IBBInputStream() {
+ // add data packet listener to connection
+ this.dataPacketListener = getDataPacketListener();
+ connection.addPacketListener(this.dataPacketListener, getDataPacketFilter());
+ }
+
+ /**
+ * Returns the packet listener that processes In-Band Bytestream data packets.
+ *
+ * @return the data packet listener
+ */
+ protected abstract PacketListener getDataPacketListener();
+
+ /**
+ * Returns the packet filter that accepts In-Band Bytestream data packets.
+ *
+ * @return the data packet filter
+ */
+ protected abstract PacketFilter getDataPacketFilter();
+
+ public synchronized int read() throws IOException {
+ checkClosed();
+
+ // if nothing read yet or whole buffer has been read fill buffer
+ if (bufferPointer == -1 || bufferPointer >= buffer.length) {
+ // if no data available and stream was closed return -1
+ if (!loadBuffer()) {
+ return -1;
+ }
+ }
+
+ // return byte and increment buffer pointer
+ return ((int) buffer[bufferPointer++]) & 0xff;
+ }
+
+ public synchronized int read(byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ }
+ else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
+ || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ }
+ else if (len == 0) {
+ return 0;
+ }
+
+ checkClosed();
+
+ // if nothing read yet or whole buffer has been read fill buffer
+ if (bufferPointer == -1 || bufferPointer >= buffer.length) {
+ // if no data available and stream was closed return -1
+ if (!loadBuffer()) {
+ return -1;
+ }
+ }
+
+ // if more bytes wanted than available return all available
+ int bytesAvailable = buffer.length - bufferPointer;
+ if (len > bytesAvailable) {
+ len = bytesAvailable;
+ }
+
+ System.arraycopy(buffer, bufferPointer, b, off, len);
+ bufferPointer += len;
+ return len;
+ }
+
+ public synchronized int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * This method blocks until a data packet is received, the stream is closed or the current
+ * thread is interrupted.
+ *
+ * @return <code>true</code> if data was received, otherwise <code>false</code>
+ * @throws IOException if data packets are out of sequence
+ */
+ private synchronized boolean loadBuffer() throws IOException {
+
+ // wait until data is available or stream is closed
+ DataPacketExtension data = null;
+ try {
+ if (this.readTimeout == 0) {
+ while (data == null) {
+ if (isClosed && this.dataQueue.isEmpty()) {
+ return false;
+ }
+ data = this.dataQueue.poll(1000, TimeUnit.MILLISECONDS);
+ }
+ }
+ else {
+ data = this.dataQueue.poll(this.readTimeout, TimeUnit.MILLISECONDS);
+ if (data == null) {
+ throw new SocketTimeoutException();
+ }
+ }
+ }
+ catch (InterruptedException e) {
+ // Restore the interrupted status
+ Thread.currentThread().interrupt();
+ return false;
+ }
+
+ // handle sequence overflow
+ if (this.seq == 65535) {
+ this.seq = -1;
+ }
+
+ // check if data packets sequence is successor of last seen sequence
+ long seq = data.getSeq();
+ if (seq - 1 != this.seq) {
+ // packets out of order; close stream/session
+ InBandBytestreamSession.this.close();
+ throw new IOException("Packets out of sequence");
+ }
+ else {
+ this.seq = seq;
+ }
+
+ // set buffer to decoded data
+ buffer = data.getDecodedData();
+ bufferPointer = 0;
+ return true;
+ }
+
+ /**
+ * Checks if this stream is closed and throws an IOException if necessary
+ *
+ * @throws IOException if stream is closed and no data should be read anymore
+ */
+ private void checkClosed() throws IOException {
+ /* throw no exception if there is data available, but not if close method was invoked */
+ if ((isClosed && this.dataQueue.isEmpty()) || closeInvoked) {
+ // clear data queue in case additional data was received after stream was closed
+ this.dataQueue.clear();
+ throw new IOException("Stream is closed");
+ }
+ }
+
+ public boolean markSupported() {
+ return false;
+ }
+
+ public void close() throws IOException {
+ if (isClosed) {
+ return;
+ }
+
+ this.closeInvoked = true;
+
+ InBandBytestreamSession.this.closeByLocal(true);
+ }
+
+ /**
+ * This method sets the close flag and removes the data packet listener.
+ */
+ private void closeInternal() {
+ if (isClosed) {
+ return;
+ }
+ isClosed = true;
+ }
+
+ /**
+ * Invoked if the session is closed.
+ */
+ private void cleanup() {
+ connection.removePacketListener(this.dataPacketListener);
+ }
+
+ }
+
+ /**
+ * IQIBBInputStream class implements IBBInputStream to be used with IQ stanzas encapsulating the
+ * data packets.
+ */
+ private class IQIBBInputStream extends IBBInputStream {
+
+ protected PacketListener getDataPacketListener() {
+ return new PacketListener() {
+
+ private long lastSequence = -1;
+
+ public void processPacket(Packet packet) {
+ // get data packet extension
+ DataPacketExtension data = (DataPacketExtension) packet.getExtension(
+ DataPacketExtension.ELEMENT_NAME,
+ InBandBytestreamManager.NAMESPACE);
+
+ /*
+ * check if sequence was not used already (see XEP-0047 Section 2.2)
+ */
+ if (data.getSeq() <= this.lastSequence) {
+ IQ unexpectedRequest = IQ.createErrorResponse((IQ) packet, new XMPPError(
+ XMPPError.Condition.unexpected_request));
+ connection.sendPacket(unexpectedRequest);
+ return;
+
+ }
+
+ // check if encoded data is valid (see XEP-0047 Section 2.2)
+ if (data.getDecodedData() == null) {
+ // data is invalid; respond with bad-request error
+ IQ badRequest = IQ.createErrorResponse((IQ) packet, new XMPPError(
+ XMPPError.Condition.bad_request));
+ connection.sendPacket(badRequest);
+ return;
+ }
+
+ // data is valid; add to data queue
+ dataQueue.offer(data);
+
+ // confirm IQ
+ IQ confirmData = IQ.createResultIQ((IQ) packet);
+ connection.sendPacket(confirmData);
+
+ // set last seen sequence
+ this.lastSequence = data.getSeq();
+ if (this.lastSequence == 65535) {
+ this.lastSequence = -1;
+ }
+
+ }
+
+ };
+ }
+
+ protected PacketFilter getDataPacketFilter() {
+ /*
+ * filter all IQ stanzas having type 'SET' (represented by Data class), containing a
+ * data packet extension, matching session ID and recipient
+ */
+ return new AndFilter(new PacketTypeFilter(Data.class), new IBBDataPacketFilter());
+ }
+
+ }
+
+ /**
+ * MessageIBBInputStream class implements IBBInputStream to be used with message stanzas
+ * encapsulating the data packets.
+ */
+ private class MessageIBBInputStream extends IBBInputStream {
+
+ protected PacketListener getDataPacketListener() {
+ return new PacketListener() {
+
+ public void processPacket(Packet packet) {
+ // get data packet extension
+ DataPacketExtension data = (DataPacketExtension) packet.getExtension(
+ DataPacketExtension.ELEMENT_NAME,
+ InBandBytestreamManager.NAMESPACE);
+
+ // check if encoded data is valid
+ if (data.getDecodedData() == null) {
+ /*
+ * TODO once a majority of XMPP server implementation support XEP-0079
+ * Advanced Message Processing the invalid message could be answered with an
+ * appropriate error. For now we just ignore the packet. Subsequent packets
+ * with an increased sequence will cause the input stream to close the
+ * stream/session.
+ */
+ return;
+ }
+
+ // data is valid; add to data queue
+ dataQueue.offer(data);
+
+ // TODO confirm packet once XMPP servers support XEP-0079
+ }
+
+ };
+ }
+
+ @Override
+ protected PacketFilter getDataPacketFilter() {
+ /*
+ * filter all message stanzas containing a data packet extension, matching session ID
+ * and recipient
+ */
+ return new AndFilter(new PacketTypeFilter(Message.class), new IBBDataPacketFilter());
+ }
+
+ }
+
+ /**
+ * IBBDataPacketFilter class filters all packets from the remote peer of this session,
+ * containing an In-Band Bytestream data packet extension whose session ID matches this sessions
+ * ID.
+ */
+ private class IBBDataPacketFilter implements PacketFilter {
+
+ public boolean accept(Packet packet) {
+ // sender equals remote peer
+ if (!packet.getFrom().equalsIgnoreCase(remoteJID)) {
+ return false;
+ }
+
+ // stanza contains data packet extension
+ PacketExtension packetExtension = packet.getExtension(DataPacketExtension.ELEMENT_NAME,
+ InBandBytestreamManager.NAMESPACE);
+ if (packetExtension == null || !(packetExtension instanceof DataPacketExtension)) {
+ return false;
+ }
+
+ // session ID equals this session ID
+ DataPacketExtension data = (DataPacketExtension) packetExtension;
+ if (!data.getSessionID().equals(byteStreamRequest.getSessionID())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ }
+
+ /**
+ * IBBOutputStream class is the base implementation of an In-Band Bytestream output stream.
+ * Subclasses of this output stream must provide a method to send data over XMPP stream.
+ */
+ private abstract class IBBOutputStream extends OutputStream {
+
+ /* buffer with the size of this sessions block size */
+ protected final byte[] buffer;
+
+ /* pointer to next byte to write to buffer */
+ protected int bufferPointer = 0;
+
+ /* data packet sequence (range from 0 to 65535) */
+ protected long seq = 0;
+
+ /* flag to indicate if output stream is closed */
+ protected boolean isClosed = false;
+
+ /**
+ * Constructor.
+ */
+ public IBBOutputStream() {
+ this.buffer = new byte[(byteStreamRequest.getBlockSize()/4)*3];
+ }
+
+ /**
+ * Writes the given data packet to the XMPP stream.
+ *
+ * @param data the data packet
+ * @throws IOException if an I/O error occurred while sending or if the stream is closed
+ */
+ protected abstract void writeToXML(DataPacketExtension data) throws IOException;
+
+ public synchronized void write(int b) throws IOException {
+ if (this.isClosed) {
+ throw new IOException("Stream is closed");
+ }
+
+ // if buffer is full flush buffer
+ if (bufferPointer >= buffer.length) {
+ flushBuffer();
+ }
+
+ buffer[bufferPointer++] = (byte) b;
+ }
+
+ public synchronized void write(byte b[], int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ }
+ else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
+ || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ }
+ else if (len == 0) {
+ return;
+ }
+
+ if (this.isClosed) {
+ throw new IOException("Stream is closed");
+ }
+
+ // is data to send greater than buffer size
+ if (len >= buffer.length) {
+
+ // "byte" off the first chunk to write out
+ writeOut(b, off, buffer.length);
+
+ // recursively call this method with the lesser amount
+ write(b, off + buffer.length, len - buffer.length);
+ }
+ else {
+ writeOut(b, off, len);
+ }
+ }
+
+ public synchronized void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Fills the buffer with the given data and sends it over the XMPP stream if the buffers
+ * capacity has been reached. This method is only called from this class so it is assured
+ * that the amount of data to send is <= buffer capacity
+ *
+ * @param b the data
+ * @param off the data
+ * @param len the number of bytes to write
+ * @throws IOException if an I/O error occurred while sending or if the stream is closed
+ */
+ private synchronized void writeOut(byte b[], int off, int len) throws IOException {
+ if (this.isClosed) {
+ throw new IOException("Stream is closed");
+ }
+
+ // set to 0 in case the next 'if' block is not executed
+ int available = 0;
+
+ // is data to send greater that buffer space left
+ if (len > buffer.length - bufferPointer) {
+ // fill buffer to capacity and send it
+ available = buffer.length - bufferPointer;
+ System.arraycopy(b, off, buffer, bufferPointer, available);
+ bufferPointer += available;
+ flushBuffer();
+ }
+
+ // copy the data left to buffer
+ System.arraycopy(b, off + available, buffer, bufferPointer, len - available);
+ bufferPointer += len - available;
+ }
+
+ public synchronized void flush() throws IOException {
+ if (this.isClosed) {
+ throw new IOException("Stream is closed");
+ }
+ flushBuffer();
+ }
+
+ private synchronized void flushBuffer() throws IOException {
+
+ // do nothing if no data to send available
+ if (bufferPointer == 0) {
+ return;
+ }
+
+ // create data packet
+ String enc = StringUtils.encodeBase64(buffer, 0, bufferPointer, false);
+ DataPacketExtension data = new DataPacketExtension(byteStreamRequest.getSessionID(),
+ this.seq, enc);
+
+ // write to XMPP stream
+ writeToXML(data);
+
+ // reset buffer pointer
+ bufferPointer = 0;
+
+ // increment sequence, considering sequence overflow
+ this.seq = (this.seq + 1 == 65535 ? 0 : this.seq + 1);
+
+ }
+
+ public void close() throws IOException {
+ if (isClosed) {
+ return;
+ }
+ InBandBytestreamSession.this.closeByLocal(false);
+ }
+
+ /**
+ * Sets the close flag and optionally flushes the stream.
+ *
+ * @param flush if <code>true</code> flushes the stream
+ */
+ protected void closeInternal(boolean flush) {
+ if (this.isClosed) {
+ return;
+ }
+ this.isClosed = true;
+
+ try {
+ if (flush) {
+ flushBuffer();
+ }
+ }
+ catch (IOException e) {
+ /*
+ * ignore, because writeToXML() will not throw an exception if stream is already
+ * closed
+ */
+ }
+ }
+
+ }
+
+ /**
+ * IQIBBOutputStream class implements IBBOutputStream to be used with IQ stanzas encapsulating
+ * the data packets.
+ */
+ private class IQIBBOutputStream extends IBBOutputStream {
+
+ @Override
+ protected synchronized void writeToXML(DataPacketExtension data) throws IOException {
+ // create IQ stanza containing data packet
+ IQ iq = new Data(data);
+ iq.setTo(remoteJID);
+
+ try {
+ SyncPacketSend.getReply(connection, iq);
+ }
+ catch (XMPPException e) {
+ // close session unless it is already closed
+ if (!this.isClosed) {
+ InBandBytestreamSession.this.close();
+ throw new IOException("Error while sending Data: " + e.getMessage());
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * MessageIBBOutputStream class implements IBBOutputStream to be used with message stanzas
+ * encapsulating the data packets.
+ */
+ private class MessageIBBOutputStream extends IBBOutputStream {
+
+ @Override
+ protected synchronized void writeToXML(DataPacketExtension data) {
+ // create message stanza containing data packet
+ Message message = new Message(remoteJID);
+ message.addExtension(data);
+
+ connection.sendPacket(message);
+
+ }
+
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java
index 0ecb08156..be8503254 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java
@@ -1,127 +1,127 @@
-/**
- * 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.bytestreams.ibb;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.IQTypeFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
-
-/**
- * InitiationListener handles all incoming In-Band Bytestream open requests. If there are no
- * listeners for a In-Band Bytestream request InitiationListener will always refuse the request and
- * reply with a &lt;not-acceptable/&gt; error (<a
- * href="http://xmpp.org/extensions/xep-0047.html#example-5" >XEP-0047</a> Section 2.1).
- * <p>
- * All In-Band Bytestream request having a block size greater than the maximum allowed block size
- * for this connection are rejected with an &lt;resource-constraint/&gt; error. The maximum block
- * size can be set by invoking {@link InBandBytestreamManager#setMaximumBlockSize(int)}.
- *
- * @author Henning Staib
- */
-class InitiationListener implements PacketListener {
-
- /* manager containing the listeners and the XMPP connection */
- private final InBandBytestreamManager manager;
-
- /* packet filter for all In-Band Bytestream requests */
- private final PacketFilter initFilter = new AndFilter(new PacketTypeFilter(Open.class),
- new IQTypeFilter(IQ.Type.SET));
-
- /* executor service to process incoming requests concurrently */
- private final ExecutorService initiationListenerExecutor;
-
- /**
- * Constructor.
- *
- * @param manager the In-Band Bytestream manager
- */
- protected InitiationListener(InBandBytestreamManager manager) {
- this.manager = manager;
- initiationListenerExecutor = Executors.newCachedThreadPool();
- }
-
- public void processPacket(final Packet packet) {
- initiationListenerExecutor.execute(new Runnable() {
-
- public void run() {
- processRequest(packet);
- }
- });
- }
-
- private void processRequest(Packet packet) {
- Open ibbRequest = (Open) packet;
-
- // validate that block size is within allowed range
- if (ibbRequest.getBlockSize() > this.manager.getMaximumBlockSize()) {
- this.manager.replyResourceConstraintPacket(ibbRequest);
- return;
- }
-
- // ignore request if in ignore list
- if (this.manager.getIgnoredBytestreamRequests().remove(ibbRequest.getSessionID()))
- return;
-
- // build bytestream request from packet
- InBandBytestreamRequest request = new InBandBytestreamRequest(this.manager, ibbRequest);
-
- // notify listeners for bytestream initiation from a specific user
- BytestreamListener userListener = this.manager.getUserListener(ibbRequest.getFrom());
- if (userListener != null) {
- userListener.incomingBytestreamRequest(request);
-
- }
- else if (!this.manager.getAllRequestListeners().isEmpty()) {
- /*
- * if there is no user specific listener inform listeners for all initiation requests
- */
- for (BytestreamListener listener : this.manager.getAllRequestListeners()) {
- listener.incomingBytestreamRequest(request);
- }
-
- }
- else {
- /*
- * if there is no listener for this initiation request, reply with reject message
- */
- this.manager.replyRejectPacket(ibbRequest);
- }
- }
-
- /**
- * Returns the packet filter for In-Band Bytestream open requests.
- *
- * @return the packet filter for In-Band Bytestream open requests
- */
- protected PacketFilter getFilter() {
- return this.initFilter;
- }
-
- /**
- * Shuts down the listeners executor service.
- */
- protected void shutdown() {
- this.initiationListenerExecutor.shutdownNow();
- }
-
-}
+/**
+ * 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.bytestreams.ibb;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.IQTypeFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+
+/**
+ * InitiationListener handles all incoming In-Band Bytestream open requests. If there are no
+ * listeners for a In-Band Bytestream request InitiationListener will always refuse the request and
+ * reply with a &lt;not-acceptable/&gt; error (<a
+ * href="http://xmpp.org/extensions/xep-0047.html#example-5" >XEP-0047</a> Section 2.1).
+ * <p>
+ * All In-Band Bytestream request having a block size greater than the maximum allowed block size
+ * for this connection are rejected with an &lt;resource-constraint/&gt; error. The maximum block
+ * size can be set by invoking {@link InBandBytestreamManager#setMaximumBlockSize(int)}.
+ *
+ * @author Henning Staib
+ */
+class InitiationListener implements PacketListener {
+
+ /* manager containing the listeners and the XMPP connection */
+ private final InBandBytestreamManager manager;
+
+ /* packet filter for all In-Band Bytestream requests */
+ private final PacketFilter initFilter = new AndFilter(new PacketTypeFilter(Open.class),
+ new IQTypeFilter(IQ.Type.SET));
+
+ /* executor service to process incoming requests concurrently */
+ private final ExecutorService initiationListenerExecutor;
+
+ /**
+ * Constructor.
+ *
+ * @param manager the In-Band Bytestream manager
+ */
+ protected InitiationListener(InBandBytestreamManager manager) {
+ this.manager = manager;
+ initiationListenerExecutor = Executors.newCachedThreadPool();
+ }
+
+ public void processPacket(final Packet packet) {
+ initiationListenerExecutor.execute(new Runnable() {
+
+ public void run() {
+ processRequest(packet);
+ }
+ });
+ }
+
+ private void processRequest(Packet packet) {
+ Open ibbRequest = (Open) packet;
+
+ // validate that block size is within allowed range
+ if (ibbRequest.getBlockSize() > this.manager.getMaximumBlockSize()) {
+ this.manager.replyResourceConstraintPacket(ibbRequest);
+ return;
+ }
+
+ // ignore request if in ignore list
+ if (this.manager.getIgnoredBytestreamRequests().remove(ibbRequest.getSessionID()))
+ return;
+
+ // build bytestream request from packet
+ InBandBytestreamRequest request = new InBandBytestreamRequest(this.manager, ibbRequest);
+
+ // notify listeners for bytestream initiation from a specific user
+ BytestreamListener userListener = this.manager.getUserListener(ibbRequest.getFrom());
+ if (userListener != null) {
+ userListener.incomingBytestreamRequest(request);
+
+ }
+ else if (!this.manager.getAllRequestListeners().isEmpty()) {
+ /*
+ * if there is no user specific listener inform listeners for all initiation requests
+ */
+ for (BytestreamListener listener : this.manager.getAllRequestListeners()) {
+ listener.incomingBytestreamRequest(request);
+ }
+
+ }
+ else {
+ /*
+ * if there is no listener for this initiation request, reply with reject message
+ */
+ this.manager.replyRejectPacket(ibbRequest);
+ }
+ }
+
+ /**
+ * Returns the packet filter for In-Band Bytestream open requests.
+ *
+ * @return the packet filter for In-Band Bytestream open requests
+ */
+ protected PacketFilter getFilter() {
+ return this.initFilter;
+ }
+
+ /**
+ * Shuts down the listeners executor service.
+ */
+ protected void shutdown() {
+ this.initiationListenerExecutor.shutdownNow();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java
index 9a78d736d..4ef73dc90 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java
@@ -1,65 +1,65 @@
-/**
- * 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.bytestreams.ibb.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-
-/**
- * Represents a request to close an In-Band Bytestream.
- *
- * @author Henning Staib
- */
-public class Close extends IQ {
-
- /* unique session ID identifying this In-Band Bytestream */
- private final String sessionID;
-
- /**
- * Creates a new In-Band Bytestream close request packet.
- *
- * @param sessionID unique session ID identifying this In-Band Bytestream
- */
- public Close(String sessionID) {
- if (sessionID == null || "".equals(sessionID)) {
- throw new IllegalArgumentException("Session ID must not be null or empty");
- }
- this.sessionID = sessionID;
- setType(Type.SET);
- }
-
- /**
- * Returns the unique session ID identifying this In-Band Bytestream.
- *
- * @return the unique session ID identifying this In-Band Bytestream
- */
- public String getSessionID() {
- return sessionID;
- }
-
- @Override
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<close ");
- buf.append("xmlns=\"");
- buf.append(InBandBytestreamManager.NAMESPACE);
- buf.append("\" ");
- buf.append("sid=\"");
- buf.append(sessionID);
- buf.append("\"");
- buf.append("/>");
- return buf.toString();
- }
-
-}
+/**
+ * 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.bytestreams.ibb.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+
+/**
+ * Represents a request to close an In-Band Bytestream.
+ *
+ * @author Henning Staib
+ */
+public class Close extends IQ {
+
+ /* unique session ID identifying this In-Band Bytestream */
+ private final String sessionID;
+
+ /**
+ * Creates a new In-Band Bytestream close request packet.
+ *
+ * @param sessionID unique session ID identifying this In-Band Bytestream
+ */
+ public Close(String sessionID) {
+ if (sessionID == null || "".equals(sessionID)) {
+ throw new IllegalArgumentException("Session ID must not be null or empty");
+ }
+ this.sessionID = sessionID;
+ setType(Type.SET);
+ }
+
+ /**
+ * Returns the unique session ID identifying this In-Band Bytestream.
+ *
+ * @return the unique session ID identifying this In-Band Bytestream
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ @Override
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<close ");
+ buf.append("xmlns=\"");
+ buf.append(InBandBytestreamManager.NAMESPACE);
+ buf.append("\" ");
+ buf.append("sid=\"");
+ buf.append(sessionID);
+ buf.append("\"");
+ buf.append("/>");
+ return buf.toString();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Data.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Data.java
index 696fa75d3..d38d7e253 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Data.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Data.java
@@ -1,64 +1,64 @@
-/**
- * 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.bytestreams.ibb.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-
-/**
- * Represents a chunk of data sent over an In-Band Bytestream encapsulated in an
- * IQ stanza.
- *
- * @author Henning Staib
- */
-public class Data extends IQ {
-
- /* the data packet extension */
- private final DataPacketExtension dataPacketExtension;
-
- /**
- * Constructor.
- *
- * @param data data packet extension containing the encoded data
- */
- public Data(DataPacketExtension data) {
- if (data == null) {
- throw new IllegalArgumentException("Data must not be null");
- }
- this.dataPacketExtension = data;
-
- /*
- * also set as packet extension so that data packet extension can be
- * retrieved from IQ stanza and message stanza in the same way
- */
- addExtension(data);
- setType(IQ.Type.SET);
- }
-
- /**
- * Returns the data packet extension.
- * <p>
- * Convenience method for <code>packet.getExtension("data",
- * "http://jabber.org/protocol/ibb")</code>.
- *
- * @return the data packet extension
- */
- public DataPacketExtension getDataPacketExtension() {
- return this.dataPacketExtension;
- }
-
- public String getChildElementXML() {
- return this.dataPacketExtension.toXML();
- }
-
-}
+/**
+ * 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.bytestreams.ibb.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+
+/**
+ * Represents a chunk of data sent over an In-Band Bytestream encapsulated in an
+ * IQ stanza.
+ *
+ * @author Henning Staib
+ */
+public class Data extends IQ {
+
+ /* the data packet extension */
+ private final DataPacketExtension dataPacketExtension;
+
+ /**
+ * Constructor.
+ *
+ * @param data data packet extension containing the encoded data
+ */
+ public Data(DataPacketExtension data) {
+ if (data == null) {
+ throw new IllegalArgumentException("Data must not be null");
+ }
+ this.dataPacketExtension = data;
+
+ /*
+ * also set as packet extension so that data packet extension can be
+ * retrieved from IQ stanza and message stanza in the same way
+ */
+ addExtension(data);
+ setType(IQ.Type.SET);
+ }
+
+ /**
+ * Returns the data packet extension.
+ * <p>
+ * Convenience method for <code>packet.getExtension("data",
+ * "http://jabber.org/protocol/ibb")</code>.
+ *
+ * @return the data packet extension
+ */
+ public DataPacketExtension getDataPacketExtension() {
+ return this.dataPacketExtension;
+ }
+
+ public String getChildElementXML() {
+ return this.dataPacketExtension.toXML();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java
index 80ed1e1fc..dce010fe3 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java
@@ -1,149 +1,149 @@
-/**
- * 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.bytestreams.ibb.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-
-/**
- * Represents a chunk of data of an In-Band Bytestream within an IQ stanza or a
- * message stanza
- *
- * @author Henning Staib
- */
-public class DataPacketExtension implements PacketExtension {
-
- /**
- * The element name of the data packet extension.
- */
- public final static String ELEMENT_NAME = "data";
-
- /* unique session ID identifying this In-Band Bytestream */
- private final String sessionID;
-
- /* sequence of this packet in regard to the other data packets */
- private final long seq;
-
- /* the data contained in this packet */
- private final String data;
-
- private byte[] decodedData;
-
- /**
- * Creates a new In-Band Bytestream data packet.
- *
- * @param sessionID unique session ID identifying this In-Band Bytestream
- * @param seq sequence of this packet in regard to the other data packets
- * @param data the base64 encoded data contained in this packet
- */
- public DataPacketExtension(String sessionID, long seq, String data) {
- if (sessionID == null || "".equals(sessionID)) {
- throw new IllegalArgumentException("Session ID must not be null or empty");
- }
- if (seq < 0 || seq > 65535) {
- throw new IllegalArgumentException("Sequence must not be between 0 and 65535");
- }
- if (data == null) {
- throw new IllegalArgumentException("Data must not be null");
- }
- this.sessionID = sessionID;
- this.seq = seq;
- this.data = data;
- }
-
- /**
- * Returns the unique session ID identifying this In-Band Bytestream.
- *
- * @return the unique session ID identifying this In-Band Bytestream
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Returns the sequence of this packet in regard to the other data packets.
- *
- * @return the sequence of this packet in regard to the other data packets.
- */
- public long getSeq() {
- return seq;
- }
-
- /**
- * Returns the data contained in this packet.
- *
- * @return the data contained in this packet.
- */
- public String getData() {
- return data;
- }
-
- /**
- * Returns the decoded data or null if data could not be decoded.
- * <p>
- * The encoded data is invalid if it contains bad Base64 input characters or
- * if it contains the pad ('=') character on a position other than the last
- * character(s) of the data. See <a
- * href="http://xmpp.org/extensions/xep-0047.html#sec">XEP-0047</a> Section
- * 6.
- *
- * @return the decoded data
- */
- public byte[] getDecodedData() {
- // return cached decoded data
- if (this.decodedData != null) {
- return this.decodedData;
- }
-
- // data must not contain the pad (=) other than end of data
- if (data.matches(".*={1,2}+.+")) {
- return null;
- }
-
- // decodeBase64 will return null if bad characters are included
- this.decodedData = StringUtils.decodeBase64(data);
- return this.decodedData;
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return InBandBytestreamManager.NAMESPACE;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<");
- buf.append(getElementName());
- buf.append(" ");
- buf.append("xmlns=\"");
- buf.append(InBandBytestreamManager.NAMESPACE);
- buf.append("\" ");
- buf.append("seq=\"");
- buf.append(seq);
- buf.append("\" ");
- buf.append("sid=\"");
- buf.append(sessionID);
- buf.append("\">");
- buf.append(data);
- buf.append("</");
- buf.append(getElementName());
- buf.append(">");
- return buf.toString();
- }
-
-}
+/**
+ * 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.bytestreams.ibb.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+
+/**
+ * Represents a chunk of data of an In-Band Bytestream within an IQ stanza or a
+ * message stanza
+ *
+ * @author Henning Staib
+ */
+public class DataPacketExtension implements PacketExtension {
+
+ /**
+ * The element name of the data packet extension.
+ */
+ public final static String ELEMENT_NAME = "data";
+
+ /* unique session ID identifying this In-Band Bytestream */
+ private final String sessionID;
+
+ /* sequence of this packet in regard to the other data packets */
+ private final long seq;
+
+ /* the data contained in this packet */
+ private final String data;
+
+ private byte[] decodedData;
+
+ /**
+ * Creates a new In-Band Bytestream data packet.
+ *
+ * @param sessionID unique session ID identifying this In-Band Bytestream
+ * @param seq sequence of this packet in regard to the other data packets
+ * @param data the base64 encoded data contained in this packet
+ */
+ public DataPacketExtension(String sessionID, long seq, String data) {
+ if (sessionID == null || "".equals(sessionID)) {
+ throw new IllegalArgumentException("Session ID must not be null or empty");
+ }
+ if (seq < 0 || seq > 65535) {
+ throw new IllegalArgumentException("Sequence must not be between 0 and 65535");
+ }
+ if (data == null) {
+ throw new IllegalArgumentException("Data must not be null");
+ }
+ this.sessionID = sessionID;
+ this.seq = seq;
+ this.data = data;
+ }
+
+ /**
+ * Returns the unique session ID identifying this In-Band Bytestream.
+ *
+ * @return the unique session ID identifying this In-Band Bytestream
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Returns the sequence of this packet in regard to the other data packets.
+ *
+ * @return the sequence of this packet in regard to the other data packets.
+ */
+ public long getSeq() {
+ return seq;
+ }
+
+ /**
+ * Returns the data contained in this packet.
+ *
+ * @return the data contained in this packet.
+ */
+ public String getData() {
+ return data;
+ }
+
+ /**
+ * Returns the decoded data or null if data could not be decoded.
+ * <p>
+ * The encoded data is invalid if it contains bad Base64 input characters or
+ * if it contains the pad ('=') character on a position other than the last
+ * character(s) of the data. See <a
+ * href="http://xmpp.org/extensions/xep-0047.html#sec">XEP-0047</a> Section
+ * 6.
+ *
+ * @return the decoded data
+ */
+ public byte[] getDecodedData() {
+ // return cached decoded data
+ if (this.decodedData != null) {
+ return this.decodedData;
+ }
+
+ // data must not contain the pad (=) other than end of data
+ if (data.matches(".*={1,2}+.+")) {
+ return null;
+ }
+
+ // decodeBase64 will return null if bad characters are included
+ this.decodedData = StringUtils.decodeBase64(data);
+ return this.decodedData;
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return InBandBytestreamManager.NAMESPACE;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<");
+ buf.append(getElementName());
+ buf.append(" ");
+ buf.append("xmlns=\"");
+ buf.append(InBandBytestreamManager.NAMESPACE);
+ buf.append("\" ");
+ buf.append("seq=\"");
+ buf.append(seq);
+ buf.append("\" ");
+ buf.append("sid=\"");
+ buf.append(sessionID);
+ buf.append("\">");
+ buf.append(data);
+ buf.append("</");
+ buf.append(getElementName());
+ buf.append(">");
+ return buf.toString();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java
index 94a7a9bf4..66e924880 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java
@@ -1,126 +1,126 @@
-/**
- * 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.bytestreams.ibb.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
-
-/**
- * Represents a request to open an In-Band Bytestream.
- *
- * @author Henning Staib
- */
-public class Open extends IQ {
-
- /* unique session ID identifying this In-Band Bytestream */
- private final String sessionID;
-
- /* block size in which the data will be fragmented */
- private final int blockSize;
-
- /* stanza type used to encapsulate the data */
- private final StanzaType stanza;
-
- /**
- * Creates a new In-Band Bytestream open request packet.
- * <p>
- * The data sent over this In-Band Bytestream will be fragmented in blocks
- * with the given block size. The block size should not be greater than
- * 65535. A recommended default value is 4096.
- * <p>
- * The data can be sent using IQ stanzas or message stanzas.
- *
- * @param sessionID unique session ID identifying this In-Band Bytestream
- * @param blockSize block size in which the data will be fragmented
- * @param stanza stanza type used to encapsulate the data
- */
- public Open(String sessionID, int blockSize, StanzaType stanza) {
- if (sessionID == null || "".equals(sessionID)) {
- throw new IllegalArgumentException("Session ID must not be null or empty");
- }
- if (blockSize <= 0) {
- throw new IllegalArgumentException("Block size must be greater than zero");
- }
-
- this.sessionID = sessionID;
- this.blockSize = blockSize;
- this.stanza = stanza;
- setType(Type.SET);
- }
-
- /**
- * Creates a new In-Band Bytestream open request packet.
- * <p>
- * The data sent over this In-Band Bytestream will be fragmented in blocks
- * with the given block size. The block size should not be greater than
- * 65535. A recommended default value is 4096.
- * <p>
- * The data will be sent using IQ stanzas.
- *
- * @param sessionID unique session ID identifying this In-Band Bytestream
- * @param blockSize block size in which the data will be fragmented
- */
- public Open(String sessionID, int blockSize) {
- this(sessionID, blockSize, StanzaType.IQ);
- }
-
- /**
- * Returns the unique session ID identifying this In-Band Bytestream.
- *
- * @return the unique session ID identifying this In-Band Bytestream
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Returns the block size in which the data will be fragmented.
- *
- * @return the block size in which the data will be fragmented
- */
- public int getBlockSize() {
- return blockSize;
- }
-
- /**
- * Returns the stanza type used to encapsulate the data.
- *
- * @return the stanza type used to encapsulate the data
- */
- public StanzaType getStanza() {
- return stanza;
- }
-
- @Override
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<open ");
- buf.append("xmlns=\"");
- buf.append(InBandBytestreamManager.NAMESPACE);
- buf.append("\" ");
- buf.append("block-size=\"");
- buf.append(blockSize);
- buf.append("\" ");
- buf.append("sid=\"");
- buf.append(sessionID);
- buf.append("\" ");
- buf.append("stanza=\"");
- buf.append(stanza.toString().toLowerCase());
- buf.append("\"");
- buf.append("/>");
- return buf.toString();
- }
-
-}
+/**
+ * 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.bytestreams.ibb.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
+
+/**
+ * Represents a request to open an In-Band Bytestream.
+ *
+ * @author Henning Staib
+ */
+public class Open extends IQ {
+
+ /* unique session ID identifying this In-Band Bytestream */
+ private final String sessionID;
+
+ /* block size in which the data will be fragmented */
+ private final int blockSize;
+
+ /* stanza type used to encapsulate the data */
+ private final StanzaType stanza;
+
+ /**
+ * Creates a new In-Band Bytestream open request packet.
+ * <p>
+ * The data sent over this In-Band Bytestream will be fragmented in blocks
+ * with the given block size. The block size should not be greater than
+ * 65535. A recommended default value is 4096.
+ * <p>
+ * The data can be sent using IQ stanzas or message stanzas.
+ *
+ * @param sessionID unique session ID identifying this In-Band Bytestream
+ * @param blockSize block size in which the data will be fragmented
+ * @param stanza stanza type used to encapsulate the data
+ */
+ public Open(String sessionID, int blockSize, StanzaType stanza) {
+ if (sessionID == null || "".equals(sessionID)) {
+ throw new IllegalArgumentException("Session ID must not be null or empty");
+ }
+ if (blockSize <= 0) {
+ throw new IllegalArgumentException("Block size must be greater than zero");
+ }
+
+ this.sessionID = sessionID;
+ this.blockSize = blockSize;
+ this.stanza = stanza;
+ setType(Type.SET);
+ }
+
+ /**
+ * Creates a new In-Band Bytestream open request packet.
+ * <p>
+ * The data sent over this In-Band Bytestream will be fragmented in blocks
+ * with the given block size. The block size should not be greater than
+ * 65535. A recommended default value is 4096.
+ * <p>
+ * The data will be sent using IQ stanzas.
+ *
+ * @param sessionID unique session ID identifying this In-Band Bytestream
+ * @param blockSize block size in which the data will be fragmented
+ */
+ public Open(String sessionID, int blockSize) {
+ this(sessionID, blockSize, StanzaType.IQ);
+ }
+
+ /**
+ * Returns the unique session ID identifying this In-Band Bytestream.
+ *
+ * @return the unique session ID identifying this In-Band Bytestream
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Returns the block size in which the data will be fragmented.
+ *
+ * @return the block size in which the data will be fragmented
+ */
+ public int getBlockSize() {
+ return blockSize;
+ }
+
+ /**
+ * Returns the stanza type used to encapsulate the data.
+ *
+ * @return the stanza type used to encapsulate the data
+ */
+ public StanzaType getStanza() {
+ return stanza;
+ }
+
+ @Override
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<open ");
+ buf.append("xmlns=\"");
+ buf.append(InBandBytestreamManager.NAMESPACE);
+ buf.append("\" ");
+ buf.append("block-size=\"");
+ buf.append(blockSize);
+ buf.append("\" ");
+ buf.append("sid=\"");
+ buf.append(sessionID);
+ buf.append("\" ");
+ buf.append("stanza=\"");
+ buf.append(stanza.toString().toLowerCase());
+ buf.append("\"");
+ buf.append("/>");
+ return buf.toString();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/CloseIQProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/CloseIQProvider.java
index 566724c21..5065819d6 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/CloseIQProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/CloseIQProvider.java
@@ -1,33 +1,33 @@
-/**
- * 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.bytestreams.ibb.provider;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Parses a close In-Band Bytestream packet.
- *
- * @author Henning Staib
- */
-public class CloseIQProvider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- String sid = parser.getAttributeValue("", "sid");
- return new Close(sid);
- }
-
-}
+/**
+ * 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.bytestreams.ibb.provider;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses a close In-Band Bytestream packet.
+ *
+ * @author Henning Staib
+ */
+public class CloseIQProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ String sid = parser.getAttributeValue("", "sid");
+ return new Close(sid);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/DataPacketProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/DataPacketProvider.java
index 5abed085c..7c78d695f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/DataPacketProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/DataPacketProvider.java
@@ -1,45 +1,45 @@
-/**
- * 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.bytestreams.ibb.provider;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Parses an In-Band Bytestream data packet which can be a packet extension of
- * either an IQ stanza or a message stanza.
- *
- * @author Henning Staib
- */
-public class DataPacketProvider implements PacketExtensionProvider, IQProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- String sessionID = parser.getAttributeValue("", "sid");
- long seq = Long.parseLong(parser.getAttributeValue("", "seq"));
- String data = parser.nextText();
- return new DataPacketExtension(sessionID, seq, data);
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- DataPacketExtension data = (DataPacketExtension) parseExtension(parser);
- IQ iq = new Data(data);
- return iq;
- }
-
-}
+/**
+ * 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.bytestreams.ibb.provider;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses an In-Band Bytestream data packet which can be a packet extension of
+ * either an IQ stanza or a message stanza.
+ *
+ * @author Henning Staib
+ */
+public class DataPacketProvider implements PacketExtensionProvider, IQProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ String sessionID = parser.getAttributeValue("", "sid");
+ long seq = Long.parseLong(parser.getAttributeValue("", "seq"));
+ String data = parser.nextText();
+ return new DataPacketExtension(sessionID, seq, data);
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ DataPacketExtension data = (DataPacketExtension) parseExtension(parser);
+ IQ iq = new Data(data);
+ return iq;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/OpenIQProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/OpenIQProvider.java
index 3cc725ae8..4ff81e8d1 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/OpenIQProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/ibb/provider/OpenIQProvider.java
@@ -1,45 +1,45 @@
-/**
- * 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.bytestreams.ibb.provider;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Parses an In-Band Bytestream open packet.
- *
- * @author Henning Staib
- */
-public class OpenIQProvider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- String sessionID = parser.getAttributeValue("", "sid");
- int blockSize = Integer.parseInt(parser.getAttributeValue("", "block-size"));
-
- String stanzaValue = parser.getAttributeValue("", "stanza");
- StanzaType stanza = null;
- if (stanzaValue == null) {
- stanza = StanzaType.IQ;
- }
- else {
- stanza = StanzaType.valueOf(stanzaValue.toUpperCase());
- }
-
- return new Open(sessionID, blockSize, stanza);
- }
-
-}
+/**
+ * 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.bytestreams.ibb.provider;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses an In-Band Bytestream open packet.
+ *
+ * @author Henning Staib
+ */
+public class OpenIQProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ String sessionID = parser.getAttributeValue("", "sid");
+ int blockSize = Integer.parseInt(parser.getAttributeValue("", "block-size"));
+
+ String stanzaValue = parser.getAttributeValue("", "stanza");
+ StanzaType stanza = null;
+ if (stanzaValue == null) {
+ stanza = StanzaType.IQ;
+ }
+ else {
+ stanza = StanzaType.valueOf(stanzaValue.toUpperCase());
+ }
+
+ return new Open(sessionID, blockSize, stanza);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/InitiationListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/InitiationListener.java
index 2a78250a0..a5a882586 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/InitiationListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/InitiationListener.java
@@ -1,119 +1,119 @@
-/**
- * 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.bytestreams.socks5;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.IQTypeFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
-
-/**
- * InitiationListener handles all incoming SOCKS5 Bytestream initiation requests. If there are no
- * listeners for a SOCKS5 bytestream request InitiationListener will always refuse the request and
- * reply with a &lt;not-acceptable/&gt; error (<a
- * href="http://xmpp.org/extensions/xep-0065.html#usecase-alternate">XEP-0065</a> Section 5.2.A2).
- *
- * @author Henning Staib
- */
-final class InitiationListener implements PacketListener {
-
- /* manager containing the listeners and the XMPP connection */
- private final Socks5BytestreamManager manager;
-
- /* packet filter for all SOCKS5 Bytestream requests */
- private final PacketFilter initFilter = new AndFilter(new PacketTypeFilter(Bytestream.class),
- new IQTypeFilter(IQ.Type.SET));
-
- /* executor service to process incoming requests concurrently */
- private final ExecutorService initiationListenerExecutor;
-
- /**
- * Constructor
- *
- * @param manager the SOCKS5 Bytestream manager
- */
- protected InitiationListener(Socks5BytestreamManager manager) {
- this.manager = manager;
- initiationListenerExecutor = Executors.newCachedThreadPool();
- }
-
- public void processPacket(final Packet packet) {
- initiationListenerExecutor.execute(new Runnable() {
-
- public void run() {
- processRequest(packet);
- }
- });
- }
-
- private void processRequest(Packet packet) {
- Bytestream byteStreamRequest = (Bytestream) packet;
-
- // ignore request if in ignore list
- if (this.manager.getIgnoredBytestreamRequests().remove(byteStreamRequest.getSessionID())) {
- return;
- }
-
- // build bytestream request from packet
- Socks5BytestreamRequest request = new Socks5BytestreamRequest(this.manager,
- byteStreamRequest);
-
- // notify listeners for bytestream initiation from a specific user
- BytestreamListener userListener = this.manager.getUserListener(byteStreamRequest.getFrom());
- if (userListener != null) {
- userListener.incomingBytestreamRequest(request);
-
- }
- else if (!this.manager.getAllRequestListeners().isEmpty()) {
- /*
- * if there is no user specific listener inform listeners for all initiation requests
- */
- for (BytestreamListener listener : this.manager.getAllRequestListeners()) {
- listener.incomingBytestreamRequest(request);
- }
-
- }
- else {
- /*
- * if there is no listener for this initiation request, reply with reject message
- */
- this.manager.replyRejectPacket(byteStreamRequest);
- }
- }
-
- /**
- * Returns the packet filter for SOCKS5 Bytestream initialization requests.
- *
- * @return the packet filter for SOCKS5 Bytestream initialization requests
- */
- protected PacketFilter getFilter() {
- return this.initFilter;
- }
-
- /**
- * Shuts down the listeners executor service.
- */
- protected void shutdown() {
- this.initiationListenerExecutor.shutdownNow();
- }
-
-}
+/**
+ * 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.bytestreams.socks5;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.IQTypeFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
+
+/**
+ * InitiationListener handles all incoming SOCKS5 Bytestream initiation requests. If there are no
+ * listeners for a SOCKS5 bytestream request InitiationListener will always refuse the request and
+ * reply with a &lt;not-acceptable/&gt; error (<a
+ * href="http://xmpp.org/extensions/xep-0065.html#usecase-alternate">XEP-0065</a> Section 5.2.A2).
+ *
+ * @author Henning Staib
+ */
+final class InitiationListener implements PacketListener {
+
+ /* manager containing the listeners and the XMPP connection */
+ private final Socks5BytestreamManager manager;
+
+ /* packet filter for all SOCKS5 Bytestream requests */
+ private final PacketFilter initFilter = new AndFilter(new PacketTypeFilter(Bytestream.class),
+ new IQTypeFilter(IQ.Type.SET));
+
+ /* executor service to process incoming requests concurrently */
+ private final ExecutorService initiationListenerExecutor;
+
+ /**
+ * Constructor
+ *
+ * @param manager the SOCKS5 Bytestream manager
+ */
+ protected InitiationListener(Socks5BytestreamManager manager) {
+ this.manager = manager;
+ initiationListenerExecutor = Executors.newCachedThreadPool();
+ }
+
+ public void processPacket(final Packet packet) {
+ initiationListenerExecutor.execute(new Runnable() {
+
+ public void run() {
+ processRequest(packet);
+ }
+ });
+ }
+
+ private void processRequest(Packet packet) {
+ Bytestream byteStreamRequest = (Bytestream) packet;
+
+ // ignore request if in ignore list
+ if (this.manager.getIgnoredBytestreamRequests().remove(byteStreamRequest.getSessionID())) {
+ return;
+ }
+
+ // build bytestream request from packet
+ Socks5BytestreamRequest request = new Socks5BytestreamRequest(this.manager,
+ byteStreamRequest);
+
+ // notify listeners for bytestream initiation from a specific user
+ BytestreamListener userListener = this.manager.getUserListener(byteStreamRequest.getFrom());
+ if (userListener != null) {
+ userListener.incomingBytestreamRequest(request);
+
+ }
+ else if (!this.manager.getAllRequestListeners().isEmpty()) {
+ /*
+ * if there is no user specific listener inform listeners for all initiation requests
+ */
+ for (BytestreamListener listener : this.manager.getAllRequestListeners()) {
+ listener.incomingBytestreamRequest(request);
+ }
+
+ }
+ else {
+ /*
+ * if there is no listener for this initiation request, reply with reject message
+ */
+ this.manager.replyRejectPacket(byteStreamRequest);
+ }
+ }
+
+ /**
+ * Returns the packet filter for SOCKS5 Bytestream initialization requests.
+ *
+ * @return the packet filter for SOCKS5 Bytestream initialization requests
+ */
+ protected PacketFilter getFilter() {
+ return this.initFilter;
+ }
+
+ /**
+ * Shuts down the listeners executor service.
+ */
+ protected void shutdown() {
+ this.initiationListenerExecutor.shutdownNow();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamListener.java
index 1430b1d23..39c8d335e 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamListener.java
@@ -1,43 +1,43 @@
-/**
- * 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.bytestreams.socks5;
-
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
-
-/**
- * Socks5BytestreamListener are informed if a remote user wants to initiate a SOCKS5 Bytestream.
- * Implement this interface to handle incoming SOCKS5 Bytestream requests.
- * <p>
- * There are two ways to add this listener. See
- * {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
- * {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for
- * further details.
- *
- * @author Henning Staib
- */
-public abstract class Socks5BytestreamListener implements BytestreamListener {
-
- public void incomingBytestreamRequest(BytestreamRequest request) {
- incomingBytestreamRequest((Socks5BytestreamRequest) request);
- }
-
- /**
- * This listener is notified if a SOCKS5 Bytestream request from another user has been received.
- *
- * @param request the incoming SOCKS5 Bytestream request
- */
- public abstract void incomingBytestreamRequest(Socks5BytestreamRequest request);
-
-}
+/**
+ * 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.bytestreams.socks5;
+
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
+
+/**
+ * Socks5BytestreamListener are informed if a remote user wants to initiate a SOCKS5 Bytestream.
+ * Implement this interface to handle incoming SOCKS5 Bytestream requests.
+ * <p>
+ * There are two ways to add this listener. See
+ * {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
+ * {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for
+ * further details.
+ *
+ * @author Henning Staib
+ */
+public abstract class Socks5BytestreamListener implements BytestreamListener {
+
+ public void incomingBytestreamRequest(BytestreamRequest request) {
+ incomingBytestreamRequest((Socks5BytestreamRequest) request);
+ }
+
+ /**
+ * This listener is notified if a SOCKS5 Bytestream request from another user has been received.
+ *
+ * @param request the incoming SOCKS5 Bytestream request
+ */
+ public abstract void incomingBytestreamRequest(Socks5BytestreamRequest request);
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java
index 286041519..d78d5d1bc 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java
@@ -1,768 +1,768 @@
-/**
- * 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.bytestreams.socks5;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeoutException;
-
-import org.jivesoftware.smack.AbstractConnectionListener;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.ConnectionCreationListener;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.util.SyncPacketSend;
-import org.jivesoftware.smackx.ServiceDiscoveryManager;
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.BytestreamManager;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHostUsed;
-import org.jivesoftware.smackx.filetransfer.FileTransferManager;
-import org.jivesoftware.smackx.packet.DiscoverInfo;
-import org.jivesoftware.smackx.packet.DiscoverItems;
-import org.jivesoftware.smackx.packet.DiscoverInfo.Identity;
-import org.jivesoftware.smackx.packet.DiscoverItems.Item;
-
-/**
- * The Socks5BytestreamManager class handles establishing SOCKS5 Bytestreams as specified in the <a
- * href="http://xmpp.org/extensions/xep-0065.html">XEP-0065</a>.
- * <p>
- * A SOCKS5 Bytestream is negotiated partly over the XMPP XML stream and partly over a separate
- * socket. The actual transfer though takes place over a separately created socket.
- * <p>
- * A SOCKS5 Bytestream generally has three parties, the initiator, the target, and the stream host.
- * The stream host is a specialized SOCKS5 proxy setup on a server, or, the initiator can act as the
- * stream host.
- * <p>
- * To establish a SOCKS5 Bytestream invoke the {@link #establishSession(String)} method. This will
- * negotiate a SOCKS5 Bytestream with the given target JID and return a socket.
- * <p>
- * If a session ID for the SOCKS5 Bytestream was already negotiated (e.g. while negotiating a file
- * transfer) invoke {@link #establishSession(String, String)}.
- * <p>
- * To handle incoming SOCKS5 Bytestream requests add an {@link Socks5BytestreamListener} to the
- * manager. There are two ways to add this listener. If you want to be informed about incoming
- * SOCKS5 Bytestreams from a specific user add the listener by invoking
- * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should
- * respond to all SOCKS5 Bytestream requests invoke
- * {@link #addIncomingBytestreamListener(BytestreamListener)}.
- * <p>
- * Note that the registered {@link Socks5BytestreamListener} will NOT be notified on incoming Socks5
- * bytestream requests sent in the context of <a
- * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
- * {@link FileTransferManager})
- * <p>
- * If no {@link Socks5BytestreamListener}s are registered, all incoming SOCKS5 Bytestream requests
- * will be rejected by returning a &lt;not-acceptable/&gt; error to the initiator.
- *
- * @author Henning Staib
- */
-public final class Socks5BytestreamManager implements BytestreamManager {
-
- /*
- * create a new Socks5BytestreamManager and register a shutdown listener on every established
- * connection
- */
- static {
- Connection.addConnectionCreationListener(new ConnectionCreationListener() {
-
- public void connectionCreated(Connection connection) {
- final Socks5BytestreamManager manager;
- manager = Socks5BytestreamManager.getBytestreamManager(connection);
-
- // register shutdown listener
- connection.addConnectionListener(new AbstractConnectionListener() {
-
- public void connectionClosed() {
- manager.disableService();
- }
-
- });
- }
-
- });
- }
-
- /**
- * The XMPP namespace of the SOCKS5 Bytestream
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/bytestreams";
-
- /* prefix used to generate session IDs */
- private static final String SESSION_ID_PREFIX = "js5_";
-
- /* random generator to create session IDs */
- private final static Random randomGenerator = new Random();
-
- /* stores one Socks5BytestreamManager for each XMPP connection */
- private final static Map<Connection, Socks5BytestreamManager> managers = new HashMap<Connection, Socks5BytestreamManager>();
-
- /* XMPP connection */
- private final Connection connection;
-
- /*
- * assigns a user to a listener that is informed if a bytestream request for this user is
- * received
- */
- private final Map<String, BytestreamListener> userListeners = new ConcurrentHashMap<String, BytestreamListener>();
-
- /*
- * list of listeners that respond to all bytestream requests if there are not user specific
- * listeners for that request
- */
- private final List<BytestreamListener> allRequestListeners = Collections.synchronizedList(new LinkedList<BytestreamListener>());
-
- /* listener that handles all incoming bytestream requests */
- private final InitiationListener initiationListener;
-
- /* timeout to wait for the response to the SOCKS5 Bytestream initialization request */
- private int targetResponseTimeout = 10000;
-
- /* timeout for connecting to the SOCKS5 proxy selected by the target */
- private int proxyConnectionTimeout = 10000;
-
- /* blacklist of errornous SOCKS5 proxies */
- private final List<String> proxyBlacklist = Collections.synchronizedList(new LinkedList<String>());
-
- /* remember the last proxy that worked to prioritize it */
- private String lastWorkingProxy = null;
-
- /* flag to enable/disable prioritization of last working proxy */
- private boolean proxyPrioritizationEnabled = true;
-
- /*
- * list containing session IDs of SOCKS5 Bytestream initialization packets that should be
- * ignored by the InitiationListener
- */
- private List<String> ignoredBytestreamRequests = Collections.synchronizedList(new LinkedList<String>());
-
- /**
- * Returns the Socks5BytestreamManager to handle SOCKS5 Bytestreams for a given
- * {@link Connection}.
- * <p>
- * If no manager exists a new is created and initialized.
- *
- * @param connection the XMPP connection or <code>null</code> if given connection is
- * <code>null</code>
- * @return the Socks5BytestreamManager for the given XMPP connection
- */
- public static synchronized Socks5BytestreamManager getBytestreamManager(Connection connection) {
- if (connection == null) {
- return null;
- }
- Socks5BytestreamManager manager = managers.get(connection);
- if (manager == null) {
- manager = new Socks5BytestreamManager(connection);
- managers.put(connection, manager);
- manager.activate();
- }
- return manager;
- }
-
- /**
- * Private constructor.
- *
- * @param connection the XMPP connection
- */
- private Socks5BytestreamManager(Connection connection) {
- this.connection = connection;
- this.initiationListener = new InitiationListener(this);
- }
-
- /**
- * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request unless
- * there is a user specific BytestreamListener registered.
- * <p>
- * If no listeners are registered all SOCKS5 Bytestream request are rejected with a
- * &lt;not-acceptable/&gt; error.
- * <p>
- * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5
- * bytestream requests sent in the context of <a
- * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
- * {@link FileTransferManager})
- *
- * @param listener the listener to register
- */
- public void addIncomingBytestreamListener(BytestreamListener listener) {
- this.allRequestListeners.add(listener);
- }
-
- /**
- * Removes the given listener from the list of listeners for all incoming SOCKS5 Bytestream
- * requests.
- *
- * @param listener the listener to remove
- */
- public void removeIncomingBytestreamListener(BytestreamListener listener) {
- this.allRequestListeners.remove(listener);
- }
-
- /**
- * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request from the
- * given user.
- * <p>
- * Use this method if you are awaiting an incoming SOCKS5 Bytestream request from a specific
- * user.
- * <p>
- * If no listeners are registered all SOCKS5 Bytestream request are rejected with a
- * &lt;not-acceptable/&gt; error.
- * <p>
- * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5
- * bytestream requests sent in the context of <a
- * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
- * {@link FileTransferManager})
- *
- * @param listener the listener to register
- * @param initiatorJID the JID of the user that wants to establish a SOCKS5 Bytestream
- */
- public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) {
- this.userListeners.put(initiatorJID, listener);
- }
-
- /**
- * Removes the listener for the given user.
- *
- * @param initiatorJID the JID of the user the listener should be removed
- */
- public void removeIncomingBytestreamListener(String initiatorJID) {
- this.userListeners.remove(initiatorJID);
- }
-
- /**
- * Use this method to ignore the next incoming SOCKS5 Bytestream request containing the given
- * session ID. No listeners will be notified for this request and and no error will be returned
- * to the initiator.
- * <p>
- * This method should be used if you are awaiting a SOCKS5 Bytestream request as a reply to
- * another packet (e.g. file transfer).
- *
- * @param sessionID to be ignored
- */
- public void ignoreBytestreamRequestOnce(String sessionID) {
- this.ignoredBytestreamRequests.add(sessionID);
- }
-
- /**
- * Disables the SOCKS5 Bytestream manager by removing the SOCKS5 Bytestream feature from the
- * service discovery, disabling the listener for SOCKS5 Bytestream initiation requests and
- * resetting its internal state.
- * <p>
- * To re-enable the SOCKS5 Bytestream feature invoke {@link #getBytestreamManager(Connection)}.
- * Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature.
- */
- public synchronized void disableService() {
-
- // remove initiation packet listener
- this.connection.removePacketListener(this.initiationListener);
-
- // shutdown threads
- this.initiationListener.shutdown();
-
- // clear listeners
- this.allRequestListeners.clear();
- this.userListeners.clear();
-
- // reset internal state
- this.lastWorkingProxy = null;
- this.proxyBlacklist.clear();
- this.ignoredBytestreamRequests.clear();
-
- // remove manager from static managers map
- managers.remove(this.connection);
-
- // shutdown local SOCKS5 proxy if there are no more managers for other connections
- if (managers.size() == 0) {
- Socks5Proxy.getSocks5Proxy().stop();
- }
-
- // remove feature from service discovery
- ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
-
- // check if service discovery is not already disposed by connection shutdown
- if (serviceDiscoveryManager != null) {
- serviceDiscoveryManager.removeFeature(NAMESPACE);
- }
-
- }
-
- /**
- * Returns the timeout to wait for the response to the SOCKS5 Bytestream initialization request.
- * Default is 10000ms.
- *
- * @return the timeout to wait for the response to the SOCKS5 Bytestream initialization request
- */
- public int getTargetResponseTimeout() {
- if (this.targetResponseTimeout <= 0) {
- this.targetResponseTimeout = 10000;
- }
- return targetResponseTimeout;
- }
-
- /**
- * Sets the timeout to wait for the response to the SOCKS5 Bytestream initialization request.
- * Default is 10000ms.
- *
- * @param targetResponseTimeout the timeout to set
- */
- public void setTargetResponseTimeout(int targetResponseTimeout) {
- this.targetResponseTimeout = targetResponseTimeout;
- }
-
- /**
- * Returns the timeout for connecting to the SOCKS5 proxy selected by the target. Default is
- * 10000ms.
- *
- * @return the timeout for connecting to the SOCKS5 proxy selected by the target
- */
- public int getProxyConnectionTimeout() {
- if (this.proxyConnectionTimeout <= 0) {
- this.proxyConnectionTimeout = 10000;
- }
- return proxyConnectionTimeout;
- }
-
- /**
- * Sets the timeout for connecting to the SOCKS5 proxy selected by the target. Default is
- * 10000ms.
- *
- * @param proxyConnectionTimeout the timeout to set
- */
- public void setProxyConnectionTimeout(int proxyConnectionTimeout) {
- this.proxyConnectionTimeout = proxyConnectionTimeout;
- }
-
- /**
- * Returns if the prioritization of the last working SOCKS5 proxy on successive SOCKS5
- * Bytestream connections is enabled. Default is <code>true</code>.
- *
- * @return <code>true</code> if prioritization is enabled, <code>false</code> otherwise
- */
- public boolean isProxyPrioritizationEnabled() {
- return proxyPrioritizationEnabled;
- }
-
- /**
- * Enable/disable the prioritization of the last working SOCKS5 proxy on successive SOCKS5
- * Bytestream connections.
- *
- * @param proxyPrioritizationEnabled enable/disable the prioritization of the last working
- * SOCKS5 proxy
- */
- public void setProxyPrioritizationEnabled(boolean proxyPrioritizationEnabled) {
- this.proxyPrioritizationEnabled = proxyPrioritizationEnabled;
- }
-
- /**
- * Establishes a SOCKS5 Bytestream with the given user and returns the Socket to send/receive
- * data to/from the user.
- * <p>
- * Use this method to establish SOCKS5 Bytestreams to users accepting all incoming Socks5
- * bytestream requests since this method doesn't provide a way to tell the user something about
- * the data to be sent.
- * <p>
- * To establish a SOCKS5 Bytestream after negotiation the kind of data to be sent (e.g. file
- * transfer) use {@link #establishSession(String, String)}.
- *
- * @param targetJID the JID of the user a SOCKS5 Bytestream should be established
- * @return the Socket to send/receive data to/from the user
- * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5
- * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies
- * @throws IOException if the bytestream could not be established
- * @throws InterruptedException if the current thread was interrupted while waiting
- */
- public Socks5BytestreamSession establishSession(String targetJID) throws XMPPException,
- IOException, InterruptedException {
- String sessionID = getNextSessionID();
- return establishSession(targetJID, sessionID);
- }
-
- /**
- * Establishes a SOCKS5 Bytestream with the given user using the given session ID and returns
- * the Socket to send/receive data to/from the user.
- *
- * @param targetJID the JID of the user a SOCKS5 Bytestream should be established
- * @param sessionID the session ID for the SOCKS5 Bytestream request
- * @return the Socket to send/receive data to/from the user
- * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5
- * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies
- * @throws IOException if the bytestream could not be established
- * @throws InterruptedException if the current thread was interrupted while waiting
- */
- public Socks5BytestreamSession establishSession(String targetJID, String sessionID)
- throws XMPPException, IOException, InterruptedException {
-
- XMPPException discoveryException = null;
- // check if target supports SOCKS5 Bytestream
- if (!supportsSocks5(targetJID)) {
- throw new XMPPException(targetJID + " doesn't support SOCKS5 Bytestream");
- }
-
- List<String> proxies = new ArrayList<String>();
- // determine SOCKS5 proxies from XMPP-server
- try {
- proxies.addAll(determineProxies());
- } catch (XMPPException e) {
- // don't abort here, just remember the exception thrown by determineProxies()
- // determineStreamHostInfos() will at least add the local Socks5 proxy (if enabled)
- discoveryException = e;
- }
-
- // determine address and port of each proxy
- List<StreamHost> streamHosts = determineStreamHostInfos(proxies);
-
- if (streamHosts.isEmpty()) {
- throw discoveryException != null ? discoveryException : new XMPPException("no SOCKS5 proxies available");
- }
-
- // compute digest
- String digest = Socks5Utils.createDigest(sessionID, this.connection.getUser(), targetJID);
-
- // prioritize last working SOCKS5 proxy if exists
- if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) {
- StreamHost selectedStreamHost = null;
- for (StreamHost streamHost : streamHosts) {
- if (streamHost.getJID().equals(this.lastWorkingProxy)) {
- selectedStreamHost = streamHost;
- break;
- }
- }
- if (selectedStreamHost != null) {
- streamHosts.remove(selectedStreamHost);
- streamHosts.add(0, selectedStreamHost);
- }
-
- }
-
- Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
- try {
-
- // add transfer digest to local proxy to make transfer valid
- socks5Proxy.addTransfer(digest);
-
- // create initiation packet
- Bytestream initiation = createBytestreamInitiation(sessionID, targetJID, streamHosts);
-
- // send initiation packet
- Packet response = SyncPacketSend.getReply(this.connection, initiation,
- getTargetResponseTimeout());
-
- // extract used stream host from response
- StreamHostUsed streamHostUsed = ((Bytestream) response).getUsedHost();
- StreamHost usedStreamHost = initiation.getStreamHost(streamHostUsed.getJID());
-
- if (usedStreamHost == null) {
- throw new XMPPException("Remote user responded with unknown host");
- }
-
- // build SOCKS5 client
- Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest,
- this.connection, sessionID, targetJID);
-
- // establish connection to proxy
- Socket socket = socks5Client.getSocket(getProxyConnectionTimeout());
-
- // remember last working SOCKS5 proxy to prioritize it for next request
- this.lastWorkingProxy = usedStreamHost.getJID();
-
- // negotiation successful, return the output stream
- return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals(
- this.connection.getUser()));
-
- }
- catch (TimeoutException e) {
- throw new IOException("Timeout while connecting to SOCKS5 proxy");
- }
- finally {
-
- // remove transfer digest if output stream is returned or an exception
- // occurred
- socks5Proxy.removeTransfer(digest);
-
- }
- }
-
- /**
- * Returns <code>true</code> if the given target JID supports feature SOCKS5 Bytestream.
- *
- * @param targetJID the target JID
- * @return <code>true</code> if the given target JID supports feature SOCKS5 Bytestream
- * otherwise <code>false</code>
- * @throws XMPPException if there was an error querying target for supported features
- */
- private boolean supportsSocks5(String targetJID) throws XMPPException {
- ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
- DiscoverInfo discoverInfo = serviceDiscoveryManager.discoverInfo(targetJID);
- return discoverInfo.containsFeature(NAMESPACE);
- }
-
- /**
- * Returns a list of JIDs of SOCKS5 proxies by querying the XMPP server. The SOCKS5 proxies are
- * in the same order as returned by the XMPP server.
- *
- * @return list of JIDs of SOCKS5 proxies
- * @throws XMPPException if there was an error querying the XMPP server for SOCKS5 proxies
- */
- private List<String> determineProxies() throws XMPPException {
- ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
-
- List<String> proxies = new ArrayList<String>();
-
- // get all items form XMPP server
- DiscoverItems discoverItems = serviceDiscoveryManager.discoverItems(this.connection.getServiceName());
- Iterator<Item> itemIterator = discoverItems.getItems();
-
- // query all items if they are SOCKS5 proxies
- while (itemIterator.hasNext()) {
- Item item = itemIterator.next();
-
- // skip blacklisted servers
- if (this.proxyBlacklist.contains(item.getEntityID())) {
- continue;
- }
-
- try {
- DiscoverInfo proxyInfo;
- proxyInfo = serviceDiscoveryManager.discoverInfo(item.getEntityID());
- Iterator<Identity> identities = proxyInfo.getIdentities();
-
- // item must have category "proxy" and type "bytestream"
- while (identities.hasNext()) {
- Identity identity = identities.next();
-
- if ("proxy".equalsIgnoreCase(identity.getCategory())
- && "bytestreams".equalsIgnoreCase(identity.getType())) {
- proxies.add(item.getEntityID());
- break;
- }
-
- /*
- * server is not a SOCKS5 proxy, blacklist server to skip next time a Socks5
- * bytestream should be established
- */
- this.proxyBlacklist.add(item.getEntityID());
-
- }
- }
- catch (XMPPException e) {
- // blacklist errornous server
- this.proxyBlacklist.add(item.getEntityID());
- }
- }
-
- return proxies;
- }
-
- /**
- * Returns a list of stream hosts containing the IP address an the port for the given list of
- * SOCKS5 proxy JIDs. The order of the returned list is the same as the given list of JIDs
- * excluding all SOCKS5 proxies who's network settings could not be determined. If a local
- * SOCKS5 proxy is running it will be the first item in the list returned.
- *
- * @param proxies a list of SOCKS5 proxy JIDs
- * @return a list of stream hosts containing the IP address an the port
- */
- private List<StreamHost> determineStreamHostInfos(List<String> proxies) {
- List<StreamHost> streamHosts = new ArrayList<StreamHost>();
-
- // add local proxy on first position if exists
- List<StreamHost> localProxies = getLocalStreamHost();
- if (localProxies != null) {
- streamHosts.addAll(localProxies);
- }
-
- // query SOCKS5 proxies for network settings
- for (String proxy : proxies) {
- Bytestream streamHostRequest = createStreamHostRequest(proxy);
- try {
- Bytestream response = (Bytestream) SyncPacketSend.getReply(this.connection,
- streamHostRequest);
- streamHosts.addAll(response.getStreamHosts());
- }
- catch (XMPPException e) {
- // blacklist errornous proxies
- this.proxyBlacklist.add(proxy);
- }
- }
-
- return streamHosts;
- }
-
- /**
- * Returns a IQ packet to query a SOCKS5 proxy its network settings.
- *
- * @param proxy the proxy to query
- * @return IQ packet to query a SOCKS5 proxy its network settings
- */
- private Bytestream createStreamHostRequest(String proxy) {
- Bytestream request = new Bytestream();
- request.setType(IQ.Type.GET);
- request.setTo(proxy);
- return request;
- }
-
- /**
- * Returns the stream host information of the local SOCKS5 proxy containing the IP address and
- * the port or null if local SOCKS5 proxy is not running.
- *
- * @return the stream host information of the local SOCKS5 proxy or null if local SOCKS5 proxy
- * is not running
- */
- private List<StreamHost> getLocalStreamHost() {
-
- // get local proxy singleton
- Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
-
- if (socks5Server.isRunning()) {
- List<String> addresses = socks5Server.getLocalAddresses();
- int port = socks5Server.getPort();
-
- if (addresses.size() >= 1) {
- List<StreamHost> streamHosts = new ArrayList<StreamHost>();
- for (String address : addresses) {
- StreamHost streamHost = new StreamHost(this.connection.getUser(), address);
- streamHost.setPort(port);
- streamHosts.add(streamHost);
- }
- return streamHosts;
- }
-
- }
-
- // server is not running or local address could not be determined
- return null;
- }
-
- /**
- * Returns a SOCKS5 Bytestream initialization request packet with the given session ID
- * containing the given stream hosts for the given target JID.
- *
- * @param sessionID the session ID for the SOCKS5 Bytestream
- * @param targetJID the target JID of SOCKS5 Bytestream request
- * @param streamHosts a list of SOCKS5 proxies the target should connect to
- * @return a SOCKS5 Bytestream initialization request packet
- */
- private Bytestream createBytestreamInitiation(String sessionID, String targetJID,
- List<StreamHost> streamHosts) {
- Bytestream initiation = new Bytestream(sessionID);
-
- // add all stream hosts
- for (StreamHost streamHost : streamHosts) {
- initiation.addStreamHost(streamHost);
- }
-
- initiation.setType(IQ.Type.SET);
- initiation.setTo(targetJID);
-
- return initiation;
- }
-
- /**
- * Responses to the given packet's sender with a XMPP error that a SOCKS5 Bytestream is not
- * accepted.
- *
- * @param packet Packet that should be answered with a not-acceptable error
- */
- protected void replyRejectPacket(IQ packet) {
- XMPPError xmppError = new XMPPError(XMPPError.Condition.no_acceptable);
- IQ errorIQ = IQ.createErrorResponse(packet, xmppError);
- this.connection.sendPacket(errorIQ);
- }
-
- /**
- * Activates the Socks5BytestreamManager by registering the SOCKS5 Bytestream initialization
- * listener and enabling the SOCKS5 Bytestream feature.
- */
- private void activate() {
- // register bytestream initiation packet listener
- this.connection.addPacketListener(this.initiationListener,
- this.initiationListener.getFilter());
-
- // enable SOCKS5 feature
- enableService();
- }
-
- /**
- * Adds the SOCKS5 Bytestream feature to the service discovery.
- */
- private void enableService() {
- ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(this.connection);
- if (!manager.includesFeature(NAMESPACE)) {
- manager.addFeature(NAMESPACE);
- }
- }
-
- /**
- * Returns a new unique session ID.
- *
- * @return a new unique session ID
- */
- private String getNextSessionID() {
- StringBuilder buffer = new StringBuilder();
- buffer.append(SESSION_ID_PREFIX);
- buffer.append(Math.abs(randomGenerator.nextLong()));
- return buffer.toString();
- }
-
- /**
- * Returns the XMPP connection.
- *
- * @return the XMPP connection
- */
- protected Connection getConnection() {
- return this.connection;
- }
-
- /**
- * Returns the {@link BytestreamListener} that should be informed if a SOCKS5 Bytestream request
- * from the given initiator JID is received.
- *
- * @param initiator the initiator's JID
- * @return the listener
- */
- protected BytestreamListener getUserListener(String initiator) {
- return this.userListeners.get(initiator);
- }
-
- /**
- * Returns a list of {@link BytestreamListener} that are informed if there are no listeners for
- * a specific initiator.
- *
- * @return list of listeners
- */
- protected List<BytestreamListener> getAllRequestListeners() {
- return this.allRequestListeners;
- }
-
- /**
- * Returns the list of session IDs that should be ignored by the InitialtionListener
- *
- * @return list of session IDs
- */
- protected List<String> getIgnoredBytestreamRequests() {
- return ignoredBytestreamRequests;
- }
-
-}
+/**
+ * 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.bytestreams.socks5;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeoutException;
+
+import org.jivesoftware.smack.AbstractConnectionListener;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.ConnectionCreationListener;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.util.SyncPacketSend;
+import org.jivesoftware.smackx.ServiceDiscoveryManager;
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.BytestreamManager;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHostUsed;
+import org.jivesoftware.smackx.filetransfer.FileTransferManager;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
+import org.jivesoftware.smackx.packet.DiscoverItems;
+import org.jivesoftware.smackx.packet.DiscoverInfo.Identity;
+import org.jivesoftware.smackx.packet.DiscoverItems.Item;
+
+/**
+ * The Socks5BytestreamManager class handles establishing SOCKS5 Bytestreams as specified in the <a
+ * href="http://xmpp.org/extensions/xep-0065.html">XEP-0065</a>.
+ * <p>
+ * A SOCKS5 Bytestream is negotiated partly over the XMPP XML stream and partly over a separate
+ * socket. The actual transfer though takes place over a separately created socket.
+ * <p>
+ * A SOCKS5 Bytestream generally has three parties, the initiator, the target, and the stream host.
+ * The stream host is a specialized SOCKS5 proxy setup on a server, or, the initiator can act as the
+ * stream host.
+ * <p>
+ * To establish a SOCKS5 Bytestream invoke the {@link #establishSession(String)} method. This will
+ * negotiate a SOCKS5 Bytestream with the given target JID and return a socket.
+ * <p>
+ * If a session ID for the SOCKS5 Bytestream was already negotiated (e.g. while negotiating a file
+ * transfer) invoke {@link #establishSession(String, String)}.
+ * <p>
+ * To handle incoming SOCKS5 Bytestream requests add an {@link Socks5BytestreamListener} to the
+ * manager. There are two ways to add this listener. If you want to be informed about incoming
+ * SOCKS5 Bytestreams from a specific user add the listener by invoking
+ * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should
+ * respond to all SOCKS5 Bytestream requests invoke
+ * {@link #addIncomingBytestreamListener(BytestreamListener)}.
+ * <p>
+ * Note that the registered {@link Socks5BytestreamListener} will NOT be notified on incoming Socks5
+ * bytestream requests sent in the context of <a
+ * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
+ * {@link FileTransferManager})
+ * <p>
+ * If no {@link Socks5BytestreamListener}s are registered, all incoming SOCKS5 Bytestream requests
+ * will be rejected by returning a &lt;not-acceptable/&gt; error to the initiator.
+ *
+ * @author Henning Staib
+ */
+public final class Socks5BytestreamManager implements BytestreamManager {
+
+ /*
+ * create a new Socks5BytestreamManager and register a shutdown listener on every established
+ * connection
+ */
+ static {
+ Connection.addConnectionCreationListener(new ConnectionCreationListener() {
+
+ public void connectionCreated(Connection connection) {
+ final Socks5BytestreamManager manager;
+ manager = Socks5BytestreamManager.getBytestreamManager(connection);
+
+ // register shutdown listener
+ connection.addConnectionListener(new AbstractConnectionListener() {
+
+ public void connectionClosed() {
+ manager.disableService();
+ }
+
+ });
+ }
+
+ });
+ }
+
+ /**
+ * The XMPP namespace of the SOCKS5 Bytestream
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/bytestreams";
+
+ /* prefix used to generate session IDs */
+ private static final String SESSION_ID_PREFIX = "js5_";
+
+ /* random generator to create session IDs */
+ private final static Random randomGenerator = new Random();
+
+ /* stores one Socks5BytestreamManager for each XMPP connection */
+ private final static Map<Connection, Socks5BytestreamManager> managers = new HashMap<Connection, Socks5BytestreamManager>();
+
+ /* XMPP connection */
+ private final Connection connection;
+
+ /*
+ * assigns a user to a listener that is informed if a bytestream request for this user is
+ * received
+ */
+ private final Map<String, BytestreamListener> userListeners = new ConcurrentHashMap<String, BytestreamListener>();
+
+ /*
+ * list of listeners that respond to all bytestream requests if there are not user specific
+ * listeners for that request
+ */
+ private final List<BytestreamListener> allRequestListeners = Collections.synchronizedList(new LinkedList<BytestreamListener>());
+
+ /* listener that handles all incoming bytestream requests */
+ private final InitiationListener initiationListener;
+
+ /* timeout to wait for the response to the SOCKS5 Bytestream initialization request */
+ private int targetResponseTimeout = 10000;
+
+ /* timeout for connecting to the SOCKS5 proxy selected by the target */
+ private int proxyConnectionTimeout = 10000;
+
+ /* blacklist of errornous SOCKS5 proxies */
+ private final List<String> proxyBlacklist = Collections.synchronizedList(new LinkedList<String>());
+
+ /* remember the last proxy that worked to prioritize it */
+ private String lastWorkingProxy = null;
+
+ /* flag to enable/disable prioritization of last working proxy */
+ private boolean proxyPrioritizationEnabled = true;
+
+ /*
+ * list containing session IDs of SOCKS5 Bytestream initialization packets that should be
+ * ignored by the InitiationListener
+ */
+ private List<String> ignoredBytestreamRequests = Collections.synchronizedList(new LinkedList<String>());
+
+ /**
+ * Returns the Socks5BytestreamManager to handle SOCKS5 Bytestreams for a given
+ * {@link Connection}.
+ * <p>
+ * If no manager exists a new is created and initialized.
+ *
+ * @param connection the XMPP connection or <code>null</code> if given connection is
+ * <code>null</code>
+ * @return the Socks5BytestreamManager for the given XMPP connection
+ */
+ public static synchronized Socks5BytestreamManager getBytestreamManager(Connection connection) {
+ if (connection == null) {
+ return null;
+ }
+ Socks5BytestreamManager manager = managers.get(connection);
+ if (manager == null) {
+ manager = new Socks5BytestreamManager(connection);
+ managers.put(connection, manager);
+ manager.activate();
+ }
+ return manager;
+ }
+
+ /**
+ * Private constructor.
+ *
+ * @param connection the XMPP connection
+ */
+ private Socks5BytestreamManager(Connection connection) {
+ this.connection = connection;
+ this.initiationListener = new InitiationListener(this);
+ }
+
+ /**
+ * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request unless
+ * there is a user specific BytestreamListener registered.
+ * <p>
+ * If no listeners are registered all SOCKS5 Bytestream request are rejected with a
+ * &lt;not-acceptable/&gt; error.
+ * <p>
+ * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5
+ * bytestream requests sent in the context of <a
+ * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * @param listener the listener to register
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener) {
+ this.allRequestListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from the list of listeners for all incoming SOCKS5 Bytestream
+ * requests.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeIncomingBytestreamListener(BytestreamListener listener) {
+ this.allRequestListeners.remove(listener);
+ }
+
+ /**
+ * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request from the
+ * given user.
+ * <p>
+ * Use this method if you are awaiting an incoming SOCKS5 Bytestream request from a specific
+ * user.
+ * <p>
+ * If no listeners are registered all SOCKS5 Bytestream request are rejected with a
+ * &lt;not-acceptable/&gt; error.
+ * <p>
+ * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5
+ * bytestream requests sent in the context of <a
+ * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * @param listener the listener to register
+ * @param initiatorJID the JID of the user that wants to establish a SOCKS5 Bytestream
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) {
+ this.userListeners.put(initiatorJID, listener);
+ }
+
+ /**
+ * Removes the listener for the given user.
+ *
+ * @param initiatorJID the JID of the user the listener should be removed
+ */
+ public void removeIncomingBytestreamListener(String initiatorJID) {
+ this.userListeners.remove(initiatorJID);
+ }
+
+ /**
+ * Use this method to ignore the next incoming SOCKS5 Bytestream request containing the given
+ * session ID. No listeners will be notified for this request and and no error will be returned
+ * to the initiator.
+ * <p>
+ * This method should be used if you are awaiting a SOCKS5 Bytestream request as a reply to
+ * another packet (e.g. file transfer).
+ *
+ * @param sessionID to be ignored
+ */
+ public void ignoreBytestreamRequestOnce(String sessionID) {
+ this.ignoredBytestreamRequests.add(sessionID);
+ }
+
+ /**
+ * Disables the SOCKS5 Bytestream manager by removing the SOCKS5 Bytestream feature from the
+ * service discovery, disabling the listener for SOCKS5 Bytestream initiation requests and
+ * resetting its internal state.
+ * <p>
+ * To re-enable the SOCKS5 Bytestream feature invoke {@link #getBytestreamManager(Connection)}.
+ * Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature.
+ */
+ public synchronized void disableService() {
+
+ // remove initiation packet listener
+ this.connection.removePacketListener(this.initiationListener);
+
+ // shutdown threads
+ this.initiationListener.shutdown();
+
+ // clear listeners
+ this.allRequestListeners.clear();
+ this.userListeners.clear();
+
+ // reset internal state
+ this.lastWorkingProxy = null;
+ this.proxyBlacklist.clear();
+ this.ignoredBytestreamRequests.clear();
+
+ // remove manager from static managers map
+ managers.remove(this.connection);
+
+ // shutdown local SOCKS5 proxy if there are no more managers for other connections
+ if (managers.size() == 0) {
+ Socks5Proxy.getSocks5Proxy().stop();
+ }
+
+ // remove feature from service discovery
+ ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
+
+ // check if service discovery is not already disposed by connection shutdown
+ if (serviceDiscoveryManager != null) {
+ serviceDiscoveryManager.removeFeature(NAMESPACE);
+ }
+
+ }
+
+ /**
+ * Returns the timeout to wait for the response to the SOCKS5 Bytestream initialization request.
+ * Default is 10000ms.
+ *
+ * @return the timeout to wait for the response to the SOCKS5 Bytestream initialization request
+ */
+ public int getTargetResponseTimeout() {
+ if (this.targetResponseTimeout <= 0) {
+ this.targetResponseTimeout = 10000;
+ }
+ return targetResponseTimeout;
+ }
+
+ /**
+ * Sets the timeout to wait for the response to the SOCKS5 Bytestream initialization request.
+ * Default is 10000ms.
+ *
+ * @param targetResponseTimeout the timeout to set
+ */
+ public void setTargetResponseTimeout(int targetResponseTimeout) {
+ this.targetResponseTimeout = targetResponseTimeout;
+ }
+
+ /**
+ * Returns the timeout for connecting to the SOCKS5 proxy selected by the target. Default is
+ * 10000ms.
+ *
+ * @return the timeout for connecting to the SOCKS5 proxy selected by the target
+ */
+ public int getProxyConnectionTimeout() {
+ if (this.proxyConnectionTimeout <= 0) {
+ this.proxyConnectionTimeout = 10000;
+ }
+ return proxyConnectionTimeout;
+ }
+
+ /**
+ * Sets the timeout for connecting to the SOCKS5 proxy selected by the target. Default is
+ * 10000ms.
+ *
+ * @param proxyConnectionTimeout the timeout to set
+ */
+ public void setProxyConnectionTimeout(int proxyConnectionTimeout) {
+ this.proxyConnectionTimeout = proxyConnectionTimeout;
+ }
+
+ /**
+ * Returns if the prioritization of the last working SOCKS5 proxy on successive SOCKS5
+ * Bytestream connections is enabled. Default is <code>true</code>.
+ *
+ * @return <code>true</code> if prioritization is enabled, <code>false</code> otherwise
+ */
+ public boolean isProxyPrioritizationEnabled() {
+ return proxyPrioritizationEnabled;
+ }
+
+ /**
+ * Enable/disable the prioritization of the last working SOCKS5 proxy on successive SOCKS5
+ * Bytestream connections.
+ *
+ * @param proxyPrioritizationEnabled enable/disable the prioritization of the last working
+ * SOCKS5 proxy
+ */
+ public void setProxyPrioritizationEnabled(boolean proxyPrioritizationEnabled) {
+ this.proxyPrioritizationEnabled = proxyPrioritizationEnabled;
+ }
+
+ /**
+ * Establishes a SOCKS5 Bytestream with the given user and returns the Socket to send/receive
+ * data to/from the user.
+ * <p>
+ * Use this method to establish SOCKS5 Bytestreams to users accepting all incoming Socks5
+ * bytestream requests since this method doesn't provide a way to tell the user something about
+ * the data to be sent.
+ * <p>
+ * To establish a SOCKS5 Bytestream after negotiation the kind of data to be sent (e.g. file
+ * transfer) use {@link #establishSession(String, String)}.
+ *
+ * @param targetJID the JID of the user a SOCKS5 Bytestream should be established
+ * @return the Socket to send/receive data to/from the user
+ * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5
+ * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies
+ * @throws IOException if the bytestream could not be established
+ * @throws InterruptedException if the current thread was interrupted while waiting
+ */
+ public Socks5BytestreamSession establishSession(String targetJID) throws XMPPException,
+ IOException, InterruptedException {
+ String sessionID = getNextSessionID();
+ return establishSession(targetJID, sessionID);
+ }
+
+ /**
+ * Establishes a SOCKS5 Bytestream with the given user using the given session ID and returns
+ * the Socket to send/receive data to/from the user.
+ *
+ * @param targetJID the JID of the user a SOCKS5 Bytestream should be established
+ * @param sessionID the session ID for the SOCKS5 Bytestream request
+ * @return the Socket to send/receive data to/from the user
+ * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5
+ * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies
+ * @throws IOException if the bytestream could not be established
+ * @throws InterruptedException if the current thread was interrupted while waiting
+ */
+ public Socks5BytestreamSession establishSession(String targetJID, String sessionID)
+ throws XMPPException, IOException, InterruptedException {
+
+ XMPPException discoveryException = null;
+ // check if target supports SOCKS5 Bytestream
+ if (!supportsSocks5(targetJID)) {
+ throw new XMPPException(targetJID + " doesn't support SOCKS5 Bytestream");
+ }
+
+ List<String> proxies = new ArrayList<String>();
+ // determine SOCKS5 proxies from XMPP-server
+ try {
+ proxies.addAll(determineProxies());
+ } catch (XMPPException e) {
+ // don't abort here, just remember the exception thrown by determineProxies()
+ // determineStreamHostInfos() will at least add the local Socks5 proxy (if enabled)
+ discoveryException = e;
+ }
+
+ // determine address and port of each proxy
+ List<StreamHost> streamHosts = determineStreamHostInfos(proxies);
+
+ if (streamHosts.isEmpty()) {
+ throw discoveryException != null ? discoveryException : new XMPPException("no SOCKS5 proxies available");
+ }
+
+ // compute digest
+ String digest = Socks5Utils.createDigest(sessionID, this.connection.getUser(), targetJID);
+
+ // prioritize last working SOCKS5 proxy if exists
+ if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) {
+ StreamHost selectedStreamHost = null;
+ for (StreamHost streamHost : streamHosts) {
+ if (streamHost.getJID().equals(this.lastWorkingProxy)) {
+ selectedStreamHost = streamHost;
+ break;
+ }
+ }
+ if (selectedStreamHost != null) {
+ streamHosts.remove(selectedStreamHost);
+ streamHosts.add(0, selectedStreamHost);
+ }
+
+ }
+
+ Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
+ try {
+
+ // add transfer digest to local proxy to make transfer valid
+ socks5Proxy.addTransfer(digest);
+
+ // create initiation packet
+ Bytestream initiation = createBytestreamInitiation(sessionID, targetJID, streamHosts);
+
+ // send initiation packet
+ Packet response = SyncPacketSend.getReply(this.connection, initiation,
+ getTargetResponseTimeout());
+
+ // extract used stream host from response
+ StreamHostUsed streamHostUsed = ((Bytestream) response).getUsedHost();
+ StreamHost usedStreamHost = initiation.getStreamHost(streamHostUsed.getJID());
+
+ if (usedStreamHost == null) {
+ throw new XMPPException("Remote user responded with unknown host");
+ }
+
+ // build SOCKS5 client
+ Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest,
+ this.connection, sessionID, targetJID);
+
+ // establish connection to proxy
+ Socket socket = socks5Client.getSocket(getProxyConnectionTimeout());
+
+ // remember last working SOCKS5 proxy to prioritize it for next request
+ this.lastWorkingProxy = usedStreamHost.getJID();
+
+ // negotiation successful, return the output stream
+ return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals(
+ this.connection.getUser()));
+
+ }
+ catch (TimeoutException e) {
+ throw new IOException("Timeout while connecting to SOCKS5 proxy");
+ }
+ finally {
+
+ // remove transfer digest if output stream is returned or an exception
+ // occurred
+ socks5Proxy.removeTransfer(digest);
+
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if the given target JID supports feature SOCKS5 Bytestream.
+ *
+ * @param targetJID the target JID
+ * @return <code>true</code> if the given target JID supports feature SOCKS5 Bytestream
+ * otherwise <code>false</code>
+ * @throws XMPPException if there was an error querying target for supported features
+ */
+ private boolean supportsSocks5(String targetJID) throws XMPPException {
+ ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
+ DiscoverInfo discoverInfo = serviceDiscoveryManager.discoverInfo(targetJID);
+ return discoverInfo.containsFeature(NAMESPACE);
+ }
+
+ /**
+ * Returns a list of JIDs of SOCKS5 proxies by querying the XMPP server. The SOCKS5 proxies are
+ * in the same order as returned by the XMPP server.
+ *
+ * @return list of JIDs of SOCKS5 proxies
+ * @throws XMPPException if there was an error querying the XMPP server for SOCKS5 proxies
+ */
+ private List<String> determineProxies() throws XMPPException {
+ ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
+
+ List<String> proxies = new ArrayList<String>();
+
+ // get all items form XMPP server
+ DiscoverItems discoverItems = serviceDiscoveryManager.discoverItems(this.connection.getServiceName());
+ Iterator<Item> itemIterator = discoverItems.getItems();
+
+ // query all items if they are SOCKS5 proxies
+ while (itemIterator.hasNext()) {
+ Item item = itemIterator.next();
+
+ // skip blacklisted servers
+ if (this.proxyBlacklist.contains(item.getEntityID())) {
+ continue;
+ }
+
+ try {
+ DiscoverInfo proxyInfo;
+ proxyInfo = serviceDiscoveryManager.discoverInfo(item.getEntityID());
+ Iterator<Identity> identities = proxyInfo.getIdentities();
+
+ // item must have category "proxy" and type "bytestream"
+ while (identities.hasNext()) {
+ Identity identity = identities.next();
+
+ if ("proxy".equalsIgnoreCase(identity.getCategory())
+ && "bytestreams".equalsIgnoreCase(identity.getType())) {
+ proxies.add(item.getEntityID());
+ break;
+ }
+
+ /*
+ * server is not a SOCKS5 proxy, blacklist server to skip next time a Socks5
+ * bytestream should be established
+ */
+ this.proxyBlacklist.add(item.getEntityID());
+
+ }
+ }
+ catch (XMPPException e) {
+ // blacklist errornous server
+ this.proxyBlacklist.add(item.getEntityID());
+ }
+ }
+
+ return proxies;
+ }
+
+ /**
+ * Returns a list of stream hosts containing the IP address an the port for the given list of
+ * SOCKS5 proxy JIDs. The order of the returned list is the same as the given list of JIDs
+ * excluding all SOCKS5 proxies who's network settings could not be determined. If a local
+ * SOCKS5 proxy is running it will be the first item in the list returned.
+ *
+ * @param proxies a list of SOCKS5 proxy JIDs
+ * @return a list of stream hosts containing the IP address an the port
+ */
+ private List<StreamHost> determineStreamHostInfos(List<String> proxies) {
+ List<StreamHost> streamHosts = new ArrayList<StreamHost>();
+
+ // add local proxy on first position if exists
+ List<StreamHost> localProxies = getLocalStreamHost();
+ if (localProxies != null) {
+ streamHosts.addAll(localProxies);
+ }
+
+ // query SOCKS5 proxies for network settings
+ for (String proxy : proxies) {
+ Bytestream streamHostRequest = createStreamHostRequest(proxy);
+ try {
+ Bytestream response = (Bytestream) SyncPacketSend.getReply(this.connection,
+ streamHostRequest);
+ streamHosts.addAll(response.getStreamHosts());
+ }
+ catch (XMPPException e) {
+ // blacklist errornous proxies
+ this.proxyBlacklist.add(proxy);
+ }
+ }
+
+ return streamHosts;
+ }
+
+ /**
+ * Returns a IQ packet to query a SOCKS5 proxy its network settings.
+ *
+ * @param proxy the proxy to query
+ * @return IQ packet to query a SOCKS5 proxy its network settings
+ */
+ private Bytestream createStreamHostRequest(String proxy) {
+ Bytestream request = new Bytestream();
+ request.setType(IQ.Type.GET);
+ request.setTo(proxy);
+ return request;
+ }
+
+ /**
+ * Returns the stream host information of the local SOCKS5 proxy containing the IP address and
+ * the port or null if local SOCKS5 proxy is not running.
+ *
+ * @return the stream host information of the local SOCKS5 proxy or null if local SOCKS5 proxy
+ * is not running
+ */
+ private List<StreamHost> getLocalStreamHost() {
+
+ // get local proxy singleton
+ Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
+
+ if (socks5Server.isRunning()) {
+ List<String> addresses = socks5Server.getLocalAddresses();
+ int port = socks5Server.getPort();
+
+ if (addresses.size() >= 1) {
+ List<StreamHost> streamHosts = new ArrayList<StreamHost>();
+ for (String address : addresses) {
+ StreamHost streamHost = new StreamHost(this.connection.getUser(), address);
+ streamHost.setPort(port);
+ streamHosts.add(streamHost);
+ }
+ return streamHosts;
+ }
+
+ }
+
+ // server is not running or local address could not be determined
+ return null;
+ }
+
+ /**
+ * Returns a SOCKS5 Bytestream initialization request packet with the given session ID
+ * containing the given stream hosts for the given target JID.
+ *
+ * @param sessionID the session ID for the SOCKS5 Bytestream
+ * @param targetJID the target JID of SOCKS5 Bytestream request
+ * @param streamHosts a list of SOCKS5 proxies the target should connect to
+ * @return a SOCKS5 Bytestream initialization request packet
+ */
+ private Bytestream createBytestreamInitiation(String sessionID, String targetJID,
+ List<StreamHost> streamHosts) {
+ Bytestream initiation = new Bytestream(sessionID);
+
+ // add all stream hosts
+ for (StreamHost streamHost : streamHosts) {
+ initiation.addStreamHost(streamHost);
+ }
+
+ initiation.setType(IQ.Type.SET);
+ initiation.setTo(targetJID);
+
+ return initiation;
+ }
+
+ /**
+ * Responses to the given packet's sender with a XMPP error that a SOCKS5 Bytestream is not
+ * accepted.
+ *
+ * @param packet Packet that should be answered with a not-acceptable error
+ */
+ protected void replyRejectPacket(IQ packet) {
+ XMPPError xmppError = new XMPPError(XMPPError.Condition.no_acceptable);
+ IQ errorIQ = IQ.createErrorResponse(packet, xmppError);
+ this.connection.sendPacket(errorIQ);
+ }
+
+ /**
+ * Activates the Socks5BytestreamManager by registering the SOCKS5 Bytestream initialization
+ * listener and enabling the SOCKS5 Bytestream feature.
+ */
+ private void activate() {
+ // register bytestream initiation packet listener
+ this.connection.addPacketListener(this.initiationListener,
+ this.initiationListener.getFilter());
+
+ // enable SOCKS5 feature
+ enableService();
+ }
+
+ /**
+ * Adds the SOCKS5 Bytestream feature to the service discovery.
+ */
+ private void enableService() {
+ ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(this.connection);
+ if (!manager.includesFeature(NAMESPACE)) {
+ manager.addFeature(NAMESPACE);
+ }
+ }
+
+ /**
+ * Returns a new unique session ID.
+ *
+ * @return a new unique session ID
+ */
+ private String getNextSessionID() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(SESSION_ID_PREFIX);
+ buffer.append(Math.abs(randomGenerator.nextLong()));
+ return buffer.toString();
+ }
+
+ /**
+ * Returns the XMPP connection.
+ *
+ * @return the XMPP connection
+ */
+ protected Connection getConnection() {
+ return this.connection;
+ }
+
+ /**
+ * Returns the {@link BytestreamListener} that should be informed if a SOCKS5 Bytestream request
+ * from the given initiator JID is received.
+ *
+ * @param initiator the initiator's JID
+ * @return the listener
+ */
+ protected BytestreamListener getUserListener(String initiator) {
+ return this.userListeners.get(initiator);
+ }
+
+ /**
+ * Returns a list of {@link BytestreamListener} that are informed if there are no listeners for
+ * a specific initiator.
+ *
+ * @return list of listeners
+ */
+ protected List<BytestreamListener> getAllRequestListeners() {
+ return this.allRequestListeners;
+ }
+
+ /**
+ * Returns the list of session IDs that should be ignored by the InitialtionListener
+ *
+ * @return list of session IDs
+ */
+ protected List<String> getIgnoredBytestreamRequests() {
+ return ignoredBytestreamRequests;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamRequest.java
index 0b2fdeb6a..5d8f0021b 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamRequest.java
@@ -1,316 +1,316 @@
-/**
- * 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.bytestreams.socks5;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.concurrent.TimeoutException;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.util.Cache;
-import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
-
-/**
- * Socks5BytestreamRequest class handles incoming SOCKS5 Bytestream requests.
- *
- * @author Henning Staib
- */
-public class Socks5BytestreamRequest implements BytestreamRequest {
-
- /* lifetime of an Item in the blacklist */
- private static final long BLACKLIST_LIFETIME = 60 * 1000 * 120;
-
- /* size of the blacklist */
- private static final int BLACKLIST_MAX_SIZE = 100;
-
- /* blacklist of addresses of SOCKS5 proxies */
- private static final Cache<String, Integer> ADDRESS_BLACKLIST = new Cache<String, Integer>(
- BLACKLIST_MAX_SIZE, BLACKLIST_LIFETIME);
-
- /*
- * The number of connection failures it takes for a particular SOCKS5 proxy to be blacklisted.
- * When a proxy is blacklisted no more connection attempts will be made to it for a period of 2
- * hours.
- */
- private static int CONNECTION_FAILURE_THRESHOLD = 2;
-
- /* the bytestream initialization request */
- private Bytestream bytestreamRequest;
-
- /* SOCKS5 Bytestream manager containing the XMPP connection and helper methods */
- private Socks5BytestreamManager manager;
-
- /* timeout to connect to all SOCKS5 proxies */
- private int totalConnectTimeout = 10000;
-
- /* minimum timeout to connect to one SOCKS5 proxy */
- private int minimumConnectTimeout = 2000;
-
- /**
- * Returns the number of connection failures it takes for a particular SOCKS5 proxy to be
- * blacklisted. When a proxy is blacklisted no more connection attempts will be made to it for a
- * period of 2 hours. Default is 2.
- *
- * @return the number of connection failures it takes for a particular SOCKS5 proxy to be
- * blacklisted
- */
- public static int getConnectFailureThreshold() {
- return CONNECTION_FAILURE_THRESHOLD;
- }
-
- /**
- * Sets the number of connection failures it takes for a particular SOCKS5 proxy to be
- * blacklisted. When a proxy is blacklisted no more connection attempts will be made to it for a
- * period of 2 hours. Default is 2.
- * <p>
- * Setting the connection failure threshold to zero disables the blacklisting.
- *
- * @param connectFailureThreshold the number of connection failures it takes for a particular
- * SOCKS5 proxy to be blacklisted
- */
- public static void setConnectFailureThreshold(int connectFailureThreshold) {
- CONNECTION_FAILURE_THRESHOLD = connectFailureThreshold;
- }
-
- /**
- * Creates a new Socks5BytestreamRequest.
- *
- * @param manager the SOCKS5 Bytestream manager
- * @param bytestreamRequest the SOCKS5 Bytestream initialization packet
- */
- protected Socks5BytestreamRequest(Socks5BytestreamManager manager, Bytestream bytestreamRequest) {
- this.manager = manager;
- this.bytestreamRequest = bytestreamRequest;
- }
-
- /**
- * Returns the maximum timeout to connect to SOCKS5 proxies. Default is 10000ms.
- * <p>
- * When accepting a SOCKS5 Bytestream request Smack tries to connect to all SOCKS5 proxies given
- * by the initiator until a connection is established. This timeout divided by the number of
- * SOCKS5 proxies determines the timeout for every connection attempt.
- * <p>
- * You can set the minimum timeout for establishing a connection to one SOCKS5 proxy by invoking
- * {@link #setMinimumConnectTimeout(int)}.
- *
- * @return the maximum timeout to connect to SOCKS5 proxies
- */
- public int getTotalConnectTimeout() {
- if (this.totalConnectTimeout <= 0) {
- return 10000;
- }
- return this.totalConnectTimeout;
- }
-
- /**
- * Sets the maximum timeout to connect to SOCKS5 proxies. Default is 10000ms.
- * <p>
- * When accepting a SOCKS5 Bytestream request Smack tries to connect to all SOCKS5 proxies given
- * by the initiator until a connection is established. This timeout divided by the number of
- * SOCKS5 proxies determines the timeout for every connection attempt.
- * <p>
- * You can set the minimum timeout for establishing a connection to one SOCKS5 proxy by invoking
- * {@link #setMinimumConnectTimeout(int)}.
- *
- * @param totalConnectTimeout the maximum timeout to connect to SOCKS5 proxies
- */
- public void setTotalConnectTimeout(int totalConnectTimeout) {
- this.totalConnectTimeout = totalConnectTimeout;
- }
-
- /**
- * Returns the timeout to connect to one SOCKS5 proxy while accepting the SOCKS5 Bytestream
- * request. Default is 2000ms.
- *
- * @return the timeout to connect to one SOCKS5 proxy
- */
- public int getMinimumConnectTimeout() {
- if (this.minimumConnectTimeout <= 0) {
- return 2000;
- }
- return this.minimumConnectTimeout;
- }
-
- /**
- * Sets the timeout to connect to one SOCKS5 proxy while accepting the SOCKS5 Bytestream
- * request. Default is 2000ms.
- *
- * @param minimumConnectTimeout the timeout to connect to one SOCKS5 proxy
- */
- public void setMinimumConnectTimeout(int minimumConnectTimeout) {
- this.minimumConnectTimeout = minimumConnectTimeout;
- }
-
- /**
- * Returns the sender of the SOCKS5 Bytestream initialization request.
- *
- * @return the sender of the SOCKS5 Bytestream initialization request.
- */
- public String getFrom() {
- return this.bytestreamRequest.getFrom();
- }
-
- /**
- * Returns the session ID of the SOCKS5 Bytestream initialization request.
- *
- * @return the session ID of the SOCKS5 Bytestream initialization request.
- */
- public String getSessionID() {
- return this.bytestreamRequest.getSessionID();
- }
-
- /**
- * Accepts the SOCKS5 Bytestream initialization request and returns the socket to send/receive
- * data.
- * <p>
- * Before accepting the SOCKS5 Bytestream request you can set timeouts by invoking
- * {@link #setTotalConnectTimeout(int)} and {@link #setMinimumConnectTimeout(int)}.
- *
- * @return the socket to send/receive data
- * @throws XMPPException if connection to all SOCKS5 proxies failed or if stream is invalid.
- * @throws InterruptedException if the current thread was interrupted while waiting
- */
- public Socks5BytestreamSession accept() throws XMPPException, InterruptedException {
- Collection<StreamHost> streamHosts = this.bytestreamRequest.getStreamHosts();
-
- // throw exceptions if request contains no stream hosts
- if (streamHosts.size() == 0) {
- cancelRequest();
- }
-
- StreamHost selectedHost = null;
- Socket socket = null;
-
- String digest = Socks5Utils.createDigest(this.bytestreamRequest.getSessionID(),
- this.bytestreamRequest.getFrom(), this.manager.getConnection().getUser());
-
- /*
- * determine timeout for each connection attempt; each SOCKS5 proxy has the same amount of
- * time so that the first does not consume the whole timeout
- */
- int timeout = Math.max(getTotalConnectTimeout() / streamHosts.size(),
- getMinimumConnectTimeout());
-
- for (StreamHost streamHost : streamHosts) {
- String address = streamHost.getAddress() + ":" + streamHost.getPort();
-
- // check to see if this address has been blacklisted
- int failures = getConnectionFailures(address);
- if (CONNECTION_FAILURE_THRESHOLD > 0 && failures >= CONNECTION_FAILURE_THRESHOLD) {
- continue;
- }
-
- // establish socket
- try {
-
- // build SOCKS5 client
- final Socks5Client socks5Client = new Socks5Client(streamHost, digest);
-
- // connect to SOCKS5 proxy with a timeout
- socket = socks5Client.getSocket(timeout);
-
- // set selected host
- selectedHost = streamHost;
- break;
-
- }
- catch (TimeoutException e) {
- incrementConnectionFailures(address);
- }
- catch (IOException e) {
- incrementConnectionFailures(address);
- }
- catch (XMPPException e) {
- incrementConnectionFailures(address);
- }
-
- }
-
- // throw exception if connecting to all SOCKS5 proxies failed
- if (selectedHost == null || socket == null) {
- cancelRequest();
- }
-
- // send used-host confirmation
- Bytestream response = createUsedHostResponse(selectedHost);
- this.manager.getConnection().sendPacket(response);
-
- return new Socks5BytestreamSession(socket, selectedHost.getJID().equals(
- this.bytestreamRequest.getFrom()));
-
- }
-
- /**
- * Rejects the SOCKS5 Bytestream request by sending a reject error to the initiator.
- */
- public void reject() {
- this.manager.replyRejectPacket(this.bytestreamRequest);
- }
-
- /**
- * Cancels the SOCKS5 Bytestream request by sending an error to the initiator and building a
- * XMPP exception.
- *
- * @throws XMPPException XMPP exception containing the XMPP error
- */
- private void cancelRequest() throws XMPPException {
- String errorMessage = "Could not establish socket with any provided host";
- XMPPError error = new XMPPError(XMPPError.Condition.item_not_found, errorMessage);
- IQ errorIQ = IQ.createErrorResponse(this.bytestreamRequest, error);
- this.manager.getConnection().sendPacket(errorIQ);
- throw new XMPPException(errorMessage, error);
- }
-
- /**
- * Returns the response to the SOCKS5 Bytestream request containing the SOCKS5 proxy used.
- *
- * @param selectedHost the used SOCKS5 proxy
- * @return the response to the SOCKS5 Bytestream request
- */
- private Bytestream createUsedHostResponse(StreamHost selectedHost) {
- Bytestream response = new Bytestream(this.bytestreamRequest.getSessionID());
- response.setTo(this.bytestreamRequest.getFrom());
- response.setType(IQ.Type.RESULT);
- response.setPacketID(this.bytestreamRequest.getPacketID());
- response.setUsedHost(selectedHost.getJID());
- return response;
- }
-
- /**
- * Increments the connection failure counter by one for the given address.
- *
- * @param address the address the connection failure counter should be increased
- */
- private void incrementConnectionFailures(String address) {
- Integer count = ADDRESS_BLACKLIST.get(address);
- ADDRESS_BLACKLIST.put(address, count == null ? 1 : count + 1);
- }
-
- /**
- * Returns how often the connection to the given address failed.
- *
- * @param address the address
- * @return number of connection failures
- */
- private int getConnectionFailures(String address) {
- Integer count = ADDRESS_BLACKLIST.get(address);
- return count != null ? count : 0;
- }
-
-}
+/**
+ * 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.bytestreams.socks5;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.concurrent.TimeoutException;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.util.Cache;
+import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
+
+/**
+ * Socks5BytestreamRequest class handles incoming SOCKS5 Bytestream requests.
+ *
+ * @author Henning Staib
+ */
+public class Socks5BytestreamRequest implements BytestreamRequest {
+
+ /* lifetime of an Item in the blacklist */
+ private static final long BLACKLIST_LIFETIME = 60 * 1000 * 120;
+
+ /* size of the blacklist */
+ private static final int BLACKLIST_MAX_SIZE = 100;
+
+ /* blacklist of addresses of SOCKS5 proxies */
+ private static final Cache<String, Integer> ADDRESS_BLACKLIST = new Cache<String, Integer>(
+ BLACKLIST_MAX_SIZE, BLACKLIST_LIFETIME);
+
+ /*
+ * The number of connection failures it takes for a particular SOCKS5 proxy to be blacklisted.
+ * When a proxy is blacklisted no more connection attempts will be made to it for a period of 2
+ * hours.
+ */
+ private static int CONNECTION_FAILURE_THRESHOLD = 2;
+
+ /* the bytestream initialization request */
+ private Bytestream bytestreamRequest;
+
+ /* SOCKS5 Bytestream manager containing the XMPP connection and helper methods */
+ private Socks5BytestreamManager manager;
+
+ /* timeout to connect to all SOCKS5 proxies */
+ private int totalConnectTimeout = 10000;
+
+ /* minimum timeout to connect to one SOCKS5 proxy */
+ private int minimumConnectTimeout = 2000;
+
+ /**
+ * Returns the number of connection failures it takes for a particular SOCKS5 proxy to be
+ * blacklisted. When a proxy is blacklisted no more connection attempts will be made to it for a
+ * period of 2 hours. Default is 2.
+ *
+ * @return the number of connection failures it takes for a particular SOCKS5 proxy to be
+ * blacklisted
+ */
+ public static int getConnectFailureThreshold() {
+ return CONNECTION_FAILURE_THRESHOLD;
+ }
+
+ /**
+ * Sets the number of connection failures it takes for a particular SOCKS5 proxy to be
+ * blacklisted. When a proxy is blacklisted no more connection attempts will be made to it for a
+ * period of 2 hours. Default is 2.
+ * <p>
+ * Setting the connection failure threshold to zero disables the blacklisting.
+ *
+ * @param connectFailureThreshold the number of connection failures it takes for a particular
+ * SOCKS5 proxy to be blacklisted
+ */
+ public static void setConnectFailureThreshold(int connectFailureThreshold) {
+ CONNECTION_FAILURE_THRESHOLD = connectFailureThreshold;
+ }
+
+ /**
+ * Creates a new Socks5BytestreamRequest.
+ *
+ * @param manager the SOCKS5 Bytestream manager
+ * @param bytestreamRequest the SOCKS5 Bytestream initialization packet
+ */
+ protected Socks5BytestreamRequest(Socks5BytestreamManager manager, Bytestream bytestreamRequest) {
+ this.manager = manager;
+ this.bytestreamRequest = bytestreamRequest;
+ }
+
+ /**
+ * Returns the maximum timeout to connect to SOCKS5 proxies. Default is 10000ms.
+ * <p>
+ * When accepting a SOCKS5 Bytestream request Smack tries to connect to all SOCKS5 proxies given
+ * by the initiator until a connection is established. This timeout divided by the number of
+ * SOCKS5 proxies determines the timeout for every connection attempt.
+ * <p>
+ * You can set the minimum timeout for establishing a connection to one SOCKS5 proxy by invoking
+ * {@link #setMinimumConnectTimeout(int)}.
+ *
+ * @return the maximum timeout to connect to SOCKS5 proxies
+ */
+ public int getTotalConnectTimeout() {
+ if (this.totalConnectTimeout <= 0) {
+ return 10000;
+ }
+ return this.totalConnectTimeout;
+ }
+
+ /**
+ * Sets the maximum timeout to connect to SOCKS5 proxies. Default is 10000ms.
+ * <p>
+ * When accepting a SOCKS5 Bytestream request Smack tries to connect to all SOCKS5 proxies given
+ * by the initiator until a connection is established. This timeout divided by the number of
+ * SOCKS5 proxies determines the timeout for every connection attempt.
+ * <p>
+ * You can set the minimum timeout for establishing a connection to one SOCKS5 proxy by invoking
+ * {@link #setMinimumConnectTimeout(int)}.
+ *
+ * @param totalConnectTimeout the maximum timeout to connect to SOCKS5 proxies
+ */
+ public void setTotalConnectTimeout(int totalConnectTimeout) {
+ this.totalConnectTimeout = totalConnectTimeout;
+ }
+
+ /**
+ * Returns the timeout to connect to one SOCKS5 proxy while accepting the SOCKS5 Bytestream
+ * request. Default is 2000ms.
+ *
+ * @return the timeout to connect to one SOCKS5 proxy
+ */
+ public int getMinimumConnectTimeout() {
+ if (this.minimumConnectTimeout <= 0) {
+ return 2000;
+ }
+ return this.minimumConnectTimeout;
+ }
+
+ /**
+ * Sets the timeout to connect to one SOCKS5 proxy while accepting the SOCKS5 Bytestream
+ * request. Default is 2000ms.
+ *
+ * @param minimumConnectTimeout the timeout to connect to one SOCKS5 proxy
+ */
+ public void setMinimumConnectTimeout(int minimumConnectTimeout) {
+ this.minimumConnectTimeout = minimumConnectTimeout;
+ }
+
+ /**
+ * Returns the sender of the SOCKS5 Bytestream initialization request.
+ *
+ * @return the sender of the SOCKS5 Bytestream initialization request.
+ */
+ public String getFrom() {
+ return this.bytestreamRequest.getFrom();
+ }
+
+ /**
+ * Returns the session ID of the SOCKS5 Bytestream initialization request.
+ *
+ * @return the session ID of the SOCKS5 Bytestream initialization request.
+ */
+ public String getSessionID() {
+ return this.bytestreamRequest.getSessionID();
+ }
+
+ /**
+ * Accepts the SOCKS5 Bytestream initialization request and returns the socket to send/receive
+ * data.
+ * <p>
+ * Before accepting the SOCKS5 Bytestream request you can set timeouts by invoking
+ * {@link #setTotalConnectTimeout(int)} and {@link #setMinimumConnectTimeout(int)}.
+ *
+ * @return the socket to send/receive data
+ * @throws XMPPException if connection to all SOCKS5 proxies failed or if stream is invalid.
+ * @throws InterruptedException if the current thread was interrupted while waiting
+ */
+ public Socks5BytestreamSession accept() throws XMPPException, InterruptedException {
+ Collection<StreamHost> streamHosts = this.bytestreamRequest.getStreamHosts();
+
+ // throw exceptions if request contains no stream hosts
+ if (streamHosts.size() == 0) {
+ cancelRequest();
+ }
+
+ StreamHost selectedHost = null;
+ Socket socket = null;
+
+ String digest = Socks5Utils.createDigest(this.bytestreamRequest.getSessionID(),
+ this.bytestreamRequest.getFrom(), this.manager.getConnection().getUser());
+
+ /*
+ * determine timeout for each connection attempt; each SOCKS5 proxy has the same amount of
+ * time so that the first does not consume the whole timeout
+ */
+ int timeout = Math.max(getTotalConnectTimeout() / streamHosts.size(),
+ getMinimumConnectTimeout());
+
+ for (StreamHost streamHost : streamHosts) {
+ String address = streamHost.getAddress() + ":" + streamHost.getPort();
+
+ // check to see if this address has been blacklisted
+ int failures = getConnectionFailures(address);
+ if (CONNECTION_FAILURE_THRESHOLD > 0 && failures >= CONNECTION_FAILURE_THRESHOLD) {
+ continue;
+ }
+
+ // establish socket
+ try {
+
+ // build SOCKS5 client
+ final Socks5Client socks5Client = new Socks5Client(streamHost, digest);
+
+ // connect to SOCKS5 proxy with a timeout
+ socket = socks5Client.getSocket(timeout);
+
+ // set selected host
+ selectedHost = streamHost;
+ break;
+
+ }
+ catch (TimeoutException e) {
+ incrementConnectionFailures(address);
+ }
+ catch (IOException e) {
+ incrementConnectionFailures(address);
+ }
+ catch (XMPPException e) {
+ incrementConnectionFailures(address);
+ }
+
+ }
+
+ // throw exception if connecting to all SOCKS5 proxies failed
+ if (selectedHost == null || socket == null) {
+ cancelRequest();
+ }
+
+ // send used-host confirmation
+ Bytestream response = createUsedHostResponse(selectedHost);
+ this.manager.getConnection().sendPacket(response);
+
+ return new Socks5BytestreamSession(socket, selectedHost.getJID().equals(
+ this.bytestreamRequest.getFrom()));
+
+ }
+
+ /**
+ * Rejects the SOCKS5 Bytestream request by sending a reject error to the initiator.
+ */
+ public void reject() {
+ this.manager.replyRejectPacket(this.bytestreamRequest);
+ }
+
+ /**
+ * Cancels the SOCKS5 Bytestream request by sending an error to the initiator and building a
+ * XMPP exception.
+ *
+ * @throws XMPPException XMPP exception containing the XMPP error
+ */
+ private void cancelRequest() throws XMPPException {
+ String errorMessage = "Could not establish socket with any provided host";
+ XMPPError error = new XMPPError(XMPPError.Condition.item_not_found, errorMessage);
+ IQ errorIQ = IQ.createErrorResponse(this.bytestreamRequest, error);
+ this.manager.getConnection().sendPacket(errorIQ);
+ throw new XMPPException(errorMessage, error);
+ }
+
+ /**
+ * Returns the response to the SOCKS5 Bytestream request containing the SOCKS5 proxy used.
+ *
+ * @param selectedHost the used SOCKS5 proxy
+ * @return the response to the SOCKS5 Bytestream request
+ */
+ private Bytestream createUsedHostResponse(StreamHost selectedHost) {
+ Bytestream response = new Bytestream(this.bytestreamRequest.getSessionID());
+ response.setTo(this.bytestreamRequest.getFrom());
+ response.setType(IQ.Type.RESULT);
+ response.setPacketID(this.bytestreamRequest.getPacketID());
+ response.setUsedHost(selectedHost.getJID());
+ return response;
+ }
+
+ /**
+ * Increments the connection failure counter by one for the given address.
+ *
+ * @param address the address the connection failure counter should be increased
+ */
+ private void incrementConnectionFailures(String address) {
+ Integer count = ADDRESS_BLACKLIST.get(address);
+ ADDRESS_BLACKLIST.put(address, count == null ? 1 : count + 1);
+ }
+
+ /**
+ * Returns how often the connection to the given address failed.
+ *
+ * @param address the address
+ * @return number of connection failures
+ */
+ private int getConnectionFailures(String address) {
+ Integer count = ADDRESS_BLACKLIST.get(address);
+ return count != null ? count : 0;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamSession.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamSession.java
index 41ab142db..267dafc62 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamSession.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamSession.java
@@ -15,84 +15,84 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smackx.bytestreams.socks5;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-import java.net.SocketException;
-
-import org.jivesoftware.smackx.bytestreams.BytestreamSession;
-
-/**
- * Socks5BytestreamSession class represents a SOCKS5 Bytestream session.
- *
- * @author Henning Staib
- */
-public class Socks5BytestreamSession implements BytestreamSession {
-
- /* the underlying socket of the SOCKS5 Bytestream */
- private final Socket socket;
-
- /* flag to indicate if this session is a direct or mediated connection */
- private final boolean isDirect;
-
- protected Socks5BytestreamSession(Socket socket, boolean isDirect) {
- this.socket = socket;
- this.isDirect = isDirect;
- }
-
- /**
- * Returns <code>true</code> if the session is established through a direct connection between
- * the initiator and target, <code>false</code> if the session is mediated over a SOCKS proxy.
- *
- * @return <code>true</code> if session is a direct connection, <code>false</code> if session is
- * mediated over a SOCKS5 proxy
- */
- public boolean isDirect() {
- return this.isDirect;
- }
-
- /**
- * Returns <code>true</code> if the session is mediated over a SOCKS proxy, <code>false</code>
- * if this session is established through a direct connection between the initiator and target.
- *
- * @return <code>true</code> if session is mediated over a SOCKS5 proxy, <code>false</code> if
- * session is a direct connection
- */
- public boolean isMediated() {
- return !this.isDirect;
- }
-
- public InputStream getInputStream() throws IOException {
- return this.socket.getInputStream();
- }
-
- public OutputStream getOutputStream() throws IOException {
- return this.socket.getOutputStream();
- }
-
- public int getReadTimeout() throws IOException {
- try {
- return this.socket.getSoTimeout();
- }
- catch (SocketException e) {
- throw new IOException("Error on underlying Socket");
- }
- }
-
- public void setReadTimeout(int timeout) throws IOException {
- try {
- this.socket.setSoTimeout(timeout);
- }
- catch (SocketException e) {
- throw new IOException("Error on underlying Socket");
- }
- }
-
- public void close() throws IOException {
- this.socket.close();
- }
-
-}
+package org.jivesoftware.smackx.bytestreams.socks5;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.jivesoftware.smackx.bytestreams.BytestreamSession;
+
+/**
+ * Socks5BytestreamSession class represents a SOCKS5 Bytestream session.
+ *
+ * @author Henning Staib
+ */
+public class Socks5BytestreamSession implements BytestreamSession {
+
+ /* the underlying socket of the SOCKS5 Bytestream */
+ private final Socket socket;
+
+ /* flag to indicate if this session is a direct or mediated connection */
+ private final boolean isDirect;
+
+ protected Socks5BytestreamSession(Socket socket, boolean isDirect) {
+ this.socket = socket;
+ this.isDirect = isDirect;
+ }
+
+ /**
+ * Returns <code>true</code> if the session is established through a direct connection between
+ * the initiator and target, <code>false</code> if the session is mediated over a SOCKS proxy.
+ *
+ * @return <code>true</code> if session is a direct connection, <code>false</code> if session is
+ * mediated over a SOCKS5 proxy
+ */
+ public boolean isDirect() {
+ return this.isDirect;
+ }
+
+ /**
+ * Returns <code>true</code> if the session is mediated over a SOCKS proxy, <code>false</code>
+ * if this session is established through a direct connection between the initiator and target.
+ *
+ * @return <code>true</code> if session is mediated over a SOCKS5 proxy, <code>false</code> if
+ * session is a direct connection
+ */
+ public boolean isMediated() {
+ return !this.isDirect;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return this.socket.getInputStream();
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return this.socket.getOutputStream();
+ }
+
+ public int getReadTimeout() throws IOException {
+ try {
+ return this.socket.getSoTimeout();
+ }
+ catch (SocketException e) {
+ throw new IOException("Error on underlying Socket");
+ }
+ }
+
+ public void setReadTimeout(int timeout) throws IOException {
+ try {
+ this.socket.setSoTimeout(timeout);
+ }
+ catch (SocketException e) {
+ throw new IOException("Error on underlying Socket");
+ }
+ }
+
+ public void close() throws IOException {
+ this.socket.close();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java
index 664ea596d..62c925a4e 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java
@@ -1,204 +1,204 @@
-/**
- * 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.bytestreams.socks5;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.util.Arrays;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
-
-/**
- * The SOCKS5 client class handles establishing a connection to a SOCKS5 proxy. Connecting to a
- * SOCKS5 proxy requires authentication. This implementation only supports the no-authentication
- * authentication method.
- *
- * @author Henning Staib
- */
-class Socks5Client {
-
- /* stream host containing network settings and name of the SOCKS5 proxy */
- protected StreamHost streamHost;
-
- /* SHA-1 digest identifying the SOCKS5 stream */
- protected String digest;
-
- /**
- * Constructor for a SOCKS5 client.
- *
- * @param streamHost containing network settings of the SOCKS5 proxy
- * @param digest identifying the SOCKS5 Bytestream
- */
- public Socks5Client(StreamHost streamHost, String digest) {
- this.streamHost = streamHost;
- this.digest = digest;
- }
-
- /**
- * Returns the initialized socket that can be used to transfer data between peers via the SOCKS5
- * proxy.
- *
- * @param timeout timeout to connect to SOCKS5 proxy in milliseconds
- * @return socket the initialized socket
- * @throws IOException if initializing the socket failed due to a network error
- * @throws XMPPException if establishing connection to SOCKS5 proxy failed
- * @throws TimeoutException if connecting to SOCKS5 proxy timed out
- * @throws InterruptedException if the current thread was interrupted while waiting
- */
- public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
- TimeoutException {
-
- // wrap connecting in future for timeout
- FutureTask<Socket> futureTask = new FutureTask<Socket>(new Callable<Socket>() {
-
- public Socket call() throws Exception {
-
- // initialize socket
- Socket socket = new Socket();
- SocketAddress socketAddress = new InetSocketAddress(streamHost.getAddress(),
- streamHost.getPort());
- socket.connect(socketAddress);
-
- // initialize connection to SOCKS5 proxy
- if (!establish(socket)) {
-
- // initialization failed, close socket
- socket.close();
- throw new XMPPException("establishing connection to SOCKS5 proxy failed");
-
- }
-
- return socket;
- }
-
- });
- Thread executor = new Thread(futureTask);
- executor.start();
-
- // get connection to initiator with timeout
- try {
- return futureTask.get(timeout, TimeUnit.MILLISECONDS);
- }
- catch (ExecutionException e) {
- Throwable cause = e.getCause();
- if (cause != null) {
- // case exceptions to comply with method signature
- if (cause instanceof IOException) {
- throw (IOException) cause;
- }
- if (cause instanceof XMPPException) {
- throw (XMPPException) cause;
- }
- }
-
- // throw generic IO exception if unexpected exception was thrown
- throw new IOException("Error while connection to SOCKS5 proxy");
- }
-
- }
-
- /**
- * Initializes the connection to the SOCKS5 proxy by negotiating authentication method and
- * requesting a stream for the given digest. Currently only the no-authentication method is
- * supported by the Socks5Client.
- * <p>
- * Returns <code>true</code> if a stream could be established, otherwise <code>false</code>. If
- * <code>false</code> is returned the given Socket should be closed.
- *
- * @param socket connected to a SOCKS5 proxy
- * @return <code>true</code> if if a stream could be established, otherwise <code>false</code>.
- * If <code>false</code> is returned the given Socket should be closed.
- * @throws IOException if a network error occurred
- */
- protected boolean establish(Socket socket) throws IOException {
-
- /*
- * use DataInputStream/DataOutpuStream to assure read and write is completed in a single
- * statement
- */
- DataInputStream in = new DataInputStream(socket.getInputStream());
- DataOutputStream out = new DataOutputStream(socket.getOutputStream());
-
- // authentication negotiation
- byte[] cmd = new byte[3];
-
- cmd[0] = (byte) 0x05; // protocol version 5
- cmd[1] = (byte) 0x01; // number of authentication methods supported
- cmd[2] = (byte) 0x00; // authentication method: no-authentication required
-
- out.write(cmd);
- out.flush();
-
- byte[] response = new byte[2];
- in.readFully(response);
-
- // check if server responded with correct version and no-authentication method
- if (response[0] != (byte) 0x05 || response[1] != (byte) 0x00) {
- return false;
- }
-
- // request SOCKS5 connection with given address/digest
- byte[] connectionRequest = createSocks5ConnectRequest();
- out.write(connectionRequest);
- out.flush();
-
- // receive response
- byte[] connectionResponse;
- try {
- connectionResponse = Socks5Utils.receiveSocks5Message(in);
- }
- catch (XMPPException e) {
- return false; // server answered in an unsupported way
- }
-
- // verify response
- connectionRequest[1] = (byte) 0x00; // set expected return status to 0
- return Arrays.equals(connectionRequest, connectionResponse);
- }
-
- /**
- * Returns a SOCKS5 connection request message. It contains the command "connect", the address
- * type "domain" and the digest as address.
- * <p>
- * (see <a href="http://tools.ietf.org/html/rfc1928">RFC1928</a>)
- *
- * @return SOCKS5 connection request message
- */
- private byte[] createSocks5ConnectRequest() {
- byte addr[] = this.digest.getBytes();
-
- byte[] data = new byte[7 + addr.length];
- data[0] = (byte) 0x05; // version (SOCKS5)
- data[1] = (byte) 0x01; // command (1 - connect)
- data[2] = (byte) 0x00; // reserved byte (always 0)
- data[3] = (byte) 0x03; // address type (3 - domain name)
- data[4] = (byte) addr.length; // address length
- System.arraycopy(addr, 0, data, 5, addr.length); // address
- data[data.length - 2] = (byte) 0; // address port (2 bytes always 0)
- data[data.length - 1] = (byte) 0;
-
- return data;
- }
-
-}
+/**
+ * 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.bytestreams.socks5;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
+
+/**
+ * The SOCKS5 client class handles establishing a connection to a SOCKS5 proxy. Connecting to a
+ * SOCKS5 proxy requires authentication. This implementation only supports the no-authentication
+ * authentication method.
+ *
+ * @author Henning Staib
+ */
+class Socks5Client {
+
+ /* stream host containing network settings and name of the SOCKS5 proxy */
+ protected StreamHost streamHost;
+
+ /* SHA-1 digest identifying the SOCKS5 stream */
+ protected String digest;
+
+ /**
+ * Constructor for a SOCKS5 client.
+ *
+ * @param streamHost containing network settings of the SOCKS5 proxy
+ * @param digest identifying the SOCKS5 Bytestream
+ */
+ public Socks5Client(StreamHost streamHost, String digest) {
+ this.streamHost = streamHost;
+ this.digest = digest;
+ }
+
+ /**
+ * Returns the initialized socket that can be used to transfer data between peers via the SOCKS5
+ * proxy.
+ *
+ * @param timeout timeout to connect to SOCKS5 proxy in milliseconds
+ * @return socket the initialized socket
+ * @throws IOException if initializing the socket failed due to a network error
+ * @throws XMPPException if establishing connection to SOCKS5 proxy failed
+ * @throws TimeoutException if connecting to SOCKS5 proxy timed out
+ * @throws InterruptedException if the current thread was interrupted while waiting
+ */
+ public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
+ TimeoutException {
+
+ // wrap connecting in future for timeout
+ FutureTask<Socket> futureTask = new FutureTask<Socket>(new Callable<Socket>() {
+
+ public Socket call() throws Exception {
+
+ // initialize socket
+ Socket socket = new Socket();
+ SocketAddress socketAddress = new InetSocketAddress(streamHost.getAddress(),
+ streamHost.getPort());
+ socket.connect(socketAddress);
+
+ // initialize connection to SOCKS5 proxy
+ if (!establish(socket)) {
+
+ // initialization failed, close socket
+ socket.close();
+ throw new XMPPException("establishing connection to SOCKS5 proxy failed");
+
+ }
+
+ return socket;
+ }
+
+ });
+ Thread executor = new Thread(futureTask);
+ executor.start();
+
+ // get connection to initiator with timeout
+ try {
+ return futureTask.get(timeout, TimeUnit.MILLISECONDS);
+ }
+ catch (ExecutionException e) {
+ Throwable cause = e.getCause();
+ if (cause != null) {
+ // case exceptions to comply with method signature
+ if (cause instanceof IOException) {
+ throw (IOException) cause;
+ }
+ if (cause instanceof XMPPException) {
+ throw (XMPPException) cause;
+ }
+ }
+
+ // throw generic IO exception if unexpected exception was thrown
+ throw new IOException("Error while connection to SOCKS5 proxy");
+ }
+
+ }
+
+ /**
+ * Initializes the connection to the SOCKS5 proxy by negotiating authentication method and
+ * requesting a stream for the given digest. Currently only the no-authentication method is
+ * supported by the Socks5Client.
+ * <p>
+ * Returns <code>true</code> if a stream could be established, otherwise <code>false</code>. If
+ * <code>false</code> is returned the given Socket should be closed.
+ *
+ * @param socket connected to a SOCKS5 proxy
+ * @return <code>true</code> if if a stream could be established, otherwise <code>false</code>.
+ * If <code>false</code> is returned the given Socket should be closed.
+ * @throws IOException if a network error occurred
+ */
+ protected boolean establish(Socket socket) throws IOException {
+
+ /*
+ * use DataInputStream/DataOutpuStream to assure read and write is completed in a single
+ * statement
+ */
+ DataInputStream in = new DataInputStream(socket.getInputStream());
+ DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+
+ // authentication negotiation
+ byte[] cmd = new byte[3];
+
+ cmd[0] = (byte) 0x05; // protocol version 5
+ cmd[1] = (byte) 0x01; // number of authentication methods supported
+ cmd[2] = (byte) 0x00; // authentication method: no-authentication required
+
+ out.write(cmd);
+ out.flush();
+
+ byte[] response = new byte[2];
+ in.readFully(response);
+
+ // check if server responded with correct version and no-authentication method
+ if (response[0] != (byte) 0x05 || response[1] != (byte) 0x00) {
+ return false;
+ }
+
+ // request SOCKS5 connection with given address/digest
+ byte[] connectionRequest = createSocks5ConnectRequest();
+ out.write(connectionRequest);
+ out.flush();
+
+ // receive response
+ byte[] connectionResponse;
+ try {
+ connectionResponse = Socks5Utils.receiveSocks5Message(in);
+ }
+ catch (XMPPException e) {
+ return false; // server answered in an unsupported way
+ }
+
+ // verify response
+ connectionRequest[1] = (byte) 0x00; // set expected return status to 0
+ return Arrays.equals(connectionRequest, connectionResponse);
+ }
+
+ /**
+ * Returns a SOCKS5 connection request message. It contains the command "connect", the address
+ * type "domain" and the digest as address.
+ * <p>
+ * (see <a href="http://tools.ietf.org/html/rfc1928">RFC1928</a>)
+ *
+ * @return SOCKS5 connection request message
+ */
+ private byte[] createSocks5ConnectRequest() {
+ byte addr[] = this.digest.getBytes();
+
+ byte[] data = new byte[7 + addr.length];
+ data[0] = (byte) 0x05; // version (SOCKS5)
+ data[1] = (byte) 0x01; // command (1 - connect)
+ data[2] = (byte) 0x00; // reserved byte (always 0)
+ data[3] = (byte) 0x03; // address type (3 - domain name)
+ data[4] = (byte) addr.length; // address length
+ System.arraycopy(addr, 0, data, 5, addr.length); // address
+ data[data.length - 2] = (byte) 0; // address port (2 bytes always 0)
+ data[data.length - 1] = (byte) 0;
+
+ return data;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java
index 0d90791a9..94a7ac729 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java
@@ -1,117 +1,117 @@
-/**
- * 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.bytestreams.socks5;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.util.concurrent.TimeoutException;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.util.SyncPacketSend;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
-
-/**
- * Implementation of a SOCKS5 client used on the initiators side. This is needed because connecting
- * to the local SOCKS5 proxy differs form the regular way to connect to a SOCKS5 proxy. Additionally
- * a remote SOCKS5 proxy has to be activated by the initiator before data can be transferred between
- * the peers.
- *
- * @author Henning Staib
- */
-class Socks5ClientForInitiator extends Socks5Client {
-
- /* the XMPP connection used to communicate with the SOCKS5 proxy */
- private Connection connection;
-
- /* the session ID used to activate SOCKS5 stream */
- private String sessionID;
-
- /* the target JID used to activate SOCKS5 stream */
- private String target;
-
- /**
- * Creates a new SOCKS5 client for the initiators side.
- *
- * @param streamHost containing network settings of the SOCKS5 proxy
- * @param digest identifying the SOCKS5 Bytestream
- * @param connection the XMPP connection
- * @param sessionID the session ID of the SOCKS5 Bytestream
- * @param target the target JID of the SOCKS5 Bytestream
- */
- public Socks5ClientForInitiator(StreamHost streamHost, String digest, Connection connection,
- String sessionID, String target) {
- super(streamHost, digest);
- this.connection = connection;
- this.sessionID = sessionID;
- this.target = target;
- }
-
- public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
- TimeoutException {
- Socket socket = null;
-
- // check if stream host is the local SOCKS5 proxy
- if (this.streamHost.getJID().equals(this.connection.getUser())) {
- Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
- socket = socks5Server.getSocket(this.digest);
- if (socket == null) {
- throw new XMPPException("target is not connected to SOCKS5 proxy");
- }
- }
- else {
- socket = super.getSocket(timeout);
-
- try {
- activate();
- }
- catch (XMPPException e) {
- socket.close();
- throw new XMPPException("activating SOCKS5 Bytestream failed", e);
- }
-
- }
-
- return socket;
- }
-
- /**
- * Activates the SOCKS5 Bytestream by sending a XMPP SOCKS5 Bytestream activation packet to the
- * SOCKS5 proxy.
- */
- private void activate() throws XMPPException {
- Bytestream activate = createStreamHostActivation();
- // if activation fails #getReply throws an exception
- SyncPacketSend.getReply(this.connection, activate);
- }
-
- /**
- * Returns a SOCKS5 Bytestream activation packet.
- *
- * @return SOCKS5 Bytestream activation packet
- */
- private Bytestream createStreamHostActivation() {
- Bytestream activate = new Bytestream(this.sessionID);
- activate.setMode(null);
- activate.setType(IQ.Type.SET);
- activate.setTo(this.streamHost.getJID());
-
- activate.setToActivate(this.target);
-
- return activate;
- }
-
-}
+/**
+ * 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.bytestreams.socks5;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.concurrent.TimeoutException;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.util.SyncPacketSend;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
+
+/**
+ * Implementation of a SOCKS5 client used on the initiators side. This is needed because connecting
+ * to the local SOCKS5 proxy differs form the regular way to connect to a SOCKS5 proxy. Additionally
+ * a remote SOCKS5 proxy has to be activated by the initiator before data can be transferred between
+ * the peers.
+ *
+ * @author Henning Staib
+ */
+class Socks5ClientForInitiator extends Socks5Client {
+
+ /* the XMPP connection used to communicate with the SOCKS5 proxy */
+ private Connection connection;
+
+ /* the session ID used to activate SOCKS5 stream */
+ private String sessionID;
+
+ /* the target JID used to activate SOCKS5 stream */
+ private String target;
+
+ /**
+ * Creates a new SOCKS5 client for the initiators side.
+ *
+ * @param streamHost containing network settings of the SOCKS5 proxy
+ * @param digest identifying the SOCKS5 Bytestream
+ * @param connection the XMPP connection
+ * @param sessionID the session ID of the SOCKS5 Bytestream
+ * @param target the target JID of the SOCKS5 Bytestream
+ */
+ public Socks5ClientForInitiator(StreamHost streamHost, String digest, Connection connection,
+ String sessionID, String target) {
+ super(streamHost, digest);
+ this.connection = connection;
+ this.sessionID = sessionID;
+ this.target = target;
+ }
+
+ public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
+ TimeoutException {
+ Socket socket = null;
+
+ // check if stream host is the local SOCKS5 proxy
+ if (this.streamHost.getJID().equals(this.connection.getUser())) {
+ Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
+ socket = socks5Server.getSocket(this.digest);
+ if (socket == null) {
+ throw new XMPPException("target is not connected to SOCKS5 proxy");
+ }
+ }
+ else {
+ socket = super.getSocket(timeout);
+
+ try {
+ activate();
+ }
+ catch (XMPPException e) {
+ socket.close();
+ throw new XMPPException("activating SOCKS5 Bytestream failed", e);
+ }
+
+ }
+
+ return socket;
+ }
+
+ /**
+ * Activates the SOCKS5 Bytestream by sending a XMPP SOCKS5 Bytestream activation packet to the
+ * SOCKS5 proxy.
+ */
+ private void activate() throws XMPPException {
+ Bytestream activate = createStreamHostActivation();
+ // if activation fails #getReply throws an exception
+ SyncPacketSend.getReply(this.connection, activate);
+ }
+
+ /**
+ * Returns a SOCKS5 Bytestream activation packet.
+ *
+ * @return SOCKS5 Bytestream activation packet
+ */
+ private Bytestream createStreamHostActivation() {
+ Bytestream activate = new Bytestream(this.sessionID);
+ activate.setMode(null);
+ activate.setType(IQ.Type.SET);
+ activate.setTo(this.streamHost.getJID());
+
+ activate.setToActivate(this.target);
+
+ return activate;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java
index 11ef7a9c5..d45dd6dd5 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java
@@ -1,423 +1,423 @@
-/**
- * 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.bytestreams.socks5;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.jivesoftware.smack.SmackConfiguration;
-import org.jivesoftware.smack.XMPPException;
-
-/**
- * The Socks5Proxy class represents a local SOCKS5 proxy server. It can be enabled/disabled by
- * setting the <code>localSocks5ProxyEnabled</code> flag in the <code>smack-config.xml</code> or by
- * invoking {@link SmackConfiguration#setLocalSocks5ProxyEnabled(boolean)}. The proxy is enabled by
- * default.
- * <p>
- * The port of the local SOCKS5 proxy can be configured by setting <code>localSocks5ProxyPort</code>
- * in the <code>smack-config.xml</code> or by invoking
- * {@link SmackConfiguration#setLocalSocks5ProxyPort(int)}. Default port is 7777. If you set the
- * port to a negative value Smack tries to the absolute value and all following until it finds an
- * open port.
- * <p>
- * If your application is running on a machine with multiple network interfaces or if you want to
- * provide your public address in case you are behind a NAT router, invoke
- * {@link #addLocalAddress(String)} or {@link #replaceLocalAddresses(List)} to modify the list of
- * local network addresses used for outgoing SOCKS5 Bytestream requests.
- * <p>
- * The local SOCKS5 proxy server refuses all connections except the ones that are explicitly allowed
- * in the process of establishing a SOCKS5 Bytestream (
- * {@link Socks5BytestreamManager#establishSession(String)}).
- * <p>
- * This Implementation has the following limitations:
- * <ul>
- * <li>only supports the no-authentication authentication method</li>
- * <li>only supports the <code>connect</code> command and will not answer correctly to other
- * commands</li>
- * <li>only supports requests with the domain address type and will not correctly answer to requests
- * with other address types</li>
- * </ul>
- * (see <a href="http://tools.ietf.org/html/rfc1928">RFC 1928</a>)
- *
- * @author Henning Staib
- */
-public class Socks5Proxy {
-
- /* SOCKS5 proxy singleton */
- private static Socks5Proxy socks5Server;
-
- /* reusable implementation of a SOCKS5 proxy server process */
- private Socks5ServerProcess serverProcess;
-
- /* thread running the SOCKS5 server process */
- private Thread serverThread;
-
- /* server socket to accept SOCKS5 connections */
- private ServerSocket serverSocket;
-
- /* assigns a connection to a digest */
- private final Map<String, Socket> connectionMap = new ConcurrentHashMap<String, Socket>();
-
- /* list of digests connections should be stored */
- private final List<String> allowedConnections = Collections.synchronizedList(new LinkedList<String>());
-
- private final Set<String> localAddresses = Collections.synchronizedSet(new LinkedHashSet<String>());
-
- /**
- * Private constructor.
- */
- private Socks5Proxy() {
- this.serverProcess = new Socks5ServerProcess();
-
- // add default local address
- try {
- this.localAddresses.add(InetAddress.getLocalHost().getHostAddress());
- }
- catch (UnknownHostException e) {
- // do nothing
- }
-
- }
-
- /**
- * Returns the local SOCKS5 proxy server.
- *
- * @return the local SOCKS5 proxy server
- */
- public static synchronized Socks5Proxy getSocks5Proxy() {
- if (socks5Server == null) {
- socks5Server = new Socks5Proxy();
- }
- if (SmackConfiguration.isLocalSocks5ProxyEnabled()) {
- socks5Server.start();
- }
- return socks5Server;
- }
-
- /**
- * Starts the local SOCKS5 proxy server. If it is already running, this method does nothing.
- */
- public synchronized void start() {
- if (isRunning()) {
- return;
- }
- try {
- if (SmackConfiguration.getLocalSocks5ProxyPort() < 0) {
- int port = Math.abs(SmackConfiguration.getLocalSocks5ProxyPort());
- for (int i = 0; i < 65535 - port; i++) {
- try {
- this.serverSocket = new ServerSocket(port + i);
- break;
- }
- catch (IOException e) {
- // port is used, try next one
- }
- }
- }
- else {
- this.serverSocket = new ServerSocket(SmackConfiguration.getLocalSocks5ProxyPort());
- }
-
- if (this.serverSocket != null) {
- this.serverThread = new Thread(this.serverProcess);
- this.serverThread.start();
- }
- }
- catch (IOException e) {
- // couldn't setup server
- System.err.println("couldn't setup local SOCKS5 proxy on port "
- + SmackConfiguration.getLocalSocks5ProxyPort() + ": " + e.getMessage());
- }
- }
-
- /**
- * Stops the local SOCKS5 proxy server. If it is not running this method does nothing.
- */
- public synchronized void stop() {
- if (!isRunning()) {
- return;
- }
-
- try {
- this.serverSocket.close();
- }
- catch (IOException e) {
- // do nothing
- }
-
- if (this.serverThread != null && this.serverThread.isAlive()) {
- try {
- this.serverThread.interrupt();
- this.serverThread.join();
- }
- catch (InterruptedException e) {
- // do nothing
- }
- }
- this.serverThread = null;
- this.serverSocket = null;
-
- }
-
- /**
- * Adds the given address to the list of local network addresses.
- * <p>
- * Use this method if you want to provide multiple addresses in a SOCKS5 Bytestream request.
- * This may be necessary if your application is running on a machine with multiple network
- * interfaces or if you want to provide your public address in case you are behind a NAT router.
- * <p>
- * The order of the addresses used is determined by the order you add addresses.
- * <p>
- * Note that the list of addresses initially contains the address returned by
- * <code>InetAddress.getLocalHost().getHostAddress()</code>. You can replace the list of
- * addresses by invoking {@link #replaceLocalAddresses(List)}.
- *
- * @param address the local network address to add
- */
- public void addLocalAddress(String address) {
- if (address == null) {
- throw new IllegalArgumentException("address may not be null");
- }
- this.localAddresses.add(address);
- }
-
- /**
- * Removes the given address from the list of local network addresses. This address will then no
- * longer be used of outgoing SOCKS5 Bytestream requests.
- *
- * @param address the local network address to remove
- */
- public void removeLocalAddress(String address) {
- this.localAddresses.remove(address);
- }
-
- /**
- * Returns an unmodifiable list of the local network addresses that will be used for streamhost
- * candidates of outgoing SOCKS5 Bytestream requests.
- *
- * @return unmodifiable list of the local network addresses
- */
- public List<String> getLocalAddresses() {
- return Collections.unmodifiableList(new ArrayList<String>(this.localAddresses));
- }
-
- /**
- * Replaces the list of local network addresses.
- * <p>
- * Use this method if you want to provide multiple addresses in a SOCKS5 Bytestream request and
- * want to define their order. This may be necessary if your application is running on a machine
- * with multiple network interfaces or if you want to provide your public address in case you
- * are behind a NAT router.
- *
- * @param addresses the new list of local network addresses
- */
- public void replaceLocalAddresses(List<String> addresses) {
- if (addresses == null) {
- throw new IllegalArgumentException("list must not be null");
- }
- this.localAddresses.clear();
- this.localAddresses.addAll(addresses);
-
- }
-
- /**
- * Returns the port of the local SOCKS5 proxy server. If it is not running -1 will be returned.
- *
- * @return the port of the local SOCKS5 proxy server or -1 if proxy is not running
- */
- public int getPort() {
- if (!isRunning()) {
- return -1;
- }
- return this.serverSocket.getLocalPort();
- }
-
- /**
- * Returns the socket for the given digest. A socket will be returned if the given digest has
- * been in the list of allowed transfers (see {@link #addTransfer(String)}) while the peer
- * connected to the SOCKS5 proxy.
- *
- * @param digest identifying the connection
- * @return socket or null if there is no socket for the given digest
- */
- protected Socket getSocket(String digest) {
- return this.connectionMap.get(digest);
- }
-
- /**
- * Add the given digest to the list of allowed transfers. Only connections for allowed transfers
- * are stored and can be retrieved by invoking {@link #getSocket(String)}. All connections to
- * the local SOCKS5 proxy that don't contain an allowed digest are discarded.
- *
- * @param digest to be added to the list of allowed transfers
- */
- protected void addTransfer(String digest) {
- this.allowedConnections.add(digest);
- }
-
- /**
- * Removes the given digest from the list of allowed transfers. After invoking this method
- * already stored connections with the given digest will be removed.
- * <p>
- * The digest should be removed after establishing the SOCKS5 Bytestream is finished, an error
- * occurred while establishing the connection or if the connection is not allowed anymore.
- *
- * @param digest to be removed from the list of allowed transfers
- */
- protected void removeTransfer(String digest) {
- this.allowedConnections.remove(digest);
- this.connectionMap.remove(digest);
- }
-
- /**
- * Returns <code>true</code> if the local SOCKS5 proxy server is running, otherwise
- * <code>false</code>.
- *
- * @return <code>true</code> if the local SOCKS5 proxy server is running, otherwise
- * <code>false</code>
- */
- public boolean isRunning() {
- return this.serverSocket != null;
- }
-
- /**
- * Implementation of a simplified SOCKS5 proxy server.
- */
- private class Socks5ServerProcess implements Runnable {
-
- public void run() {
- while (true) {
- Socket socket = null;
-
- try {
-
- if (Socks5Proxy.this.serverSocket.isClosed()
- || Thread.currentThread().isInterrupted()) {
- return;
- }
-
- // accept connection
- socket = Socks5Proxy.this.serverSocket.accept();
-
- // initialize connection
- establishConnection(socket);
-
- }
- catch (SocketException e) {
- /*
- * do nothing, if caused by closing the server socket, thread will terminate in
- * next loop
- */
- }
- catch (Exception e) {
- try {
- if (socket != null) {
- socket.close();
- }
- }
- catch (IOException e1) {
- /* do nothing */
- }
- }
- }
-
- }
-
- /**
- * Negotiates a SOCKS5 connection and stores it on success.
- *
- * @param socket connection to the client
- * @throws XMPPException if client requests a connection in an unsupported way
- * @throws IOException if a network error occurred
- */
- private void establishConnection(Socket socket) throws XMPPException, IOException {
- DataOutputStream out = new DataOutputStream(socket.getOutputStream());
- DataInputStream in = new DataInputStream(socket.getInputStream());
-
- // first byte is version should be 5
- int b = in.read();
- if (b != 5) {
- throw new XMPPException("Only SOCKS5 supported");
- }
-
- // second byte number of authentication methods supported
- b = in.read();
-
- // read list of supported authentication methods
- byte[] auth = new byte[b];
- in.readFully(auth);
-
- byte[] authMethodSelectionResponse = new byte[2];
- authMethodSelectionResponse[0] = (byte) 0x05; // protocol version
-
- // only authentication method 0, no authentication, supported
- boolean noAuthMethodFound = false;
- for (int i = 0; i < auth.length; i++) {
- if (auth[i] == (byte) 0x00) {
- noAuthMethodFound = true;
- break;
- }
- }
-
- if (!noAuthMethodFound) {
- authMethodSelectionResponse[1] = (byte) 0xFF; // no acceptable methods
- out.write(authMethodSelectionResponse);
- out.flush();
- throw new XMPPException("Authentication method not supported");
- }
-
- authMethodSelectionResponse[1] = (byte) 0x00; // no-authentication method
- out.write(authMethodSelectionResponse);
- out.flush();
-
- // receive connection request
- byte[] connectionRequest = Socks5Utils.receiveSocks5Message(in);
-
- // extract digest
- String responseDigest = new String(connectionRequest, 5, connectionRequest[4]);
-
- // return error if digest is not allowed
- if (!Socks5Proxy.this.allowedConnections.contains(responseDigest)) {
- connectionRequest[1] = (byte) 0x05; // set return status to 5 (connection refused)
- out.write(connectionRequest);
- out.flush();
-
- throw new XMPPException("Connection is not allowed");
- }
-
- connectionRequest[1] = (byte) 0x00; // set return status to 0 (success)
- out.write(connectionRequest);
- out.flush();
-
- // store connection
- Socks5Proxy.this.connectionMap.put(responseDigest, socket);
- }
-
- }
-
-}
+/**
+ * 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.bytestreams.socks5;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.XMPPException;
+
+/**
+ * The Socks5Proxy class represents a local SOCKS5 proxy server. It can be enabled/disabled by
+ * setting the <code>localSocks5ProxyEnabled</code> flag in the <code>smack-config.xml</code> or by
+ * invoking {@link SmackConfiguration#setLocalSocks5ProxyEnabled(boolean)}. The proxy is enabled by
+ * default.
+ * <p>
+ * The port of the local SOCKS5 proxy can be configured by setting <code>localSocks5ProxyPort</code>
+ * in the <code>smack-config.xml</code> or by invoking
+ * {@link SmackConfiguration#setLocalSocks5ProxyPort(int)}. Default port is 7777. If you set the
+ * port to a negative value Smack tries to the absolute value and all following until it finds an
+ * open port.
+ * <p>
+ * If your application is running on a machine with multiple network interfaces or if you want to
+ * provide your public address in case you are behind a NAT router, invoke
+ * {@link #addLocalAddress(String)} or {@link #replaceLocalAddresses(List)} to modify the list of
+ * local network addresses used for outgoing SOCKS5 Bytestream requests.
+ * <p>
+ * The local SOCKS5 proxy server refuses all connections except the ones that are explicitly allowed
+ * in the process of establishing a SOCKS5 Bytestream (
+ * {@link Socks5BytestreamManager#establishSession(String)}).
+ * <p>
+ * This Implementation has the following limitations:
+ * <ul>
+ * <li>only supports the no-authentication authentication method</li>
+ * <li>only supports the <code>connect</code> command and will not answer correctly to other
+ * commands</li>
+ * <li>only supports requests with the domain address type and will not correctly answer to requests
+ * with other address types</li>
+ * </ul>
+ * (see <a href="http://tools.ietf.org/html/rfc1928">RFC 1928</a>)
+ *
+ * @author Henning Staib
+ */
+public class Socks5Proxy {
+
+ /* SOCKS5 proxy singleton */
+ private static Socks5Proxy socks5Server;
+
+ /* reusable implementation of a SOCKS5 proxy server process */
+ private Socks5ServerProcess serverProcess;
+
+ /* thread running the SOCKS5 server process */
+ private Thread serverThread;
+
+ /* server socket to accept SOCKS5 connections */
+ private ServerSocket serverSocket;
+
+ /* assigns a connection to a digest */
+ private final Map<String, Socket> connectionMap = new ConcurrentHashMap<String, Socket>();
+
+ /* list of digests connections should be stored */
+ private final List<String> allowedConnections = Collections.synchronizedList(new LinkedList<String>());
+
+ private final Set<String> localAddresses = Collections.synchronizedSet(new LinkedHashSet<String>());
+
+ /**
+ * Private constructor.
+ */
+ private Socks5Proxy() {
+ this.serverProcess = new Socks5ServerProcess();
+
+ // add default local address
+ try {
+ this.localAddresses.add(InetAddress.getLocalHost().getHostAddress());
+ }
+ catch (UnknownHostException e) {
+ // do nothing
+ }
+
+ }
+
+ /**
+ * Returns the local SOCKS5 proxy server.
+ *
+ * @return the local SOCKS5 proxy server
+ */
+ public static synchronized Socks5Proxy getSocks5Proxy() {
+ if (socks5Server == null) {
+ socks5Server = new Socks5Proxy();
+ }
+ if (SmackConfiguration.isLocalSocks5ProxyEnabled()) {
+ socks5Server.start();
+ }
+ return socks5Server;
+ }
+
+ /**
+ * Starts the local SOCKS5 proxy server. If it is already running, this method does nothing.
+ */
+ public synchronized void start() {
+ if (isRunning()) {
+ return;
+ }
+ try {
+ if (SmackConfiguration.getLocalSocks5ProxyPort() < 0) {
+ int port = Math.abs(SmackConfiguration.getLocalSocks5ProxyPort());
+ for (int i = 0; i < 65535 - port; i++) {
+ try {
+ this.serverSocket = new ServerSocket(port + i);
+ break;
+ }
+ catch (IOException e) {
+ // port is used, try next one
+ }
+ }
+ }
+ else {
+ this.serverSocket = new ServerSocket(SmackConfiguration.getLocalSocks5ProxyPort());
+ }
+
+ if (this.serverSocket != null) {
+ this.serverThread = new Thread(this.serverProcess);
+ this.serverThread.start();
+ }
+ }
+ catch (IOException e) {
+ // couldn't setup server
+ System.err.println("couldn't setup local SOCKS5 proxy on port "
+ + SmackConfiguration.getLocalSocks5ProxyPort() + ": " + e.getMessage());
+ }
+ }
+
+ /**
+ * Stops the local SOCKS5 proxy server. If it is not running this method does nothing.
+ */
+ public synchronized void stop() {
+ if (!isRunning()) {
+ return;
+ }
+
+ try {
+ this.serverSocket.close();
+ }
+ catch (IOException e) {
+ // do nothing
+ }
+
+ if (this.serverThread != null && this.serverThread.isAlive()) {
+ try {
+ this.serverThread.interrupt();
+ this.serverThread.join();
+ }
+ catch (InterruptedException e) {
+ // do nothing
+ }
+ }
+ this.serverThread = null;
+ this.serverSocket = null;
+
+ }
+
+ /**
+ * Adds the given address to the list of local network addresses.
+ * <p>
+ * Use this method if you want to provide multiple addresses in a SOCKS5 Bytestream request.
+ * This may be necessary if your application is running on a machine with multiple network
+ * interfaces or if you want to provide your public address in case you are behind a NAT router.
+ * <p>
+ * The order of the addresses used is determined by the order you add addresses.
+ * <p>
+ * Note that the list of addresses initially contains the address returned by
+ * <code>InetAddress.getLocalHost().getHostAddress()</code>. You can replace the list of
+ * addresses by invoking {@link #replaceLocalAddresses(List)}.
+ *
+ * @param address the local network address to add
+ */
+ public void addLocalAddress(String address) {
+ if (address == null) {
+ throw new IllegalArgumentException("address may not be null");
+ }
+ this.localAddresses.add(address);
+ }
+
+ /**
+ * Removes the given address from the list of local network addresses. This address will then no
+ * longer be used of outgoing SOCKS5 Bytestream requests.
+ *
+ * @param address the local network address to remove
+ */
+ public void removeLocalAddress(String address) {
+ this.localAddresses.remove(address);
+ }
+
+ /**
+ * Returns an unmodifiable list of the local network addresses that will be used for streamhost
+ * candidates of outgoing SOCKS5 Bytestream requests.
+ *
+ * @return unmodifiable list of the local network addresses
+ */
+ public List<String> getLocalAddresses() {
+ return Collections.unmodifiableList(new ArrayList<String>(this.localAddresses));
+ }
+
+ /**
+ * Replaces the list of local network addresses.
+ * <p>
+ * Use this method if you want to provide multiple addresses in a SOCKS5 Bytestream request and
+ * want to define their order. This may be necessary if your application is running on a machine
+ * with multiple network interfaces or if you want to provide your public address in case you
+ * are behind a NAT router.
+ *
+ * @param addresses the new list of local network addresses
+ */
+ public void replaceLocalAddresses(List<String> addresses) {
+ if (addresses == null) {
+ throw new IllegalArgumentException("list must not be null");
+ }
+ this.localAddresses.clear();
+ this.localAddresses.addAll(addresses);
+
+ }
+
+ /**
+ * Returns the port of the local SOCKS5 proxy server. If it is not running -1 will be returned.
+ *
+ * @return the port of the local SOCKS5 proxy server or -1 if proxy is not running
+ */
+ public int getPort() {
+ if (!isRunning()) {
+ return -1;
+ }
+ return this.serverSocket.getLocalPort();
+ }
+
+ /**
+ * Returns the socket for the given digest. A socket will be returned if the given digest has
+ * been in the list of allowed transfers (see {@link #addTransfer(String)}) while the peer
+ * connected to the SOCKS5 proxy.
+ *
+ * @param digest identifying the connection
+ * @return socket or null if there is no socket for the given digest
+ */
+ protected Socket getSocket(String digest) {
+ return this.connectionMap.get(digest);
+ }
+
+ /**
+ * Add the given digest to the list of allowed transfers. Only connections for allowed transfers
+ * are stored and can be retrieved by invoking {@link #getSocket(String)}. All connections to
+ * the local SOCKS5 proxy that don't contain an allowed digest are discarded.
+ *
+ * @param digest to be added to the list of allowed transfers
+ */
+ protected void addTransfer(String digest) {
+ this.allowedConnections.add(digest);
+ }
+
+ /**
+ * Removes the given digest from the list of allowed transfers. After invoking this method
+ * already stored connections with the given digest will be removed.
+ * <p>
+ * The digest should be removed after establishing the SOCKS5 Bytestream is finished, an error
+ * occurred while establishing the connection or if the connection is not allowed anymore.
+ *
+ * @param digest to be removed from the list of allowed transfers
+ */
+ protected void removeTransfer(String digest) {
+ this.allowedConnections.remove(digest);
+ this.connectionMap.remove(digest);
+ }
+
+ /**
+ * Returns <code>true</code> if the local SOCKS5 proxy server is running, otherwise
+ * <code>false</code>.
+ *
+ * @return <code>true</code> if the local SOCKS5 proxy server is running, otherwise
+ * <code>false</code>
+ */
+ public boolean isRunning() {
+ return this.serverSocket != null;
+ }
+
+ /**
+ * Implementation of a simplified SOCKS5 proxy server.
+ */
+ private class Socks5ServerProcess implements Runnable {
+
+ public void run() {
+ while (true) {
+ Socket socket = null;
+
+ try {
+
+ if (Socks5Proxy.this.serverSocket.isClosed()
+ || Thread.currentThread().isInterrupted()) {
+ return;
+ }
+
+ // accept connection
+ socket = Socks5Proxy.this.serverSocket.accept();
+
+ // initialize connection
+ establishConnection(socket);
+
+ }
+ catch (SocketException e) {
+ /*
+ * do nothing, if caused by closing the server socket, thread will terminate in
+ * next loop
+ */
+ }
+ catch (Exception e) {
+ try {
+ if (socket != null) {
+ socket.close();
+ }
+ }
+ catch (IOException e1) {
+ /* do nothing */
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Negotiates a SOCKS5 connection and stores it on success.
+ *
+ * @param socket connection to the client
+ * @throws XMPPException if client requests a connection in an unsupported way
+ * @throws IOException if a network error occurred
+ */
+ private void establishConnection(Socket socket) throws XMPPException, IOException {
+ DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+ DataInputStream in = new DataInputStream(socket.getInputStream());
+
+ // first byte is version should be 5
+ int b = in.read();
+ if (b != 5) {
+ throw new XMPPException("Only SOCKS5 supported");
+ }
+
+ // second byte number of authentication methods supported
+ b = in.read();
+
+ // read list of supported authentication methods
+ byte[] auth = new byte[b];
+ in.readFully(auth);
+
+ byte[] authMethodSelectionResponse = new byte[2];
+ authMethodSelectionResponse[0] = (byte) 0x05; // protocol version
+
+ // only authentication method 0, no authentication, supported
+ boolean noAuthMethodFound = false;
+ for (int i = 0; i < auth.length; i++) {
+ if (auth[i] == (byte) 0x00) {
+ noAuthMethodFound = true;
+ break;
+ }
+ }
+
+ if (!noAuthMethodFound) {
+ authMethodSelectionResponse[1] = (byte) 0xFF; // no acceptable methods
+ out.write(authMethodSelectionResponse);
+ out.flush();
+ throw new XMPPException("Authentication method not supported");
+ }
+
+ authMethodSelectionResponse[1] = (byte) 0x00; // no-authentication method
+ out.write(authMethodSelectionResponse);
+ out.flush();
+
+ // receive connection request
+ byte[] connectionRequest = Socks5Utils.receiveSocks5Message(in);
+
+ // extract digest
+ String responseDigest = new String(connectionRequest, 5, connectionRequest[4]);
+
+ // return error if digest is not allowed
+ if (!Socks5Proxy.this.allowedConnections.contains(responseDigest)) {
+ connectionRequest[1] = (byte) 0x05; // set return status to 5 (connection refused)
+ out.write(connectionRequest);
+ out.flush();
+
+ throw new XMPPException("Connection is not allowed");
+ }
+
+ connectionRequest[1] = (byte) 0x00; // set return status to 0 (success)
+ out.write(connectionRequest);
+ out.flush();
+
+ // store connection
+ Socks5Proxy.this.connectionMap.put(responseDigest, socket);
+ }
+
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java
index 9c9256341..73402a54a 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java
@@ -1,73 +1,73 @@
-/**
- * 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.bytestreams.socks5;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.util.StringUtils;
-
-/**
- * A collection of utility methods for SOcKS5 messages.
- *
- * @author Henning Staib
- */
-class Socks5Utils {
-
- /**
- * Returns a SHA-1 digest of the given parameters as specified in <a
- * href="http://xmpp.org/extensions/xep-0065.html#impl-socks5">XEP-0065</a>.
- *
- * @param sessionID for the SOCKS5 Bytestream
- * @param initiatorJID JID of the initiator of a SOCKS5 Bytestream
- * @param targetJID JID of the target of a SOCKS5 Bytestream
- * @return SHA-1 digest of the given parameters
- */
- public static String createDigest(String sessionID, String initiatorJID, String targetJID) {
- StringBuilder b = new StringBuilder();
- b.append(sessionID).append(initiatorJID).append(targetJID);
- return StringUtils.hash(b.toString());
- }
-
- /**
- * Reads a SOCKS5 message from the given InputStream. The message can either be a SOCKS5 request
- * message or a SOCKS5 response message.
- * <p>
- * (see <a href="http://tools.ietf.org/html/rfc1928">RFC1928</a>)
- *
- * @param in the DataInputStream to read the message from
- * @return the SOCKS5 message
- * @throws IOException if a network error occurred
- * @throws XMPPException if the SOCKS5 message contains an unsupported address type
- */
- public static byte[] receiveSocks5Message(DataInputStream in) throws IOException, XMPPException {
- byte[] header = new byte[5];
- in.readFully(header, 0, 5);
-
- if (header[3] != (byte) 0x03) {
- throw new XMPPException("Unsupported SOCKS5 address type");
- }
-
- int addressLength = header[4];
-
- byte[] response = new byte[7 + addressLength];
- System.arraycopy(header, 0, response, 0, header.length);
-
- in.readFully(response, header.length, addressLength + 2);
-
- return response;
- }
-
-}
+/**
+ * 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.bytestreams.socks5;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.util.StringUtils;
+
+/**
+ * A collection of utility methods for SOcKS5 messages.
+ *
+ * @author Henning Staib
+ */
+class Socks5Utils {
+
+ /**
+ * Returns a SHA-1 digest of the given parameters as specified in <a
+ * href="http://xmpp.org/extensions/xep-0065.html#impl-socks5">XEP-0065</a>.
+ *
+ * @param sessionID for the SOCKS5 Bytestream
+ * @param initiatorJID JID of the initiator of a SOCKS5 Bytestream
+ * @param targetJID JID of the target of a SOCKS5 Bytestream
+ * @return SHA-1 digest of the given parameters
+ */
+ public static String createDigest(String sessionID, String initiatorJID, String targetJID) {
+ StringBuilder b = new StringBuilder();
+ b.append(sessionID).append(initiatorJID).append(targetJID);
+ return StringUtils.hash(b.toString());
+ }
+
+ /**
+ * Reads a SOCKS5 message from the given InputStream. The message can either be a SOCKS5 request
+ * message or a SOCKS5 response message.
+ * <p>
+ * (see <a href="http://tools.ietf.org/html/rfc1928">RFC1928</a>)
+ *
+ * @param in the DataInputStream to read the message from
+ * @return the SOCKS5 message
+ * @throws IOException if a network error occurred
+ * @throws XMPPException if the SOCKS5 message contains an unsupported address type
+ */
+ public static byte[] receiveSocks5Message(DataInputStream in) throws IOException, XMPPException {
+ byte[] header = new byte[5];
+ in.readFully(header, 0, 5);
+
+ if (header[3] != (byte) 0x03) {
+ throw new XMPPException("Unsupported SOCKS5 address type");
+ }
+
+ int addressLength = header[4];
+
+ byte[] response = new byte[7 + addressLength];
+ System.arraycopy(header, 0, response, 0, header.length);
+
+ in.readFully(response, header.length, addressLength + 2);
+
+ return response;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
index 9e07fc379..303d5b885 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
@@ -1,474 +1,474 @@
-/**
- * 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.bytestreams.socks5.packet;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * A packet representing part of a SOCKS5 Bytestream negotiation.
- *
- * @author Alexander Wenckus
- */
-public class Bytestream extends IQ {
-
- private String sessionID;
-
- private Mode mode = Mode.tcp;
-
- private final List<StreamHost> streamHosts = new ArrayList<StreamHost>();
-
- private StreamHostUsed usedHost;
-
- private Activate toActivate;
-
- /**
- * The default constructor
- */
- public Bytestream() {
- super();
- }
-
- /**
- * A constructor where the session ID can be specified.
- *
- * @param SID The session ID related to the negotiation.
- * @see #setSessionID(String)
- */
- public Bytestream(final String SID) {
- super();
- setSessionID(SID);
- }
-
- /**
- * Set the session ID related to the bytestream. The session ID is a unique identifier used to
- * differentiate between stream negotiations.
- *
- * @param sessionID the unique session ID that identifies the transfer.
- */
- public void setSessionID(final String sessionID) {
- this.sessionID = sessionID;
- }
-
- /**
- * Returns the session ID related to the bytestream negotiation.
- *
- * @return Returns the session ID related to the bytestream negotiation.
- * @see #setSessionID(String)
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Set the transport mode. This should be put in the initiation of the interaction.
- *
- * @param mode the transport mode, either UDP or TCP
- * @see Mode
- */
- public void setMode(final Mode mode) {
- this.mode = mode;
- }
-
- /**
- * Returns the transport mode.
- *
- * @return Returns the transport mode.
- * @see #setMode(Mode)
- */
- public Mode getMode() {
- return mode;
- }
-
- /**
- * Adds a potential stream host that the remote user can connect to to receive the file.
- *
- * @param JID The JID of the stream host.
- * @param address The internet address of the stream host.
- * @return The added stream host.
- */
- public StreamHost addStreamHost(final String JID, final String address) {
- return addStreamHost(JID, address, 0);
- }
-
- /**
- * Adds a potential stream host that the remote user can connect to to receive the file.
- *
- * @param JID The JID of the stream host.
- * @param address The internet address of the stream host.
- * @param port The port on which the remote host is seeking connections.
- * @return The added stream host.
- */
- public StreamHost addStreamHost(final String JID, final String address, final int port) {
- StreamHost host = new StreamHost(JID, address);
- host.setPort(port);
- addStreamHost(host);
-
- return host;
- }
-
- /**
- * Adds a potential stream host that the remote user can transfer the file through.
- *
- * @param host The potential stream host.
- */
- public void addStreamHost(final StreamHost host) {
- streamHosts.add(host);
- }
-
- /**
- * Returns the list of stream hosts contained in the packet.
- *
- * @return Returns the list of stream hosts contained in the packet.
- */
- public Collection<StreamHost> getStreamHosts() {
- return Collections.unmodifiableCollection(streamHosts);
- }
-
- /**
- * Returns the stream host related to the given JID, or null if there is none.
- *
- * @param JID The JID of the desired stream host.
- * @return Returns the stream host related to the given JID, or null if there is none.
- */
- public StreamHost getStreamHost(final String JID) {
- if (JID == null) {
- return null;
- }
- for (StreamHost host : streamHosts) {
- if (host.getJID().equals(JID)) {
- return host;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the count of stream hosts contained in this packet.
- *
- * @return Returns the count of stream hosts contained in this packet.
- */
- public int countStreamHosts() {
- return streamHosts.size();
- }
-
- /**
- * Upon connecting to the stream host the target of the stream replies to the initiator with the
- * JID of the SOCKS5 host that they used.
- *
- * @param JID The JID of the used host.
- */
- public void setUsedHost(final String JID) {
- this.usedHost = new StreamHostUsed(JID);
- }
-
- /**
- * Returns the SOCKS5 host connected to by the remote user.
- *
- * @return Returns the SOCKS5 host connected to by the remote user.
- */
- public StreamHostUsed getUsedHost() {
- return usedHost;
- }
-
- /**
- * Returns the activate element of the packet sent to the proxy host to verify the identity of
- * the initiator and match them to the appropriate stream.
- *
- * @return Returns the activate element of the packet sent to the proxy host to verify the
- * identity of the initiator and match them to the appropriate stream.
- */
- public Activate getToActivate() {
- return toActivate;
- }
-
- /**
- * Upon the response from the target of the used host the activate packet is sent to the SOCKS5
- * proxy. The proxy will activate the stream or return an error after verifying the identity of
- * the initiator, using the activate packet.
- *
- * @param targetID The JID of the target of the file transfer.
- */
- public void setToActivate(final String targetID) {
- this.toActivate = new Activate(targetID);
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<query xmlns=\"http://jabber.org/protocol/bytestreams\"");
- if (this.getType().equals(IQ.Type.SET)) {
- if (getSessionID() != null) {
- buf.append(" sid=\"").append(getSessionID()).append("\"");
- }
- if (getMode() != null) {
- buf.append(" mode = \"").append(getMode()).append("\"");
- }
- buf.append(">");
- if (getToActivate() == null) {
- for (StreamHost streamHost : getStreamHosts()) {
- buf.append(streamHost.toXML());
- }
- }
- else {
- buf.append(getToActivate().toXML());
- }
- }
- else if (this.getType().equals(IQ.Type.RESULT)) {
- buf.append(">");
- if (getUsedHost() != null) {
- buf.append(getUsedHost().toXML());
- }
- // A result from the server can also contain stream hosts
- else if (countStreamHosts() > 0) {
- for (StreamHost host : streamHosts) {
- buf.append(host.toXML());
- }
- }
- }
- else if (this.getType().equals(IQ.Type.GET)) {
- return buf.append("/>").toString();
- }
- else {
- return null;
- }
- buf.append("</query>");
-
- return buf.toString();
- }
-
- /**
- * Packet extension that represents a potential SOCKS5 proxy for the file transfer. Stream hosts
- * are forwarded to the target of the file transfer who then chooses and connects to one.
- *
- * @author Alexander Wenckus
- */
- public static class StreamHost implements PacketExtension {
-
- public static String NAMESPACE = "";
-
- public static String ELEMENTNAME = "streamhost";
-
- private final String JID;
-
- private final String addy;
-
- private int port = 0;
-
- /**
- * Default constructor.
- *
- * @param JID The JID of the stream host.
- * @param address The internet address of the stream host.
- */
- public StreamHost(final String JID, final String address) {
- this.JID = JID;
- this.addy = address;
- }
-
- /**
- * Returns the JID of the stream host.
- *
- * @return Returns the JID of the stream host.
- */
- public String getJID() {
- return JID;
- }
-
- /**
- * Returns the internet address of the stream host.
- *
- * @return Returns the internet address of the stream host.
- */
- public String getAddress() {
- return addy;
- }
-
- /**
- * Sets the port of the stream host.
- *
- * @param port The port on which the potential stream host would accept the connection.
- */
- public void setPort(final int port) {
- this.port = port;
- }
-
- /**
- * Returns the port on which the potential stream host would accept the connection.
- *
- * @return Returns the port on which the potential stream host would accept the connection.
- */
- public int getPort() {
- return port;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String getElementName() {
- return ELEMENTNAME;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(getElementName()).append(" ");
- buf.append("jid=\"").append(getJID()).append("\" ");
- buf.append("host=\"").append(getAddress()).append("\" ");
- if (getPort() != 0) {
- buf.append("port=\"").append(getPort()).append("\"");
- }
- else {
- buf.append("zeroconf=\"_jabber.bytestreams\"");
- }
- buf.append("/>");
-
- return buf.toString();
- }
- }
-
- /**
- * After selected a SOCKS5 stream host and successfully connecting, the target of the file
- * transfer returns a byte stream packet with the stream host used extension.
- *
- * @author Alexander Wenckus
- */
- public static class StreamHostUsed implements PacketExtension {
-
- public String NAMESPACE = "";
-
- public static String ELEMENTNAME = "streamhost-used";
-
- private final String JID;
-
- /**
- * Default constructor.
- *
- * @param JID The JID of the selected stream host.
- */
- public StreamHostUsed(final String JID) {
- this.JID = JID;
- }
-
- /**
- * Returns the JID of the selected stream host.
- *
- * @return Returns the JID of the selected stream host.
- */
- public String getJID() {
- return JID;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String getElementName() {
- return ELEMENTNAME;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(getElementName()).append(" ");
- buf.append("jid=\"").append(getJID()).append("\" ");
- buf.append("/>");
- return buf.toString();
- }
- }
-
- /**
- * The packet sent by the stream initiator to the stream proxy to activate the connection.
- *
- * @author Alexander Wenckus
- */
- public static class Activate implements PacketExtension {
-
- public String NAMESPACE = "";
-
- public static String ELEMENTNAME = "activate";
-
- private final String target;
-
- /**
- * Default constructor specifying the target of the stream.
- *
- * @param target The target of the stream.
- */
- public Activate(final String target) {
- this.target = target;
- }
-
- /**
- * Returns the target of the activation.
- *
- * @return Returns the target of the activation.
- */
- public String getTarget() {
- return target;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String getElementName() {
- return ELEMENTNAME;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(getElementName()).append(">");
- buf.append(getTarget());
- buf.append("</").append(getElementName()).append(">");
- return buf.toString();
- }
- }
-
- /**
- * The stream can be either a TCP stream or a UDP stream.
- *
- * @author Alexander Wenckus
- */
- public enum Mode {
-
- /**
- * A TCP based stream.
- */
- tcp,
-
- /**
- * A UDP based stream.
- */
- udp;
-
- public static Mode fromName(String name) {
- Mode mode;
- try {
- mode = Mode.valueOf(name);
- }
- catch (Exception ex) {
- mode = tcp;
- }
-
- return mode;
- }
- }
-}
+/**
+ * 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.bytestreams.socks5.packet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * A packet representing part of a SOCKS5 Bytestream negotiation.
+ *
+ * @author Alexander Wenckus
+ */
+public class Bytestream extends IQ {
+
+ private String sessionID;
+
+ private Mode mode = Mode.tcp;
+
+ private final List<StreamHost> streamHosts = new ArrayList<StreamHost>();
+
+ private StreamHostUsed usedHost;
+
+ private Activate toActivate;
+
+ /**
+ * The default constructor
+ */
+ public Bytestream() {
+ super();
+ }
+
+ /**
+ * A constructor where the session ID can be specified.
+ *
+ * @param SID The session ID related to the negotiation.
+ * @see #setSessionID(String)
+ */
+ public Bytestream(final String SID) {
+ super();
+ setSessionID(SID);
+ }
+
+ /**
+ * Set the session ID related to the bytestream. The session ID is a unique identifier used to
+ * differentiate between stream negotiations.
+ *
+ * @param sessionID the unique session ID that identifies the transfer.
+ */
+ public void setSessionID(final String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+ /**
+ * Returns the session ID related to the bytestream negotiation.
+ *
+ * @return Returns the session ID related to the bytestream negotiation.
+ * @see #setSessionID(String)
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Set the transport mode. This should be put in the initiation of the interaction.
+ *
+ * @param mode the transport mode, either UDP or TCP
+ * @see Mode
+ */
+ public void setMode(final Mode mode) {
+ this.mode = mode;
+ }
+
+ /**
+ * Returns the transport mode.
+ *
+ * @return Returns the transport mode.
+ * @see #setMode(Mode)
+ */
+ public Mode getMode() {
+ return mode;
+ }
+
+ /**
+ * Adds a potential stream host that the remote user can connect to to receive the file.
+ *
+ * @param JID The JID of the stream host.
+ * @param address The internet address of the stream host.
+ * @return The added stream host.
+ */
+ public StreamHost addStreamHost(final String JID, final String address) {
+ return addStreamHost(JID, address, 0);
+ }
+
+ /**
+ * Adds a potential stream host that the remote user can connect to to receive the file.
+ *
+ * @param JID The JID of the stream host.
+ * @param address The internet address of the stream host.
+ * @param port The port on which the remote host is seeking connections.
+ * @return The added stream host.
+ */
+ public StreamHost addStreamHost(final String JID, final String address, final int port) {
+ StreamHost host = new StreamHost(JID, address);
+ host.setPort(port);
+ addStreamHost(host);
+
+ return host;
+ }
+
+ /**
+ * Adds a potential stream host that the remote user can transfer the file through.
+ *
+ * @param host The potential stream host.
+ */
+ public void addStreamHost(final StreamHost host) {
+ streamHosts.add(host);
+ }
+
+ /**
+ * Returns the list of stream hosts contained in the packet.
+ *
+ * @return Returns the list of stream hosts contained in the packet.
+ */
+ public Collection<StreamHost> getStreamHosts() {
+ return Collections.unmodifiableCollection(streamHosts);
+ }
+
+ /**
+ * Returns the stream host related to the given JID, or null if there is none.
+ *
+ * @param JID The JID of the desired stream host.
+ * @return Returns the stream host related to the given JID, or null if there is none.
+ */
+ public StreamHost getStreamHost(final String JID) {
+ if (JID == null) {
+ return null;
+ }
+ for (StreamHost host : streamHosts) {
+ if (host.getJID().equals(JID)) {
+ return host;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the count of stream hosts contained in this packet.
+ *
+ * @return Returns the count of stream hosts contained in this packet.
+ */
+ public int countStreamHosts() {
+ return streamHosts.size();
+ }
+
+ /**
+ * Upon connecting to the stream host the target of the stream replies to the initiator with the
+ * JID of the SOCKS5 host that they used.
+ *
+ * @param JID The JID of the used host.
+ */
+ public void setUsedHost(final String JID) {
+ this.usedHost = new StreamHostUsed(JID);
+ }
+
+ /**
+ * Returns the SOCKS5 host connected to by the remote user.
+ *
+ * @return Returns the SOCKS5 host connected to by the remote user.
+ */
+ public StreamHostUsed getUsedHost() {
+ return usedHost;
+ }
+
+ /**
+ * Returns the activate element of the packet sent to the proxy host to verify the identity of
+ * the initiator and match them to the appropriate stream.
+ *
+ * @return Returns the activate element of the packet sent to the proxy host to verify the
+ * identity of the initiator and match them to the appropriate stream.
+ */
+ public Activate getToActivate() {
+ return toActivate;
+ }
+
+ /**
+ * Upon the response from the target of the used host the activate packet is sent to the SOCKS5
+ * proxy. The proxy will activate the stream or return an error after verifying the identity of
+ * the initiator, using the activate packet.
+ *
+ * @param targetID The JID of the target of the file transfer.
+ */
+ public void setToActivate(final String targetID) {
+ this.toActivate = new Activate(targetID);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<query xmlns=\"http://jabber.org/protocol/bytestreams\"");
+ if (this.getType().equals(IQ.Type.SET)) {
+ if (getSessionID() != null) {
+ buf.append(" sid=\"").append(getSessionID()).append("\"");
+ }
+ if (getMode() != null) {
+ buf.append(" mode = \"").append(getMode()).append("\"");
+ }
+ buf.append(">");
+ if (getToActivate() == null) {
+ for (StreamHost streamHost : getStreamHosts()) {
+ buf.append(streamHost.toXML());
+ }
+ }
+ else {
+ buf.append(getToActivate().toXML());
+ }
+ }
+ else if (this.getType().equals(IQ.Type.RESULT)) {
+ buf.append(">");
+ if (getUsedHost() != null) {
+ buf.append(getUsedHost().toXML());
+ }
+ // A result from the server can also contain stream hosts
+ else if (countStreamHosts() > 0) {
+ for (StreamHost host : streamHosts) {
+ buf.append(host.toXML());
+ }
+ }
+ }
+ else if (this.getType().equals(IQ.Type.GET)) {
+ return buf.append("/>").toString();
+ }
+ else {
+ return null;
+ }
+ buf.append("</query>");
+
+ return buf.toString();
+ }
+
+ /**
+ * Packet extension that represents a potential SOCKS5 proxy for the file transfer. Stream hosts
+ * are forwarded to the target of the file transfer who then chooses and connects to one.
+ *
+ * @author Alexander Wenckus
+ */
+ public static class StreamHost implements PacketExtension {
+
+ public static String NAMESPACE = "";
+
+ public static String ELEMENTNAME = "streamhost";
+
+ private final String JID;
+
+ private final String addy;
+
+ private int port = 0;
+
+ /**
+ * Default constructor.
+ *
+ * @param JID The JID of the stream host.
+ * @param address The internet address of the stream host.
+ */
+ public StreamHost(final String JID, final String address) {
+ this.JID = JID;
+ this.addy = address;
+ }
+
+ /**
+ * Returns the JID of the stream host.
+ *
+ * @return Returns the JID of the stream host.
+ */
+ public String getJID() {
+ return JID;
+ }
+
+ /**
+ * Returns the internet address of the stream host.
+ *
+ * @return Returns the internet address of the stream host.
+ */
+ public String getAddress() {
+ return addy;
+ }
+
+ /**
+ * Sets the port of the stream host.
+ *
+ * @param port The port on which the potential stream host would accept the connection.
+ */
+ public void setPort(final int port) {
+ this.port = port;
+ }
+
+ /**
+ * Returns the port on which the potential stream host would accept the connection.
+ *
+ * @return Returns the port on which the potential stream host would accept the connection.
+ */
+ public int getPort() {
+ return port;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getElementName() {
+ return ELEMENTNAME;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(getElementName()).append(" ");
+ buf.append("jid=\"").append(getJID()).append("\" ");
+ buf.append("host=\"").append(getAddress()).append("\" ");
+ if (getPort() != 0) {
+ buf.append("port=\"").append(getPort()).append("\"");
+ }
+ else {
+ buf.append("zeroconf=\"_jabber.bytestreams\"");
+ }
+ buf.append("/>");
+
+ return buf.toString();
+ }
+ }
+
+ /**
+ * After selected a SOCKS5 stream host and successfully connecting, the target of the file
+ * transfer returns a byte stream packet with the stream host used extension.
+ *
+ * @author Alexander Wenckus
+ */
+ public static class StreamHostUsed implements PacketExtension {
+
+ public String NAMESPACE = "";
+
+ public static String ELEMENTNAME = "streamhost-used";
+
+ private final String JID;
+
+ /**
+ * Default constructor.
+ *
+ * @param JID The JID of the selected stream host.
+ */
+ public StreamHostUsed(final String JID) {
+ this.JID = JID;
+ }
+
+ /**
+ * Returns the JID of the selected stream host.
+ *
+ * @return Returns the JID of the selected stream host.
+ */
+ public String getJID() {
+ return JID;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getElementName() {
+ return ELEMENTNAME;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(getElementName()).append(" ");
+ buf.append("jid=\"").append(getJID()).append("\" ");
+ buf.append("/>");
+ return buf.toString();
+ }
+ }
+
+ /**
+ * The packet sent by the stream initiator to the stream proxy to activate the connection.
+ *
+ * @author Alexander Wenckus
+ */
+ public static class Activate implements PacketExtension {
+
+ public String NAMESPACE = "";
+
+ public static String ELEMENTNAME = "activate";
+
+ private final String target;
+
+ /**
+ * Default constructor specifying the target of the stream.
+ *
+ * @param target The target of the stream.
+ */
+ public Activate(final String target) {
+ this.target = target;
+ }
+
+ /**
+ * Returns the target of the activation.
+ *
+ * @return Returns the target of the activation.
+ */
+ public String getTarget() {
+ return target;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getElementName() {
+ return ELEMENTNAME;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(getElementName()).append(">");
+ buf.append(getTarget());
+ buf.append("</").append(getElementName()).append(">");
+ return buf.toString();
+ }
+ }
+
+ /**
+ * The stream can be either a TCP stream or a UDP stream.
+ *
+ * @author Alexander Wenckus
+ */
+ public enum Mode {
+
+ /**
+ * A TCP based stream.
+ */
+ tcp,
+
+ /**
+ * A UDP based stream.
+ */
+ udp;
+
+ public static Mode fromName(String name) {
+ Mode mode;
+ try {
+ mode = Mode.valueOf(name);
+ }
+ catch (Exception ex) {
+ mode = tcp;
+ }
+
+ return mode;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/provider/BytestreamsProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/provider/BytestreamsProvider.java
index 76f9b0c66..fca8b27d1 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/provider/BytestreamsProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/bytestreams/socks5/provider/BytestreamsProvider.java
@@ -1,82 +1,82 @@
-/**
- * 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.bytestreams.socks5.provider;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Parses a bytestream packet.
- *
- * @author Alexander Wenckus
- */
-public class BytestreamsProvider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- boolean done = false;
-
- Bytestream toReturn = new Bytestream();
-
- String id = parser.getAttributeValue("", "sid");
- String mode = parser.getAttributeValue("", "mode");
-
- // streamhost
- String JID = null;
- String host = null;
- String port = null;
-
- int eventType;
- String elementName;
- while (!done) {
- eventType = parser.next();
- elementName = parser.getName();
- if (eventType == XmlPullParser.START_TAG) {
- if (elementName.equals(Bytestream.StreamHost.ELEMENTNAME)) {
- JID = parser.getAttributeValue("", "jid");
- host = parser.getAttributeValue("", "host");
- port = parser.getAttributeValue("", "port");
- }
- else if (elementName.equals(Bytestream.StreamHostUsed.ELEMENTNAME)) {
- toReturn.setUsedHost(parser.getAttributeValue("", "jid"));
- }
- else if (elementName.equals(Bytestream.Activate.ELEMENTNAME)) {
- toReturn.setToActivate(parser.getAttributeValue("", "jid"));
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (elementName.equals("streamhost")) {
- if (port == null) {
- toReturn.addStreamHost(JID, host);
- }
- else {
- toReturn.addStreamHost(JID, host, Integer.parseInt(port));
- }
- JID = null;
- host = null;
- port = null;
- }
- else if (elementName.equals("query")) {
- done = true;
- }
- }
- }
-
- toReturn.setMode((Bytestream.Mode.fromName(mode)));
- toReturn.setSessionID(id);
- return toReturn;
- }
-
-}
+/**
+ * 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.bytestreams.socks5.provider;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses a bytestream packet.
+ *
+ * @author Alexander Wenckus
+ */
+public class BytestreamsProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ boolean done = false;
+
+ Bytestream toReturn = new Bytestream();
+
+ String id = parser.getAttributeValue("", "sid");
+ String mode = parser.getAttributeValue("", "mode");
+
+ // streamhost
+ String JID = null;
+ String host = null;
+ String port = null;
+
+ int eventType;
+ String elementName;
+ while (!done) {
+ eventType = parser.next();
+ elementName = parser.getName();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (elementName.equals(Bytestream.StreamHost.ELEMENTNAME)) {
+ JID = parser.getAttributeValue("", "jid");
+ host = parser.getAttributeValue("", "host");
+ port = parser.getAttributeValue("", "port");
+ }
+ else if (elementName.equals(Bytestream.StreamHostUsed.ELEMENTNAME)) {
+ toReturn.setUsedHost(parser.getAttributeValue("", "jid"));
+ }
+ else if (elementName.equals(Bytestream.Activate.ELEMENTNAME)) {
+ toReturn.setToActivate(parser.getAttributeValue("", "jid"));
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (elementName.equals("streamhost")) {
+ if (port == null) {
+ toReturn.addStreamHost(JID, host);
+ }
+ else {
+ toReturn.addStreamHost(JID, host, Integer.parseInt(port));
+ }
+ JID = null;
+ host = null;
+ port = null;
+ }
+ else if (elementName.equals("query")) {
+ done = true;
+ }
+ }
+ }
+
+ toReturn.setMode((Bytestream.Mode.fromName(mode)));
+ toReturn.setSessionID(id);
+ return toReturn;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommand.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommand.java
index 3077d0892..6aa0110d9 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommand.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommand.java
@@ -1,450 +1,450 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2005-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
- *
- * 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.commands;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.packet.AdHocCommandData;
-
-import java.util.List;
-
-/**
- * An ad-hoc command is responsible for executing the provided service and
- * storing the result of the execution. Each new request will create a new
- * instance of the command, allowing information related to executions to be
- * stored in it. For example suppose that a command that retrieves the list of
- * users on a server is implemented. When the command is executed it gets that
- * list and the result is stored as a form in the command instance, i.e. the
- * <code>getForm</code> method retrieves a form with all the users.
- * <p>
- * Each command has a <tt>node</tt> that should be unique within a given JID.
- * <p>
- * Commands may have zero or more stages. Each stage is usually used for
- * gathering information required for the command execution. Users are able to
- * move forward or backward across the different stages. Commands may not be
- * cancelled while they are being executed. However, users may request the
- * "cancel" action when submitting a stage response indicating that the command
- * execution should be aborted. Thus, releasing any collected information.
- * Commands that require user interaction (i.e. have more than one stage) will
- * have to provide the data forms the user must complete in each stage and the
- * allowed actions the user might perform during each stage (e.g. go to the
- * previous stage or go to the next stage).
- * <p>
- * All the actions may throw an XMPPException if there is a problem executing
- * them. The <code>XMPPError</code> of that exception may have some specific
- * information about the problem. The possible extensions are:
- *
- * <li><i>malformed-action</i>. Extension of a <i>bad-request</i> error.</li>
- * <li><i>bad-action</i>. Extension of a <i>bad-request</i> error.</li>
- * <li><i>bad-locale</i>. Extension of a <i>bad-request</i> error.</li>
- * <li><i>bad-payload</i>. Extension of a <i>bad-request</i> error.</li>
- * <li><i>bad-sessionid</i>. Extension of a <i>bad-request</i> error.</li>
- * <li><i>session-expired</i>. Extension of a <i>not-allowed</i> error.</li>
- * <p>
- * See the <code>SpecificErrorCondition</code> class for detailed description
- * of each one.
- * <p>
- * Use the <code>getSpecificErrorConditionFrom</code> to obtain the specific
- * information from an <code>XMPPError</code>.
- *
- * @author Gabriel Guardincerri
- *
- */
-public abstract class AdHocCommand {
- // TODO: Analyze the redesign of command by having an ExecutionResponse as a
- // TODO: result to the execution of every action. That result should have all the
- // TODO: information related to the execution, e.g. the form to fill. Maybe this
- // TODO: design is more intuitive and simpler than the current one that has all in
- // TODO: one class.
-
- private AdHocCommandData data;
-
- public AdHocCommand() {
- super();
- data = new AdHocCommandData();
- }
-
- /**
- * Returns the specific condition of the <code>error</code> or <tt>null</tt> if the
- * error doesn't have any.
- *
- * @param error the error the get the specific condition from.
- * @return the specific condition of this error, or null if it doesn't have
- * any.
- */
- public static SpecificErrorCondition getSpecificErrorCondition(XMPPError error) {
- // This method is implemented to provide an easy way of getting a packet
- // extension of the XMPPError.
- for (SpecificErrorCondition condition : SpecificErrorCondition.values()) {
- if (error.getExtension(condition.toString(),
- AdHocCommandData.SpecificError.namespace) != null) {
- return condition;
- }
- }
- return null;
- }
-
- /**
- * Set the the human readable name of the command, usually used for
- * displaying in a UI.
- *
- * @param name the name.
- */
- public void setName(String name) {
- data.setName(name);
- }
-
- /**
- * Returns the human readable name of the command.
- *
- * @return the human readable name of the command
- */
- public String getName() {
- return data.getName();
- }
-
- /**
- * Sets the unique identifier of the command. This value must be unique for
- * the <code>OwnerJID</code>.
- *
- * @param node the unique identifier of the command.
- */
- public void setNode(String node) {
- data.setNode(node);
- }
-
- /**
- * Returns the unique identifier of the command. It is unique for the
- * <code>OwnerJID</code>.
- *
- * @return the unique identifier of the command.
- */
- public String getNode() {
- return data.getNode();
- }
-
- /**
- * Returns the full JID of the owner of this command. This JID is the "to" of a
- * execution request.
- *
- * @return the owner JID.
- */
- public abstract String getOwnerJID();
-
- /**
- * Returns the notes that the command has at the current stage.
- *
- * @return a list of notes.
- */
- public List<AdHocCommandNote> getNotes() {
- return data.getNotes();
- }
-
- /**
- * Adds a note to the current stage. This should be used when setting a
- * response to the execution of an action. All the notes added here are
- * returned by the {@link #getNotes} method during the current stage.
- * Once the stage changes all the notes are discarded.
- *
- * @param note the note.
- */
- protected void addNote(AdHocCommandNote note) {
- data.addNote(note);
- }
-
- public String getRaw() {
- return data.getChildElementXML();
- }
-
- /**
- * Returns the form of the current stage. Usually it is the form that must
- * be answered to execute the next action. If that is the case it should be
- * used by the requester to fill all the information that the executor needs
- * to continue to the next stage. It can also be the result of the
- * execution.
- *
- * @return the form of the current stage to fill out or the result of the
- * execution.
- */
- public Form getForm() {
- if (data.getForm() == null) {
- return null;
- }
- else {
- return new Form(data.getForm());
- }
- }
-
- /**
- * Sets the form of the current stage. This should be used when setting a
- * response. It could be a form to fill out the information needed to go to
- * the next stage or the result of an execution.
- *
- * @param form the form of the current stage to fill out or the result of the
- * execution.
- */
- protected void setForm(Form form) {
- data.setForm(form.getDataFormToSend());
- }
-
- /**
- * Executes the command. This is invoked only on the first stage of the
- * command. It is invoked on every command. If there is a problem executing
- * the command it throws an XMPPException.
- *
- * @throws XMPPException if there is an error executing the command.
- */
- public abstract void execute() throws XMPPException;
-
- /**
- * Executes the next action of the command with the information provided in
- * the <code>response</code>. This form must be the answer form of the
- * previous stage. This method will be only invoked for commands that have one
- * or more stages. If there is a problem executing the command it throws an
- * XMPPException.
- *
- * @param response the form answer of the previous stage.
- * @throws XMPPException if there is a problem executing the command.
- */
- public abstract void next(Form response) throws XMPPException;
-
- /**
- * Completes the command execution with the information provided in the
- * <code>response</code>. This form must be the answer form of the
- * previous stage. This method will be only invoked for commands that have one
- * or more stages. If there is a problem executing the command it throws an
- * XMPPException.
- *
- * @param response the form answer of the previous stage.
- * @throws XMPPException if there is a problem executing the command.
- */
- public abstract void complete(Form response) throws XMPPException;
-
- /**
- * Goes to the previous stage. The requester is asking to re-send the
- * information of the previous stage. The command must change it state to
- * the previous one. If there is a problem executing the command it throws
- * an XMPPException.
- *
- * @throws XMPPException if there is a problem executing the command.
- */
- public abstract void prev() throws XMPPException;
-
- /**
- * Cancels the execution of the command. This can be invoked on any stage of
- * the execution. If there is a problem executing the command it throws an
- * XMPPException.
- *
- * @throws XMPPException if there is a problem executing the command.
- */
- public abstract void cancel() throws XMPPException;
-
- /**
- * Returns a collection with the allowed actions based on the current stage.
- * Possible actions are: {@link Action#prev prev}, {@link Action#next next} and
- * {@link Action#complete complete}. This method will be only invoked for commands that
- * have one or more stages.
- *
- * @return a collection with the allowed actions based on the current stage
- * as defined in the SessionData.
- */
- protected List<Action> getActions() {
- return data.getActions();
- }
-
- /**
- * Add an action to the current stage available actions. This should be used
- * when creating a response.
- *
- * @param action the action.
- */
- protected void addActionAvailable(Action action) {
- data.addAction(action);
- }
-
- /**
- * Returns the action available for the current stage which is
- * considered the equivalent to "execute". When the requester sends his
- * reply, if no action was defined in the command then the action will be
- * assumed "execute" thus assuming the action returned by this method. This
- * method will never be invoked for commands that have no stages.
- *
- * @return the action available for the current stage which is considered
- * the equivalent to "execute".
- */
- protected Action getExecuteAction() {
- return data.getExecuteAction();
- }
-
- /**
- * Sets which of the actions available for the current stage is
- * considered the equivalent to "execute". This should be used when setting
- * a response. When the requester sends his reply, if no action was defined
- * in the command then the action will be assumed "execute" thus assuming
- * the action returned by this method.
- *
- * @param action the action.
- */
- protected void setExecuteAction(Action action) {
- data.setExecuteAction(action);
- }
-
- /**
- * Returns the status of the current stage.
- *
- * @return the current status.
- */
- public Status getStatus() {
- return data.getStatus();
- }
-
- /**
- * Sets the data of the current stage. This should not used.
- *
- * @param data the data.
- */
- void setData(AdHocCommandData data) {
- this.data = data;
- }
-
- /**
- * Gets the data of the current stage. This should not used.
- *
- * @return the data.
- */
- AdHocCommandData getData() {
- return data;
- }
-
- /**
- * Returns true if the <code>action</code> is available in the current stage.
- * The {@link Action#cancel cancel} action is always allowed. To define the
- * available actions use the <code>addActionAvailable</code> method.
- *
- * @param action
- * The action to check if it is available.
- * @return True if the action is available for the current stage.
- */
- protected boolean isValidAction(Action action) {
- return getActions().contains(action) || Action.cancel.equals(action);
- }
-
- /**
- * The status of the stage in the adhoc command.
- */
- public enum Status {
-
- /**
- * The command is being executed.
- */
- executing,
-
- /**
- * The command has completed. The command session has ended.
- */
- completed,
-
- /**
- * The command has been canceled. The command session has ended.
- */
- canceled
- }
-
- public enum Action {
-
- /**
- * The command should be executed or continue to be executed. This is
- * the default value.
- */
- execute,
-
- /**
- * The command should be canceled.
- */
- cancel,
-
- /**
- * The command should be digress to the previous stage of execution.
- */
- prev,
-
- /**
- * The command should progress to the next stage of execution.
- */
- next,
-
- /**
- * The command should be completed (if possible).
- */
- complete,
-
- /**
- * The action is unknow. This is used when a recieved message has an
- * unknown action. It must not be used to send an execution request.
- */
- unknown
- }
-
- public enum SpecificErrorCondition {
-
- /**
- * The responding JID cannot accept the specified action.
- */
- badAction("bad-action"),
-
- /**
- * The responding JID does not understand the specified action.
- */
- malformedAction("malformed-action"),
-
- /**
- * The responding JID cannot accept the specified language/locale.
- */
- badLocale("bad-locale"),
-
- /**
- * The responding JID cannot accept the specified payload (e.g. the data
- * form did not provide one or more required fields).
- */
- badPayload("bad-payload"),
-
- /**
- * The responding JID cannot accept the specified sessionid.
- */
- badSessionid("bad-sessionid"),
-
- /**
- * The requesting JID specified a sessionid that is no longer active
- * (either because it was completed, canceled, or timed out).
- */
- sessionExpired("session-expired");
-
- private String value;
-
- SpecificErrorCondition(String value) {
- this.value = value;
- }
-
- public String toString() {
- return value;
- }
- }
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2005-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
+ *
+ * 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.commands;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.packet.AdHocCommandData;
+
+import java.util.List;
+
+/**
+ * An ad-hoc command is responsible for executing the provided service and
+ * storing the result of the execution. Each new request will create a new
+ * instance of the command, allowing information related to executions to be
+ * stored in it. For example suppose that a command that retrieves the list of
+ * users on a server is implemented. When the command is executed it gets that
+ * list and the result is stored as a form in the command instance, i.e. the
+ * <code>getForm</code> method retrieves a form with all the users.
+ * <p>
+ * Each command has a <tt>node</tt> that should be unique within a given JID.
+ * <p>
+ * Commands may have zero or more stages. Each stage is usually used for
+ * gathering information required for the command execution. Users are able to
+ * move forward or backward across the different stages. Commands may not be
+ * cancelled while they are being executed. However, users may request the
+ * "cancel" action when submitting a stage response indicating that the command
+ * execution should be aborted. Thus, releasing any collected information.
+ * Commands that require user interaction (i.e. have more than one stage) will
+ * have to provide the data forms the user must complete in each stage and the
+ * allowed actions the user might perform during each stage (e.g. go to the
+ * previous stage or go to the next stage).
+ * <p>
+ * All the actions may throw an XMPPException if there is a problem executing
+ * them. The <code>XMPPError</code> of that exception may have some specific
+ * information about the problem. The possible extensions are:
+ *
+ * <li><i>malformed-action</i>. Extension of a <i>bad-request</i> error.</li>
+ * <li><i>bad-action</i>. Extension of a <i>bad-request</i> error.</li>
+ * <li><i>bad-locale</i>. Extension of a <i>bad-request</i> error.</li>
+ * <li><i>bad-payload</i>. Extension of a <i>bad-request</i> error.</li>
+ * <li><i>bad-sessionid</i>. Extension of a <i>bad-request</i> error.</li>
+ * <li><i>session-expired</i>. Extension of a <i>not-allowed</i> error.</li>
+ * <p>
+ * See the <code>SpecificErrorCondition</code> class for detailed description
+ * of each one.
+ * <p>
+ * Use the <code>getSpecificErrorConditionFrom</code> to obtain the specific
+ * information from an <code>XMPPError</code>.
+ *
+ * @author Gabriel Guardincerri
+ *
+ */
+public abstract class AdHocCommand {
+ // TODO: Analyze the redesign of command by having an ExecutionResponse as a
+ // TODO: result to the execution of every action. That result should have all the
+ // TODO: information related to the execution, e.g. the form to fill. Maybe this
+ // TODO: design is more intuitive and simpler than the current one that has all in
+ // TODO: one class.
+
+ private AdHocCommandData data;
+
+ public AdHocCommand() {
+ super();
+ data = new AdHocCommandData();
+ }
+
+ /**
+ * Returns the specific condition of the <code>error</code> or <tt>null</tt> if the
+ * error doesn't have any.
+ *
+ * @param error the error the get the specific condition from.
+ * @return the specific condition of this error, or null if it doesn't have
+ * any.
+ */
+ public static SpecificErrorCondition getSpecificErrorCondition(XMPPError error) {
+ // This method is implemented to provide an easy way of getting a packet
+ // extension of the XMPPError.
+ for (SpecificErrorCondition condition : SpecificErrorCondition.values()) {
+ if (error.getExtension(condition.toString(),
+ AdHocCommandData.SpecificError.namespace) != null) {
+ return condition;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Set the the human readable name of the command, usually used for
+ * displaying in a UI.
+ *
+ * @param name the name.
+ */
+ public void setName(String name) {
+ data.setName(name);
+ }
+
+ /**
+ * Returns the human readable name of the command.
+ *
+ * @return the human readable name of the command
+ */
+ public String getName() {
+ return data.getName();
+ }
+
+ /**
+ * Sets the unique identifier of the command. This value must be unique for
+ * the <code>OwnerJID</code>.
+ *
+ * @param node the unique identifier of the command.
+ */
+ public void setNode(String node) {
+ data.setNode(node);
+ }
+
+ /**
+ * Returns the unique identifier of the command. It is unique for the
+ * <code>OwnerJID</code>.
+ *
+ * @return the unique identifier of the command.
+ */
+ public String getNode() {
+ return data.getNode();
+ }
+
+ /**
+ * Returns the full JID of the owner of this command. This JID is the "to" of a
+ * execution request.
+ *
+ * @return the owner JID.
+ */
+ public abstract String getOwnerJID();
+
+ /**
+ * Returns the notes that the command has at the current stage.
+ *
+ * @return a list of notes.
+ */
+ public List<AdHocCommandNote> getNotes() {
+ return data.getNotes();
+ }
+
+ /**
+ * Adds a note to the current stage. This should be used when setting a
+ * response to the execution of an action. All the notes added here are
+ * returned by the {@link #getNotes} method during the current stage.
+ * Once the stage changes all the notes are discarded.
+ *
+ * @param note the note.
+ */
+ protected void addNote(AdHocCommandNote note) {
+ data.addNote(note);
+ }
+
+ public String getRaw() {
+ return data.getChildElementXML();
+ }
+
+ /**
+ * Returns the form of the current stage. Usually it is the form that must
+ * be answered to execute the next action. If that is the case it should be
+ * used by the requester to fill all the information that the executor needs
+ * to continue to the next stage. It can also be the result of the
+ * execution.
+ *
+ * @return the form of the current stage to fill out or the result of the
+ * execution.
+ */
+ public Form getForm() {
+ if (data.getForm() == null) {
+ return null;
+ }
+ else {
+ return new Form(data.getForm());
+ }
+ }
+
+ /**
+ * Sets the form of the current stage. This should be used when setting a
+ * response. It could be a form to fill out the information needed to go to
+ * the next stage or the result of an execution.
+ *
+ * @param form the form of the current stage to fill out or the result of the
+ * execution.
+ */
+ protected void setForm(Form form) {
+ data.setForm(form.getDataFormToSend());
+ }
+
+ /**
+ * Executes the command. This is invoked only on the first stage of the
+ * command. It is invoked on every command. If there is a problem executing
+ * the command it throws an XMPPException.
+ *
+ * @throws XMPPException if there is an error executing the command.
+ */
+ public abstract void execute() throws XMPPException;
+
+ /**
+ * Executes the next action of the command with the information provided in
+ * the <code>response</code>. This form must be the answer form of the
+ * previous stage. This method will be only invoked for commands that have one
+ * or more stages. If there is a problem executing the command it throws an
+ * XMPPException.
+ *
+ * @param response the form answer of the previous stage.
+ * @throws XMPPException if there is a problem executing the command.
+ */
+ public abstract void next(Form response) throws XMPPException;
+
+ /**
+ * Completes the command execution with the information provided in the
+ * <code>response</code>. This form must be the answer form of the
+ * previous stage. This method will be only invoked for commands that have one
+ * or more stages. If there is a problem executing the command it throws an
+ * XMPPException.
+ *
+ * @param response the form answer of the previous stage.
+ * @throws XMPPException if there is a problem executing the command.
+ */
+ public abstract void complete(Form response) throws XMPPException;
+
+ /**
+ * Goes to the previous stage. The requester is asking to re-send the
+ * information of the previous stage. The command must change it state to
+ * the previous one. If there is a problem executing the command it throws
+ * an XMPPException.
+ *
+ * @throws XMPPException if there is a problem executing the command.
+ */
+ public abstract void prev() throws XMPPException;
+
+ /**
+ * Cancels the execution of the command. This can be invoked on any stage of
+ * the execution. If there is a problem executing the command it throws an
+ * XMPPException.
+ *
+ * @throws XMPPException if there is a problem executing the command.
+ */
+ public abstract void cancel() throws XMPPException;
+
+ /**
+ * Returns a collection with the allowed actions based on the current stage.
+ * Possible actions are: {@link Action#prev prev}, {@link Action#next next} and
+ * {@link Action#complete complete}. This method will be only invoked for commands that
+ * have one or more stages.
+ *
+ * @return a collection with the allowed actions based on the current stage
+ * as defined in the SessionData.
+ */
+ protected List<Action> getActions() {
+ return data.getActions();
+ }
+
+ /**
+ * Add an action to the current stage available actions. This should be used
+ * when creating a response.
+ *
+ * @param action the action.
+ */
+ protected void addActionAvailable(Action action) {
+ data.addAction(action);
+ }
+
+ /**
+ * Returns the action available for the current stage which is
+ * considered the equivalent to "execute". When the requester sends his
+ * reply, if no action was defined in the command then the action will be
+ * assumed "execute" thus assuming the action returned by this method. This
+ * method will never be invoked for commands that have no stages.
+ *
+ * @return the action available for the current stage which is considered
+ * the equivalent to "execute".
+ */
+ protected Action getExecuteAction() {
+ return data.getExecuteAction();
+ }
+
+ /**
+ * Sets which of the actions available for the current stage is
+ * considered the equivalent to "execute". This should be used when setting
+ * a response. When the requester sends his reply, if no action was defined
+ * in the command then the action will be assumed "execute" thus assuming
+ * the action returned by this method.
+ *
+ * @param action the action.
+ */
+ protected void setExecuteAction(Action action) {
+ data.setExecuteAction(action);
+ }
+
+ /**
+ * Returns the status of the current stage.
+ *
+ * @return the current status.
+ */
+ public Status getStatus() {
+ return data.getStatus();
+ }
+
+ /**
+ * Sets the data of the current stage. This should not used.
+ *
+ * @param data the data.
+ */
+ void setData(AdHocCommandData data) {
+ this.data = data;
+ }
+
+ /**
+ * Gets the data of the current stage. This should not used.
+ *
+ * @return the data.
+ */
+ AdHocCommandData getData() {
+ return data;
+ }
+
+ /**
+ * Returns true if the <code>action</code> is available in the current stage.
+ * The {@link Action#cancel cancel} action is always allowed. To define the
+ * available actions use the <code>addActionAvailable</code> method.
+ *
+ * @param action
+ * The action to check if it is available.
+ * @return True if the action is available for the current stage.
+ */
+ protected boolean isValidAction(Action action) {
+ return getActions().contains(action) || Action.cancel.equals(action);
+ }
+
+ /**
+ * The status of the stage in the adhoc command.
+ */
+ public enum Status {
+
+ /**
+ * The command is being executed.
+ */
+ executing,
+
+ /**
+ * The command has completed. The command session has ended.
+ */
+ completed,
+
+ /**
+ * The command has been canceled. The command session has ended.
+ */
+ canceled
+ }
+
+ public enum Action {
+
+ /**
+ * The command should be executed or continue to be executed. This is
+ * the default value.
+ */
+ execute,
+
+ /**
+ * The command should be canceled.
+ */
+ cancel,
+
+ /**
+ * The command should be digress to the previous stage of execution.
+ */
+ prev,
+
+ /**
+ * The command should progress to the next stage of execution.
+ */
+ next,
+
+ /**
+ * The command should be completed (if possible).
+ */
+ complete,
+
+ /**
+ * The action is unknow. This is used when a recieved message has an
+ * unknown action. It must not be used to send an execution request.
+ */
+ unknown
+ }
+
+ public enum SpecificErrorCondition {
+
+ /**
+ * The responding JID cannot accept the specified action.
+ */
+ badAction("bad-action"),
+
+ /**
+ * The responding JID does not understand the specified action.
+ */
+ malformedAction("malformed-action"),
+
+ /**
+ * The responding JID cannot accept the specified language/locale.
+ */
+ badLocale("bad-locale"),
+
+ /**
+ * The responding JID cannot accept the specified payload (e.g. the data
+ * form did not provide one or more required fields).
+ */
+ badPayload("bad-payload"),
+
+ /**
+ * The responding JID cannot accept the specified sessionid.
+ */
+ badSessionid("bad-sessionid"),
+
+ /**
+ * The requesting JID specified a sessionid that is no longer active
+ * (either because it was completed, canceled, or timed out).
+ */
+ sessionExpired("session-expired");
+
+ private String value;
+
+ SpecificErrorCondition(String value) {
+ this.value = value;
+ }
+
+ public String toString() {
+ return value;
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandManager.java
index 8f4eb65c5..737a204ab 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandManager.java
@@ -1,750 +1,750 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2005-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.
- * 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.commands;
-
-import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.NodeInformationProvider;
-import org.jivesoftware.smackx.ServiceDiscoveryManager;
-import org.jivesoftware.smackx.commands.AdHocCommand.Action;
-import org.jivesoftware.smackx.commands.AdHocCommand.Status;
-import org.jivesoftware.smackx.packet.AdHocCommandData;
-import org.jivesoftware.smackx.packet.DiscoverInfo;
-import org.jivesoftware.smackx.packet.DiscoverInfo.Identity;
-import org.jivesoftware.smackx.packet.DiscoverItems;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * An AdHocCommandManager is responsible for keeping the list of available
- * commands offered by a service and for processing commands requests.
- *
- * Pass in a Connection instance to
- * {@link #getAddHocCommandsManager(org.jivesoftware.smack.Connection)} in order to
- * get an instance of this class.
- *
- * @author Gabriel Guardincerri
- */
-public class AdHocCommandManager {
-
- private static final String DISCO_NAMESPACE = "http://jabber.org/protocol/commands";
-
- private static final String discoNode = DISCO_NAMESPACE;
-
- /**
- * The session time out in seconds.
- */
- private static final int SESSION_TIMEOUT = 2 * 60;
-
- /**
- * Map a Connection with it AdHocCommandManager. This map have a key-value
- * pair for every active connection.
- */
- private static Map<Connection, AdHocCommandManager> instances =
- new ConcurrentHashMap<Connection, AdHocCommandManager>();
-
- /**
- * Register the listener for all the connection creations. When a new
- * connection is created a new AdHocCommandManager is also created and
- * related to that connection.
- */
- static {
- Connection.addConnectionCreationListener(new ConnectionCreationListener() {
- public void connectionCreated(Connection connection) {
- new AdHocCommandManager(connection);
- }
- });
- }
-
- /**
- * Returns the <code>AdHocCommandManager</code> related to the
- * <code>connection</code>.
- *
- * @param connection the XMPP connection.
- * @return the AdHocCommandManager associated with the connection.
- */
- public static AdHocCommandManager getAddHocCommandsManager(Connection connection) {
- return instances.get(connection);
- }
-
- /**
- * Thread that reaps stale sessions.
- */
- private Thread sessionsSweeper;
-
- /**
- * The Connection that this instances of AdHocCommandManager manages
- */
- private Connection connection;
-
- /**
- * Map a command node with its AdHocCommandInfo. Note: Key=command node,
- * Value=command. Command node matches the node attribute sent by command
- * requesters.
- */
- private Map<String, AdHocCommandInfo> commands = new ConcurrentHashMap<String, AdHocCommandInfo>();
-
- /**
- * Map a command session ID with the instance LocalCommand. The LocalCommand
- * is the an objects that has all the information of the current state of
- * the command execution. Note: Key=session ID, Value=LocalCommand. Session
- * ID matches the sessionid attribute sent by command responders.
- */
- private Map<String, LocalCommand> executingCommands = new ConcurrentHashMap<String, LocalCommand>();
-
- private AdHocCommandManager(Connection connection) {
- super();
- this.connection = connection;
- init();
- }
-
- /**
- * Registers a new command with this command manager, which is related to a
- * connection. The <tt>node</tt> is an unique identifier of that command for
- * the connection related to this command manager. The <tt>name</tt> is the
- * human readable name of the command. The <tt>class</tt> is the class of
- * the command, which must extend {@link LocalCommand} and have a default
- * constructor.
- *
- * @param node the unique identifier of the command.
- * @param name the human readable name of the command.
- * @param clazz the class of the command, which must extend {@link LocalCommand}.
- */
- public void registerCommand(String node, String name, final Class<? extends LocalCommand> clazz) {
- registerCommand(node, name, new LocalCommandFactory() {
- public LocalCommand getInstance() throws InstantiationException, IllegalAccessException {
- return clazz.newInstance();
- }
- });
- }
-
- /**
- * Registers a new command with this command manager, which is related to a
- * connection. The <tt>node</tt> is an unique identifier of that
- * command for the connection related to this command manager. The <tt>name</tt>
- * is the human readeale name of the command. The <tt>factory</tt> generates
- * new instances of the command.
- *
- * @param node the unique identifier of the command.
- * @param name the human readable name of the command.
- * @param factory a factory to create new instances of the command.
- */
- public void registerCommand(String node, final String name, LocalCommandFactory factory) {
- AdHocCommandInfo commandInfo = new AdHocCommandInfo(node, name, connection.getUser(), factory);
-
- commands.put(node, commandInfo);
- // Set the NodeInformationProvider that will provide information about
- // the added command
- ServiceDiscoveryManager.getInstanceFor(connection).setNodeInformationProvider(node,
- new NodeInformationProvider() {
- public List<DiscoverItems.Item> getNodeItems() {
- return null;
- }
-
- public List<String> getNodeFeatures() {
- List<String> answer = new ArrayList<String>();
- answer.add(DISCO_NAMESPACE);
- // TODO: check if this service is provided by the
- // TODO: current connection.
- answer.add("jabber:x:data");
- return answer;
- }
-
- public List<DiscoverInfo.Identity> getNodeIdentities() {
- List<DiscoverInfo.Identity> answer = new ArrayList<DiscoverInfo.Identity>();
- DiscoverInfo.Identity identity = new DiscoverInfo.Identity(
- "automation", name, "command-node");
- answer.add(identity);
- return answer;
- }
-
- @Override
- public List<PacketExtension> getNodePacketExtensions() {
- return null;
- }
-
- });
- }
-
- /**
- * Discover the commands of an specific JID. The <code>jid</code> is a
- * full JID.
- *
- * @param jid the full JID to retrieve the commands for.
- * @return the discovered items.
- * @throws XMPPException if the operation failed for some reason.
- */
- public DiscoverItems discoverCommands(String jid) throws XMPPException {
- ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager
- .getInstanceFor(connection);
- return serviceDiscoveryManager.discoverItems(jid, discoNode);
- }
-
- /**
- * Publish the commands to an specific JID.
- *
- * @param jid the full JID to publish the commands to.
- * @throws XMPPException if the operation failed for some reason.
- */
- public void publishCommands(String jid) throws XMPPException {
- ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager
- .getInstanceFor(connection);
-
- // Collects the commands to publish as items
- DiscoverItems discoverItems = new DiscoverItems();
- Collection<AdHocCommandInfo> xCommandsList = getRegisteredCommands();
-
- for (AdHocCommandInfo info : xCommandsList) {
- DiscoverItems.Item item = new DiscoverItems.Item(info.getOwnerJID());
- item.setName(info.getName());
- item.setNode(info.getNode());
- discoverItems.addItem(item);
- }
-
- serviceDiscoveryManager.publishItems(jid, discoNode, discoverItems);
- }
-
- /**
- * Returns a command that represents an instance of a command in a remote
- * host. It is used to execute remote commands. The concept is similar to
- * RMI. Every invocation on this command is equivalent to an invocation in
- * the remote command.
- *
- * @param jid the full JID of the host of the remote command
- * @param node the identifier of the command
- * @return a local instance equivalent to the remote command.
- */
- public RemoteCommand getRemoteCommand(String jid, String node) {
- return new RemoteCommand(connection, node, jid);
- }
-
- /**
- * <ul>
- * <li>Adds listeners to the connection</li>
- * <li>Registers the ad-hoc command feature to the ServiceDiscoveryManager</li>
- * <li>Registers the items of the feature</li>
- * <li>Adds packet listeners to handle execution requests</li>
- * <li>Creates and start the session sweeper</li>
- * </ul>
- */
- private void init() {
- // Register the new instance and associate it with the connection
- instances.put(connection, this);
-
- // Add a listener to the connection that removes the registered instance
- // when the connection is closed
- connection.addConnectionListener(new ConnectionListener() {
- public void connectionClosed() {
- // Unregister this instance since the connection has been closed
- instances.remove(connection);
- }
-
- public void connectionClosedOnError(Exception e) {
- // Unregister this instance since the connection has been closed
- instances.remove(connection);
- }
-
- public void reconnectionSuccessful() {
- // Register this instance since the connection has been
- // reestablished
- instances.put(connection, AdHocCommandManager.this);
- }
-
- public void reconnectingIn(int seconds) {
- // Nothing to do
- }
-
- public void reconnectionFailed(Exception e) {
- // Nothing to do
- }
- });
-
- // Add the feature to the service discovery manage to show that this
- // connection supports the AdHoc-Commands protocol.
- // This information will be used when another client tries to
- // discover whether this client supports AdHoc-Commands or not.
- ServiceDiscoveryManager.getInstanceFor(connection).addFeature(
- DISCO_NAMESPACE);
-
- // Set the NodeInformationProvider that will provide information about
- // which AdHoc-Commands are registered, whenever a disco request is
- // received
- ServiceDiscoveryManager.getInstanceFor(connection)
- .setNodeInformationProvider(discoNode,
- new NodeInformationProvider() {
- public List<DiscoverItems.Item> getNodeItems() {
-
- List<DiscoverItems.Item> answer = new ArrayList<DiscoverItems.Item>();
- Collection<AdHocCommandInfo> commandsList = getRegisteredCommands();
-
- for (AdHocCommandInfo info : commandsList) {
- DiscoverItems.Item item = new DiscoverItems.Item(
- info.getOwnerJID());
- item.setName(info.getName());
- item.setNode(info.getNode());
- answer.add(item);
- }
-
- return answer;
- }
-
- public List<String> getNodeFeatures() {
- return null;
- }
-
- public List<Identity> getNodeIdentities() {
- return null;
- }
-
- @Override
- public List<PacketExtension> getNodePacketExtensions() {
- return null;
- }
- });
-
- // The packet listener and the filter for processing some AdHoc Commands
- // Packets
- PacketListener listener = new PacketListener() {
- public void processPacket(Packet packet) {
- AdHocCommandData requestData = (AdHocCommandData) packet;
- processAdHocCommand(requestData);
- }
- };
-
- PacketFilter filter = new PacketTypeFilter(AdHocCommandData.class);
- connection.addPacketListener(listener, filter);
-
- sessionsSweeper = null;
- }
-
- /**
- * Process the AdHoc-Command packet that request the execution of some
- * action of a command. If this is the first request, this method checks,
- * before executing the command, if:
- * <ul>
- * <li>The requested command exists</li>
- * <li>The requester has permissions to execute it</li>
- * <li>The command has more than one stage, if so, it saves the command and
- * session ID for further use</li>
- * </ul>
- *
- * <br>
- * <br>
- * If this is not the first request, this method checks, before executing
- * the command, if:
- * <ul>
- * <li>The session ID of the request was stored</li>
- * <li>The session life do not exceed the time out</li>
- * <li>The action to execute is one of the available actions</li>
- * </ul>
- *
- * @param requestData
- * the packet to process.
- */
- private void processAdHocCommand(AdHocCommandData requestData) {
- // Only process requests of type SET
- if (requestData.getType() != IQ.Type.SET) {
- return;
- }
-
- // Creates the response with the corresponding data
- AdHocCommandData response = new AdHocCommandData();
- response.setTo(requestData.getFrom());
- response.setPacketID(requestData.getPacketID());
- response.setNode(requestData.getNode());
- response.setId(requestData.getTo());
-
- String sessionId = requestData.getSessionID();
- String commandNode = requestData.getNode();
-
- if (sessionId == null) {
- // A new execution request has been received. Check that the
- // command exists
- if (!commands.containsKey(commandNode)) {
- // Requested command does not exist so return
- // item_not_found error.
- respondError(response, XMPPError.Condition.item_not_found);
- return;
- }
-
- // Create new session ID
- sessionId = StringUtils.randomString(15);
-
- try {
- // Create a new instance of the command with the
- // corresponding sessioid
- LocalCommand command = newInstanceOfCmd(commandNode, sessionId);
-
- response.setType(IQ.Type.RESULT);
- command.setData(response);
-
- // Check that the requester has enough permission.
- // Answer forbidden error if requester permissions are not
- // enough to execute the requested command
- if (!command.hasPermission(requestData.getFrom())) {
- respondError(response, XMPPError.Condition.forbidden);
- return;
- }
-
- Action action = requestData.getAction();
-
- // If the action is unknown then respond an error.
- if (action != null && action.equals(Action.unknown)) {
- respondError(response, XMPPError.Condition.bad_request,
- AdHocCommand.SpecificErrorCondition.malformedAction);
- return;
- }
-
- // If the action is not execute, then it is an invalid action.
- if (action != null && !action.equals(Action.execute)) {
- respondError(response, XMPPError.Condition.bad_request,
- AdHocCommand.SpecificErrorCondition.badAction);
- return;
- }
-
- // Increase the state number, so the command knows in witch
- // stage it is
- command.incrementStage();
- // Executes the command
- command.execute();
-
- if (command.isLastStage()) {
- // If there is only one stage then the command is completed
- response.setStatus(Status.completed);
- }
- else {
- // Else it is still executing, and is registered to be
- // available for the next call
- response.setStatus(Status.executing);
- executingCommands.put(sessionId, command);
- // See if the session reaping thread is started. If not, start it.
- if (sessionsSweeper == null) {
- sessionsSweeper = new Thread(new Runnable() {
- public void run() {
- while (true) {
- for (String sessionId : executingCommands.keySet()) {
- LocalCommand command = executingCommands.get(sessionId);
- // Since the command could be removed in the meanwhile
- // of getting the key and getting the value - by a
- // processed packet. We must check if it still in the
- // map.
- if (command != null) {
- long creationStamp = command.getCreationDate();
- // Check if the Session data has expired (default is
- // 10 minutes)
- // To remove it from the session list it waits for
- // the double of the of time out time. This is to
- // let
- // the requester know why his execution request is
- // not accepted. If the session is removed just
- // after the time out, then whe the user request to
- // continue the execution he will recieved an
- // invalid session error and not a time out error.
- if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000 * 2) {
- // Remove the expired session
- executingCommands.remove(sessionId);
- }
- }
- }
- try {
- Thread.sleep(1000);
- }
- catch (InterruptedException ie) {
- // Ignore.
- }
- }
- }
-
- });
- sessionsSweeper.setDaemon(true);
- sessionsSweeper.start();
- }
- }
-
- // Sends the response packet
- connection.sendPacket(response);
-
- }
- catch (XMPPException e) {
- // If there is an exception caused by the next, complete,
- // prev or cancel method, then that error is returned to the
- // requester.
- XMPPError error = e.getXMPPError();
-
- // If the error type is cancel, then the execution is
- // canceled therefore the status must show that, and the
- // command be removed from the executing list.
- if (XMPPError.Type.CANCEL.equals(error.getType())) {
- response.setStatus(Status.canceled);
- executingCommands.remove(sessionId);
- }
- respondError(response, error);
- e.printStackTrace();
- }
- }
- else {
- LocalCommand command = executingCommands.get(sessionId);
-
- // Check that a command exists for the specified sessionID
- // This also handles if the command was removed in the meanwhile
- // of getting the key and the value of the map.
- if (command == null) {
- respondError(response, XMPPError.Condition.bad_request,
- AdHocCommand.SpecificErrorCondition.badSessionid);
- return;
- }
-
- // Check if the Session data has expired (default is 10 minutes)
- long creationStamp = command.getCreationDate();
- if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000) {
- // Remove the expired session
- executingCommands.remove(sessionId);
-
- // Answer a not_allowed error (session-expired)
- respondError(response, XMPPError.Condition.not_allowed,
- AdHocCommand.SpecificErrorCondition.sessionExpired);
- return;
- }
-
- /*
- * Since the requester could send two requests for the same
- * executing command i.e. the same session id, all the execution of
- * the action must be synchronized to avoid inconsistencies.
- */
- synchronized (command) {
- Action action = requestData.getAction();
-
- // If the action is unknown the respond an error
- if (action != null && action.equals(Action.unknown)) {
- respondError(response, XMPPError.Condition.bad_request,
- AdHocCommand.SpecificErrorCondition.malformedAction);
- return;
- }
-
- // If the user didn't specify an action or specify the execute
- // action then follow the actual default execute action
- if (action == null || Action.execute.equals(action)) {
- action = command.getExecuteAction();
- }
-
- // Check that the specified action was previously
- // offered
- if (!command.isValidAction(action)) {
- respondError(response, XMPPError.Condition.bad_request,
- AdHocCommand.SpecificErrorCondition.badAction);
- return;
- }
-
- try {
- // TODO: Check that all the requierd fields of the form are
- // TODO: filled, if not throw an exception. This will simplify the
- // TODO: construction of new commands
-
- // Since all errors were passed, the response is now a
- // result
- response.setType(IQ.Type.RESULT);
-
- // Set the new data to the command.
- command.setData(response);
-
- if (Action.next.equals(action)) {
- command.incrementStage();
- command.next(new Form(requestData.getForm()));
- if (command.isLastStage()) {
- // If it is the last stage then the command is
- // completed
- response.setStatus(Status.completed);
- }
- else {
- // Otherwise it is still executing
- response.setStatus(Status.executing);
- }
- }
- else if (Action.complete.equals(action)) {
- command.incrementStage();
- command.complete(new Form(requestData.getForm()));
- response.setStatus(Status.completed);
- // Remove the completed session
- executingCommands.remove(sessionId);
- }
- else if (Action.prev.equals(action)) {
- command.decrementStage();
- command.prev();
- }
- else if (Action.cancel.equals(action)) {
- command.cancel();
- response.setStatus(Status.canceled);
- // Remove the canceled session
- executingCommands.remove(sessionId);
- }
-
- connection.sendPacket(response);
- }
- catch (XMPPException e) {
- // If there is an exception caused by the next, complete,
- // prev or cancel method, then that error is returned to the
- // requester.
- XMPPError error = e.getXMPPError();
-
- // If the error type is cancel, then the execution is
- // canceled therefore the status must show that, and the
- // command be removed from the executing list.
- if (XMPPError.Type.CANCEL.equals(error.getType())) {
- response.setStatus(Status.canceled);
- executingCommands.remove(sessionId);
- }
- respondError(response, error);
-
- e.printStackTrace();
- }
- }
- }
- }
-
- /**
- * Responds an error with an specific condition.
- *
- * @param response the response to send.
- * @param condition the condition of the error.
- */
- private void respondError(AdHocCommandData response,
- XMPPError.Condition condition) {
- respondError(response, new XMPPError(condition));
- }
-
- /**
- * Responds an error with an specific condition.
- *
- * @param response the response to send.
- * @param condition the condition of the error.
- * @param specificCondition the adhoc command error condition.
- */
- private void respondError(AdHocCommandData response, XMPPError.Condition condition,
- AdHocCommand.SpecificErrorCondition specificCondition)
- {
- XMPPError error = new XMPPError(condition);
- error.addExtension(new AdHocCommandData.SpecificError(specificCondition));
- respondError(response, error);
- }
-
- /**
- * Responds an error with an specific error.
- *
- * @param response the response to send.
- * @param error the error to send.
- */
- private void respondError(AdHocCommandData response, XMPPError error) {
- response.setType(IQ.Type.ERROR);
- response.setError(error);
- connection.sendPacket(response);
- }
-
- /**
- * Creates a new instance of a command to be used by a new execution request
- *
- * @param commandNode the command node that identifies it.
- * @param sessionID the session id of this execution.
- * @return the command instance to execute.
- * @throws XMPPException if there is problem creating the new instance.
- */
- private LocalCommand newInstanceOfCmd(String commandNode, String sessionID)
- throws XMPPException
- {
- AdHocCommandInfo commandInfo = commands.get(commandNode);
- LocalCommand command;
- try {
- command = (LocalCommand) commandInfo.getCommandInstance();
- command.setSessionID(sessionID);
- command.setName(commandInfo.getName());
- command.setNode(commandInfo.getNode());
- }
- catch (InstantiationException e) {
- e.printStackTrace();
- throw new XMPPException(new XMPPError(
- XMPPError.Condition.interna_server_error));
- }
- catch (IllegalAccessException e) {
- e.printStackTrace();
- throw new XMPPException(new XMPPError(
- XMPPError.Condition.interna_server_error));
- }
- return command;
- }
-
- /**
- * Returns the registered commands of this command manager, which is related
- * to a connection.
- *
- * @return the registered commands.
- */
- private Collection<AdHocCommandInfo> getRegisteredCommands() {
- return commands.values();
- }
-
- /**
- * Stores ad-hoc command information.
- */
- private static class AdHocCommandInfo {
-
- private String node;
- private String name;
- private String ownerJID;
- private LocalCommandFactory factory;
-
- public AdHocCommandInfo(String node, String name, String ownerJID,
- LocalCommandFactory factory)
- {
- this.node = node;
- this.name = name;
- this.ownerJID = ownerJID;
- this.factory = factory;
- }
-
- public LocalCommand getCommandInstance() throws InstantiationException,
- IllegalAccessException
- {
- return factory.getInstance();
- }
-
- public String getName() {
- return name;
- }
-
- public String getNode() {
- return node;
- }
-
- public String getOwnerJID() {
- return ownerJID;
- }
- }
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2005-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.
+ * 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.commands;
+
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.NodeInformationProvider;
+import org.jivesoftware.smackx.ServiceDiscoveryManager;
+import org.jivesoftware.smackx.commands.AdHocCommand.Action;
+import org.jivesoftware.smackx.commands.AdHocCommand.Status;
+import org.jivesoftware.smackx.packet.AdHocCommandData;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
+import org.jivesoftware.smackx.packet.DiscoverInfo.Identity;
+import org.jivesoftware.smackx.packet.DiscoverItems;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * An AdHocCommandManager is responsible for keeping the list of available
+ * commands offered by a service and for processing commands requests.
+ *
+ * Pass in a Connection instance to
+ * {@link #getAddHocCommandsManager(org.jivesoftware.smack.Connection)} in order to
+ * get an instance of this class.
+ *
+ * @author Gabriel Guardincerri
+ */
+public class AdHocCommandManager {
+
+ private static final String DISCO_NAMESPACE = "http://jabber.org/protocol/commands";
+
+ private static final String discoNode = DISCO_NAMESPACE;
+
+ /**
+ * The session time out in seconds.
+ */
+ private static final int SESSION_TIMEOUT = 2 * 60;
+
+ /**
+ * Map a Connection with it AdHocCommandManager. This map have a key-value
+ * pair for every active connection.
+ */
+ private static Map<Connection, AdHocCommandManager> instances =
+ new ConcurrentHashMap<Connection, AdHocCommandManager>();
+
+ /**
+ * Register the listener for all the connection creations. When a new
+ * connection is created a new AdHocCommandManager is also created and
+ * related to that connection.
+ */
+ static {
+ Connection.addConnectionCreationListener(new ConnectionCreationListener() {
+ public void connectionCreated(Connection connection) {
+ new AdHocCommandManager(connection);
+ }
+ });
+ }
+
+ /**
+ * Returns the <code>AdHocCommandManager</code> related to the
+ * <code>connection</code>.
+ *
+ * @param connection the XMPP connection.
+ * @return the AdHocCommandManager associated with the connection.
+ */
+ public static AdHocCommandManager getAddHocCommandsManager(Connection connection) {
+ return instances.get(connection);
+ }
+
+ /**
+ * Thread that reaps stale sessions.
+ */
+ private Thread sessionsSweeper;
+
+ /**
+ * The Connection that this instances of AdHocCommandManager manages
+ */
+ private Connection connection;
+
+ /**
+ * Map a command node with its AdHocCommandInfo. Note: Key=command node,
+ * Value=command. Command node matches the node attribute sent by command
+ * requesters.
+ */
+ private Map<String, AdHocCommandInfo> commands = new ConcurrentHashMap<String, AdHocCommandInfo>();
+
+ /**
+ * Map a command session ID with the instance LocalCommand. The LocalCommand
+ * is the an objects that has all the information of the current state of
+ * the command execution. Note: Key=session ID, Value=LocalCommand. Session
+ * ID matches the sessionid attribute sent by command responders.
+ */
+ private Map<String, LocalCommand> executingCommands = new ConcurrentHashMap<String, LocalCommand>();
+
+ private AdHocCommandManager(Connection connection) {
+ super();
+ this.connection = connection;
+ init();
+ }
+
+ /**
+ * Registers a new command with this command manager, which is related to a
+ * connection. The <tt>node</tt> is an unique identifier of that command for
+ * the connection related to this command manager. The <tt>name</tt> is the
+ * human readable name of the command. The <tt>class</tt> is the class of
+ * the command, which must extend {@link LocalCommand} and have a default
+ * constructor.
+ *
+ * @param node the unique identifier of the command.
+ * @param name the human readable name of the command.
+ * @param clazz the class of the command, which must extend {@link LocalCommand}.
+ */
+ public void registerCommand(String node, String name, final Class<? extends LocalCommand> clazz) {
+ registerCommand(node, name, new LocalCommandFactory() {
+ public LocalCommand getInstance() throws InstantiationException, IllegalAccessException {
+ return clazz.newInstance();
+ }
+ });
+ }
+
+ /**
+ * Registers a new command with this command manager, which is related to a
+ * connection. The <tt>node</tt> is an unique identifier of that
+ * command for the connection related to this command manager. The <tt>name</tt>
+ * is the human readeale name of the command. The <tt>factory</tt> generates
+ * new instances of the command.
+ *
+ * @param node the unique identifier of the command.
+ * @param name the human readable name of the command.
+ * @param factory a factory to create new instances of the command.
+ */
+ public void registerCommand(String node, final String name, LocalCommandFactory factory) {
+ AdHocCommandInfo commandInfo = new AdHocCommandInfo(node, name, connection.getUser(), factory);
+
+ commands.put(node, commandInfo);
+ // Set the NodeInformationProvider that will provide information about
+ // the added command
+ ServiceDiscoveryManager.getInstanceFor(connection).setNodeInformationProvider(node,
+ new NodeInformationProvider() {
+ public List<DiscoverItems.Item> getNodeItems() {
+ return null;
+ }
+
+ public List<String> getNodeFeatures() {
+ List<String> answer = new ArrayList<String>();
+ answer.add(DISCO_NAMESPACE);
+ // TODO: check if this service is provided by the
+ // TODO: current connection.
+ answer.add("jabber:x:data");
+ return answer;
+ }
+
+ public List<DiscoverInfo.Identity> getNodeIdentities() {
+ List<DiscoverInfo.Identity> answer = new ArrayList<DiscoverInfo.Identity>();
+ DiscoverInfo.Identity identity = new DiscoverInfo.Identity(
+ "automation", name, "command-node");
+ answer.add(identity);
+ return answer;
+ }
+
+ @Override
+ public List<PacketExtension> getNodePacketExtensions() {
+ return null;
+ }
+
+ });
+ }
+
+ /**
+ * Discover the commands of an specific JID. The <code>jid</code> is a
+ * full JID.
+ *
+ * @param jid the full JID to retrieve the commands for.
+ * @return the discovered items.
+ * @throws XMPPException if the operation failed for some reason.
+ */
+ public DiscoverItems discoverCommands(String jid) throws XMPPException {
+ ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager
+ .getInstanceFor(connection);
+ return serviceDiscoveryManager.discoverItems(jid, discoNode);
+ }
+
+ /**
+ * Publish the commands to an specific JID.
+ *
+ * @param jid the full JID to publish the commands to.
+ * @throws XMPPException if the operation failed for some reason.
+ */
+ public void publishCommands(String jid) throws XMPPException {
+ ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager
+ .getInstanceFor(connection);
+
+ // Collects the commands to publish as items
+ DiscoverItems discoverItems = new DiscoverItems();
+ Collection<AdHocCommandInfo> xCommandsList = getRegisteredCommands();
+
+ for (AdHocCommandInfo info : xCommandsList) {
+ DiscoverItems.Item item = new DiscoverItems.Item(info.getOwnerJID());
+ item.setName(info.getName());
+ item.setNode(info.getNode());
+ discoverItems.addItem(item);
+ }
+
+ serviceDiscoveryManager.publishItems(jid, discoNode, discoverItems);
+ }
+
+ /**
+ * Returns a command that represents an instance of a command in a remote
+ * host. It is used to execute remote commands. The concept is similar to
+ * RMI. Every invocation on this command is equivalent to an invocation in
+ * the remote command.
+ *
+ * @param jid the full JID of the host of the remote command
+ * @param node the identifier of the command
+ * @return a local instance equivalent to the remote command.
+ */
+ public RemoteCommand getRemoteCommand(String jid, String node) {
+ return new RemoteCommand(connection, node, jid);
+ }
+
+ /**
+ * <ul>
+ * <li>Adds listeners to the connection</li>
+ * <li>Registers the ad-hoc command feature to the ServiceDiscoveryManager</li>
+ * <li>Registers the items of the feature</li>
+ * <li>Adds packet listeners to handle execution requests</li>
+ * <li>Creates and start the session sweeper</li>
+ * </ul>
+ */
+ private void init() {
+ // Register the new instance and associate it with the connection
+ instances.put(connection, this);
+
+ // Add a listener to the connection that removes the registered instance
+ // when the connection is closed
+ connection.addConnectionListener(new ConnectionListener() {
+ public void connectionClosed() {
+ // Unregister this instance since the connection has been closed
+ instances.remove(connection);
+ }
+
+ public void connectionClosedOnError(Exception e) {
+ // Unregister this instance since the connection has been closed
+ instances.remove(connection);
+ }
+
+ public void reconnectionSuccessful() {
+ // Register this instance since the connection has been
+ // reestablished
+ instances.put(connection, AdHocCommandManager.this);
+ }
+
+ public void reconnectingIn(int seconds) {
+ // Nothing to do
+ }
+
+ public void reconnectionFailed(Exception e) {
+ // Nothing to do
+ }
+ });
+
+ // Add the feature to the service discovery manage to show that this
+ // connection supports the AdHoc-Commands protocol.
+ // This information will be used when another client tries to
+ // discover whether this client supports AdHoc-Commands or not.
+ ServiceDiscoveryManager.getInstanceFor(connection).addFeature(
+ DISCO_NAMESPACE);
+
+ // Set the NodeInformationProvider that will provide information about
+ // which AdHoc-Commands are registered, whenever a disco request is
+ // received
+ ServiceDiscoveryManager.getInstanceFor(connection)
+ .setNodeInformationProvider(discoNode,
+ new NodeInformationProvider() {
+ public List<DiscoverItems.Item> getNodeItems() {
+
+ List<DiscoverItems.Item> answer = new ArrayList<DiscoverItems.Item>();
+ Collection<AdHocCommandInfo> commandsList = getRegisteredCommands();
+
+ for (AdHocCommandInfo info : commandsList) {
+ DiscoverItems.Item item = new DiscoverItems.Item(
+ info.getOwnerJID());
+ item.setName(info.getName());
+ item.setNode(info.getNode());
+ answer.add(item);
+ }
+
+ return answer;
+ }
+
+ public List<String> getNodeFeatures() {
+ return null;
+ }
+
+ public List<Identity> getNodeIdentities() {
+ return null;
+ }
+
+ @Override
+ public List<PacketExtension> getNodePacketExtensions() {
+ return null;
+ }
+ });
+
+ // The packet listener and the filter for processing some AdHoc Commands
+ // Packets
+ PacketListener listener = new PacketListener() {
+ public void processPacket(Packet packet) {
+ AdHocCommandData requestData = (AdHocCommandData) packet;
+ processAdHocCommand(requestData);
+ }
+ };
+
+ PacketFilter filter = new PacketTypeFilter(AdHocCommandData.class);
+ connection.addPacketListener(listener, filter);
+
+ sessionsSweeper = null;
+ }
+
+ /**
+ * Process the AdHoc-Command packet that request the execution of some
+ * action of a command. If this is the first request, this method checks,
+ * before executing the command, if:
+ * <ul>
+ * <li>The requested command exists</li>
+ * <li>The requester has permissions to execute it</li>
+ * <li>The command has more than one stage, if so, it saves the command and
+ * session ID for further use</li>
+ * </ul>
+ *
+ * <br>
+ * <br>
+ * If this is not the first request, this method checks, before executing
+ * the command, if:
+ * <ul>
+ * <li>The session ID of the request was stored</li>
+ * <li>The session life do not exceed the time out</li>
+ * <li>The action to execute is one of the available actions</li>
+ * </ul>
+ *
+ * @param requestData
+ * the packet to process.
+ */
+ private void processAdHocCommand(AdHocCommandData requestData) {
+ // Only process requests of type SET
+ if (requestData.getType() != IQ.Type.SET) {
+ return;
+ }
+
+ // Creates the response with the corresponding data
+ AdHocCommandData response = new AdHocCommandData();
+ response.setTo(requestData.getFrom());
+ response.setPacketID(requestData.getPacketID());
+ response.setNode(requestData.getNode());
+ response.setId(requestData.getTo());
+
+ String sessionId = requestData.getSessionID();
+ String commandNode = requestData.getNode();
+
+ if (sessionId == null) {
+ // A new execution request has been received. Check that the
+ // command exists
+ if (!commands.containsKey(commandNode)) {
+ // Requested command does not exist so return
+ // item_not_found error.
+ respondError(response, XMPPError.Condition.item_not_found);
+ return;
+ }
+
+ // Create new session ID
+ sessionId = StringUtils.randomString(15);
+
+ try {
+ // Create a new instance of the command with the
+ // corresponding sessioid
+ LocalCommand command = newInstanceOfCmd(commandNode, sessionId);
+
+ response.setType(IQ.Type.RESULT);
+ command.setData(response);
+
+ // Check that the requester has enough permission.
+ // Answer forbidden error if requester permissions are not
+ // enough to execute the requested command
+ if (!command.hasPermission(requestData.getFrom())) {
+ respondError(response, XMPPError.Condition.forbidden);
+ return;
+ }
+
+ Action action = requestData.getAction();
+
+ // If the action is unknown then respond an error.
+ if (action != null && action.equals(Action.unknown)) {
+ respondError(response, XMPPError.Condition.bad_request,
+ AdHocCommand.SpecificErrorCondition.malformedAction);
+ return;
+ }
+
+ // If the action is not execute, then it is an invalid action.
+ if (action != null && !action.equals(Action.execute)) {
+ respondError(response, XMPPError.Condition.bad_request,
+ AdHocCommand.SpecificErrorCondition.badAction);
+ return;
+ }
+
+ // Increase the state number, so the command knows in witch
+ // stage it is
+ command.incrementStage();
+ // Executes the command
+ command.execute();
+
+ if (command.isLastStage()) {
+ // If there is only one stage then the command is completed
+ response.setStatus(Status.completed);
+ }
+ else {
+ // Else it is still executing, and is registered to be
+ // available for the next call
+ response.setStatus(Status.executing);
+ executingCommands.put(sessionId, command);
+ // See if the session reaping thread is started. If not, start it.
+ if (sessionsSweeper == null) {
+ sessionsSweeper = new Thread(new Runnable() {
+ public void run() {
+ while (true) {
+ for (String sessionId : executingCommands.keySet()) {
+ LocalCommand command = executingCommands.get(sessionId);
+ // Since the command could be removed in the meanwhile
+ // of getting the key and getting the value - by a
+ // processed packet. We must check if it still in the
+ // map.
+ if (command != null) {
+ long creationStamp = command.getCreationDate();
+ // Check if the Session data has expired (default is
+ // 10 minutes)
+ // To remove it from the session list it waits for
+ // the double of the of time out time. This is to
+ // let
+ // the requester know why his execution request is
+ // not accepted. If the session is removed just
+ // after the time out, then whe the user request to
+ // continue the execution he will recieved an
+ // invalid session error and not a time out error.
+ if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000 * 2) {
+ // Remove the expired session
+ executingCommands.remove(sessionId);
+ }
+ }
+ }
+ try {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException ie) {
+ // Ignore.
+ }
+ }
+ }
+
+ });
+ sessionsSweeper.setDaemon(true);
+ sessionsSweeper.start();
+ }
+ }
+
+ // Sends the response packet
+ connection.sendPacket(response);
+
+ }
+ catch (XMPPException e) {
+ // If there is an exception caused by the next, complete,
+ // prev or cancel method, then that error is returned to the
+ // requester.
+ XMPPError error = e.getXMPPError();
+
+ // If the error type is cancel, then the execution is
+ // canceled therefore the status must show that, and the
+ // command be removed from the executing list.
+ if (XMPPError.Type.CANCEL.equals(error.getType())) {
+ response.setStatus(Status.canceled);
+ executingCommands.remove(sessionId);
+ }
+ respondError(response, error);
+ e.printStackTrace();
+ }
+ }
+ else {
+ LocalCommand command = executingCommands.get(sessionId);
+
+ // Check that a command exists for the specified sessionID
+ // This also handles if the command was removed in the meanwhile
+ // of getting the key and the value of the map.
+ if (command == null) {
+ respondError(response, XMPPError.Condition.bad_request,
+ AdHocCommand.SpecificErrorCondition.badSessionid);
+ return;
+ }
+
+ // Check if the Session data has expired (default is 10 minutes)
+ long creationStamp = command.getCreationDate();
+ if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000) {
+ // Remove the expired session
+ executingCommands.remove(sessionId);
+
+ // Answer a not_allowed error (session-expired)
+ respondError(response, XMPPError.Condition.not_allowed,
+ AdHocCommand.SpecificErrorCondition.sessionExpired);
+ return;
+ }
+
+ /*
+ * Since the requester could send two requests for the same
+ * executing command i.e. the same session id, all the execution of
+ * the action must be synchronized to avoid inconsistencies.
+ */
+ synchronized (command) {
+ Action action = requestData.getAction();
+
+ // If the action is unknown the respond an error
+ if (action != null && action.equals(Action.unknown)) {
+ respondError(response, XMPPError.Condition.bad_request,
+ AdHocCommand.SpecificErrorCondition.malformedAction);
+ return;
+ }
+
+ // If the user didn't specify an action or specify the execute
+ // action then follow the actual default execute action
+ if (action == null || Action.execute.equals(action)) {
+ action = command.getExecuteAction();
+ }
+
+ // Check that the specified action was previously
+ // offered
+ if (!command.isValidAction(action)) {
+ respondError(response, XMPPError.Condition.bad_request,
+ AdHocCommand.SpecificErrorCondition.badAction);
+ return;
+ }
+
+ try {
+ // TODO: Check that all the requierd fields of the form are
+ // TODO: filled, if not throw an exception. This will simplify the
+ // TODO: construction of new commands
+
+ // Since all errors were passed, the response is now a
+ // result
+ response.setType(IQ.Type.RESULT);
+
+ // Set the new data to the command.
+ command.setData(response);
+
+ if (Action.next.equals(action)) {
+ command.incrementStage();
+ command.next(new Form(requestData.getForm()));
+ if (command.isLastStage()) {
+ // If it is the last stage then the command is
+ // completed
+ response.setStatus(Status.completed);
+ }
+ else {
+ // Otherwise it is still executing
+ response.setStatus(Status.executing);
+ }
+ }
+ else if (Action.complete.equals(action)) {
+ command.incrementStage();
+ command.complete(new Form(requestData.getForm()));
+ response.setStatus(Status.completed);
+ // Remove the completed session
+ executingCommands.remove(sessionId);
+ }
+ else if (Action.prev.equals(action)) {
+ command.decrementStage();
+ command.prev();
+ }
+ else if (Action.cancel.equals(action)) {
+ command.cancel();
+ response.setStatus(Status.canceled);
+ // Remove the canceled session
+ executingCommands.remove(sessionId);
+ }
+
+ connection.sendPacket(response);
+ }
+ catch (XMPPException e) {
+ // If there is an exception caused by the next, complete,
+ // prev or cancel method, then that error is returned to the
+ // requester.
+ XMPPError error = e.getXMPPError();
+
+ // If the error type is cancel, then the execution is
+ // canceled therefore the status must show that, and the
+ // command be removed from the executing list.
+ if (XMPPError.Type.CANCEL.equals(error.getType())) {
+ response.setStatus(Status.canceled);
+ executingCommands.remove(sessionId);
+ }
+ respondError(response, error);
+
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Responds an error with an specific condition.
+ *
+ * @param response the response to send.
+ * @param condition the condition of the error.
+ */
+ private void respondError(AdHocCommandData response,
+ XMPPError.Condition condition) {
+ respondError(response, new XMPPError(condition));
+ }
+
+ /**
+ * Responds an error with an specific condition.
+ *
+ * @param response the response to send.
+ * @param condition the condition of the error.
+ * @param specificCondition the adhoc command error condition.
+ */
+ private void respondError(AdHocCommandData response, XMPPError.Condition condition,
+ AdHocCommand.SpecificErrorCondition specificCondition)
+ {
+ XMPPError error = new XMPPError(condition);
+ error.addExtension(new AdHocCommandData.SpecificError(specificCondition));
+ respondError(response, error);
+ }
+
+ /**
+ * Responds an error with an specific error.
+ *
+ * @param response the response to send.
+ * @param error the error to send.
+ */
+ private void respondError(AdHocCommandData response, XMPPError error) {
+ response.setType(IQ.Type.ERROR);
+ response.setError(error);
+ connection.sendPacket(response);
+ }
+
+ /**
+ * Creates a new instance of a command to be used by a new execution request
+ *
+ * @param commandNode the command node that identifies it.
+ * @param sessionID the session id of this execution.
+ * @return the command instance to execute.
+ * @throws XMPPException if there is problem creating the new instance.
+ */
+ private LocalCommand newInstanceOfCmd(String commandNode, String sessionID)
+ throws XMPPException
+ {
+ AdHocCommandInfo commandInfo = commands.get(commandNode);
+ LocalCommand command;
+ try {
+ command = (LocalCommand) commandInfo.getCommandInstance();
+ command.setSessionID(sessionID);
+ command.setName(commandInfo.getName());
+ command.setNode(commandInfo.getNode());
+ }
+ catch (InstantiationException e) {
+ e.printStackTrace();
+ throw new XMPPException(new XMPPError(
+ XMPPError.Condition.interna_server_error));
+ }
+ catch (IllegalAccessException e) {
+ e.printStackTrace();
+ throw new XMPPException(new XMPPError(
+ XMPPError.Condition.interna_server_error));
+ }
+ return command;
+ }
+
+ /**
+ * Returns the registered commands of this command manager, which is related
+ * to a connection.
+ *
+ * @return the registered commands.
+ */
+ private Collection<AdHocCommandInfo> getRegisteredCommands() {
+ return commands.values();
+ }
+
+ /**
+ * Stores ad-hoc command information.
+ */
+ private static class AdHocCommandInfo {
+
+ private String node;
+ private String name;
+ private String ownerJID;
+ private LocalCommandFactory factory;
+
+ public AdHocCommandInfo(String node, String name, String ownerJID,
+ LocalCommandFactory factory)
+ {
+ this.node = node;
+ this.name = name;
+ this.ownerJID = ownerJID;
+ this.factory = factory;
+ }
+
+ public LocalCommand getCommandInstance() throws InstantiationException,
+ IllegalAccessException
+ {
+ return factory.getInstance();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getNode() {
+ return node;
+ }
+
+ public String getOwnerJID() {
+ return ownerJID;
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandNote.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandNote.java
index 10dedbead..15ef4b21c 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandNote.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/AdHocCommandNote.java
@@ -1,86 +1,86 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2005-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
- *
- * 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.commands;
-
-/**
- * Notes can be added to a command execution response. A note has a type and value.
- *
- * @author Gabriel Guardincerri
- */
-public class AdHocCommandNote {
-
- private Type type;
- private String value;
-
- /**
- * Creates a new adhoc command note with the specified type and value.
- *
- * @param type the type of the note.
- * @param value the value of the note.
- */
- public AdHocCommandNote(Type type, String value) {
- this.type = type;
- this.value = value;
- }
-
- /**
- * Returns the value or message of the note.
- *
- * @return the value or message of the note.
- */
- public String getValue() {
- return value;
- }
-
- /**
- * Return the type of the note.
- *
- * @return the type of the note.
- */
- public Type getType() {
- return type;
- }
-
- /**
- * Represents a note type.
- */
- public enum Type {
-
- /**
- * The note is informational only. This is not really an exceptional
- * condition.
- */
- info,
-
- /**
- * The note indicates a warning. Possibly due to illogical (yet valid)
- * data.
- */
- warn,
-
- /**
- * The note indicates an error. The text should indicate the reason for
- * the error.
- */
- error
- }
-
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2005-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
+ *
+ * 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.commands;
+
+/**
+ * Notes can be added to a command execution response. A note has a type and value.
+ *
+ * @author Gabriel Guardincerri
+ */
+public class AdHocCommandNote {
+
+ private Type type;
+ private String value;
+
+ /**
+ * Creates a new adhoc command note with the specified type and value.
+ *
+ * @param type the type of the note.
+ * @param value the value of the note.
+ */
+ public AdHocCommandNote(Type type, String value) {
+ this.type = type;
+ this.value = value;
+ }
+
+ /**
+ * Returns the value or message of the note.
+ *
+ * @return the value or message of the note.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Return the type of the note.
+ *
+ * @return the type of the note.
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Represents a note type.
+ */
+ public enum Type {
+
+ /**
+ * The note is informational only. This is not really an exceptional
+ * condition.
+ */
+ info,
+
+ /**
+ * The note indicates a warning. Possibly due to illogical (yet valid)
+ * data.
+ */
+ warn,
+
+ /**
+ * The note indicates an error. The text should indicate the reason for
+ * the error.
+ */
+ error
+ }
+
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/LocalCommand.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/LocalCommand.java
index 627d30ea7..dae1fb407 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/LocalCommand.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/commands/LocalCommand.java
@@ -1,169 +1,169 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2005-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
- *
- * 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.commands;
-
-import org.jivesoftware.smackx.packet.AdHocCommandData;
-
-/**
- * Represents a command that can be executed locally from a remote location. This
- * class must be extended to implement an specific ad-hoc command. This class
- * provides some useful tools:<ul>
- * <li>Node</li>
- * <li>Name</li>
- * <li>Session ID</li>
- * <li>Current Stage</li>
- * <li>Available actions</li>
- * <li>Default action</li>
- * </ul><p/>
- * To implement a new command extend this class and implement all the abstract
- * methods. When implementing the actions remember that they could be invoked
- * several times, and that you must use the current stage number to know what to
- * do.
- *
- * @author Gabriel Guardincerri
- */
-public abstract class LocalCommand extends AdHocCommand {
-
- /**
- * The time stamp of first invokation of the command. Used to implement the session timeout.
- */
- private long creationDate;
-
- /**
- * The unique ID of the execution of the command.
- */
- private String sessionID;
-
- /**
- * The full JID of the host of the command.
- */
- private String ownerJID;
-
- /**
- * The number of the current stage.
- */
- private int currenStage;
-
- public LocalCommand() {
- super();
- this.creationDate = System.currentTimeMillis();
- currenStage = -1;
- }
-
- /**
- * The sessionID is an unique identifier of an execution request. This is
- * automatically handled and should not be called.
- *
- * @param sessionID the unique session id of this execution
- */
- public void setSessionID(String sessionID) {
- this.sessionID = sessionID;
- getData().setSessionID(sessionID);
- }
-
- /**
- * Returns the session ID of this execution.
- *
- * @return the unique session id of this execution
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Sets the JID of the command host. This is automatically handled and should
- * not be called.
- *
- * @param ownerJID the JID of the owner.
- */
- public void setOwnerJID(String ownerJID) {
- this.ownerJID = ownerJID;
- }
-
- @Override
- public String getOwnerJID() {
- return ownerJID;
- }
-
- /**
- * Returns the date the command was created.
- *
- * @return the date the command was created.
- */
- public long getCreationDate() {
- return creationDate;
- }
-
- /**
- * Returns true if the current stage is the last one. If it is then the
- * execution of some action will complete the execution of the command.
- * Commands that don't have multiple stages can always return <tt>true</tt>.
- *
- * @return true if the command is in the last stage.
- */
- public abstract boolean isLastStage();
-
- /**
- * Returns true if the specified requester has permission to execute all the
- * stages of this action. This is checked when the first request is received,
- * if the permission is grant then the requester will be able to execute
- * all the stages of the command. It is not checked again during the
- * execution.
- *
- * @param jid the JID to check permissions on.
- * @return true if the user has permission to execute this action.
- */
- public abstract boolean hasPermission(String jid);
-
- /**
- * Returns the currently executing stage number. The first stage number is
- * 0. During the execution of the first action this method will answer 0.
- *
- * @return the current stage number.
- */
- public int getCurrentStage() {
- return currenStage;
- }
-
- @Override
- void setData(AdHocCommandData data) {
- data.setSessionID(sessionID);
- super.setData(data);
- }
-
- /**
- * Increase the current stage number. This is automatically handled and should
- * not be called.
- *
- */
- void incrementStage() {
- currenStage++;
- }
-
- /**
- * Decrease the current stage number. This is automatically handled and should
- * not be called.
- *
- */
- void decrementStage() {
- currenStage--;
- }
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2005-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
+ *
+ * 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.commands;
+
+import org.jivesoftware.smackx.packet.AdHocCommandData;
+
+/**
+ * Represents a command that can be executed locally from a remote location. This
+ * class must be extended to implement an specific ad-hoc command. This class
+ * provides some useful tools:<ul>
+ * <li>Node</li>
+ * <li>Name</li>
+ * <li>Session ID</li>
+ * <li>Current Stage</li>
+ * <li>Available actions</li>
+ * <li>Default action</li>
+ * </ul><p/>
+ * To implement a new command extend this class and implement all the abstract
+ * methods. When implementing the actions remember that they could be invoked
+ * several times, and that you must use the current stage number to know what to
+ * do.
+ *
+ * @author Gabriel Guardincerri
+ */
+public abstract class LocalCommand extends AdHocCommand {
+
+ /**
+ * The time stamp of first invokation of the command. Used to implement the session timeout.
+ */
+ private long creationDate;
+
+ /**
+ * The unique ID of the execution of the command.
+ */
+ private String sessionID;
+
+ /**
+ * The full JID of the host of the command.
+ */
+ private String ownerJID;
+
+ /**
+ * The number of the current stage.
+ */
+ private int currenStage;
+
+ public LocalCommand() {
+ super();
+ this.creationDate = System.currentTimeMillis();
+ currenStage = -1;
+ }
+
+ /**
+ * The sessionID is an unique identifier of an execution request. This is
+ * automatically handled and should not be called.
+ *
+ * @param sessionID the unique session id of this execution
+ */
+ public void setSessionID(String sessionID) {
+ this.sessionID = sessionID;
+ getData().setSessionID(sessionID);
+ }
+
+ /**
+ * Returns the session ID of this execution.
+ *
+ * @return the unique session id of this execution
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Sets the JID of the command host. This is automatically handled and should
+ * not be called.
+ *
+ * @param ownerJID the JID of the owner.
+ */
+ public void setOwnerJID(String ownerJID) {
+ this.ownerJID = ownerJID;
+ }
+
+ @Override
+ public String getOwnerJID() {
+ return ownerJID;
+ }
+
+ /**
+ * Returns the date the command was created.
+ *
+ * @return the date the command was created.
+ */
+ public long getCreationDate() {
+ return creationDate;
+ }
+
+ /**
+ * Returns true if the current stage is the last one. If it is then the
+ * execution of some action will complete the execution of the command.
+ * Commands that don't have multiple stages can always return <tt>true</tt>.
+ *
+ * @return true if the command is in the last stage.
+ */
+ public abstract boolean isLastStage();
+
+ /**
+ * Returns true if the specified requester has permission to execute all the
+ * stages of this action. This is checked when the first request is received,
+ * if the permission is grant then the requester will be able to execute
+ * all the stages of the command. It is not checked again during the
+ * execution.
+ *
+ * @param jid the JID to check permissions on.
+ * @return true if the user has permission to execute this action.
+ */
+ public abstract boolean hasPermission(String jid);
+
+ /**
+ * Returns the currently executing stage number. The first stage number is
+ * 0. During the execution of the first action this method will answer 0.
+ *
+ * @return the current stage number.
+ */
+ public int getCurrentStage() {
+ return currenStage;
+ }
+
+ @Override
+ void setData(AdHocCommandData data) {
+ data.setSessionID(sessionID);
+ super.setData(data);
+ }
+
+ /**
+ * Increase the current stage number. This is automatically handled and should
+ * not be called.
+ *
+ */
+ void incrementStage() {
+ currenStage++;
+ }
+
+ /**
+ * Decrease the current stage number. This is automatically handled and should
+ * not be called.
+ *
+ */
+ void decrementStage() {
+ currenStage--;
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransfer.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransfer.java
index b840fd537..13d2c5ae9 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransfer.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransfer.java
@@ -1,380 +1,380 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-import org.jivesoftware.smack.XMPPException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Contains the generic file information and progress related to a particular
- * file transfer.
- *
- * @author Alexander Wenckus
- *
- */
-public abstract class FileTransfer {
-
- private String fileName;
-
- private String filePath;
-
- private long fileSize;
-
- private String peer;
-
- private Status status = Status.initial;
-
- private final Object statusMonitor = new Object();
-
- protected FileTransferNegotiator negotiator;
-
- protected String streamID;
-
- protected long amountWritten = -1;
-
- private Error error;
-
- private Exception exception;
-
- /**
- * Buffer size between input and output
- */
- private static final int BUFFER_SIZE = 8192;
-
- protected FileTransfer(String peer, String streamID,
- FileTransferNegotiator negotiator) {
- this.peer = peer;
- this.streamID = streamID;
- this.negotiator = negotiator;
- }
-
- protected void setFileInfo(String fileName, long fileSize) {
- this.fileName = fileName;
- this.fileSize = fileSize;
- }
-
- protected void setFileInfo(String path, String fileName, long fileSize) {
- this.filePath = path;
- this.fileName = fileName;
- this.fileSize = fileSize;
- }
-
- /**
- * Returns the size of the file being transfered.
- *
- * @return Returns the size of the file being transfered.
- */
- public long getFileSize() {
- return fileSize;
- }
-
- /**
- * Returns the name of the file being transfered.
- *
- * @return Returns the name of the file being transfered.
- */
- public String getFileName() {
- return fileName;
- }
-
- /**
- * Returns the local path of the file.
- *
- * @return Returns the local path of the file.
- */
- public String getFilePath() {
- return filePath;
- }
-
- /**
- * Returns the JID of the peer for this file transfer.
- *
- * @return Returns the JID of the peer for this file transfer.
- */
- public String getPeer() {
- return peer;
- }
-
- /**
- * Returns the progress of the file transfer as a number between 0 and 1.
- *
- * @return Returns the progress of the file transfer as a number between 0
- * and 1.
- */
- public double getProgress() {
- if (amountWritten <= 0 || fileSize <= 0) {
- return 0;
- }
- return (double) amountWritten / (double) fileSize;
- }
-
- /**
- * Returns true if the transfer has been cancelled, if it has stopped because
- * of a an error, or the transfer completed successfully.
- *
- * @return Returns true if the transfer has been cancelled, if it has stopped
- * because of a an error, or the transfer completed successfully.
- */
- public boolean isDone() {
- return status == Status.cancelled || status == Status.error
- || status == Status.complete || status == Status.refused;
- }
-
- /**
- * Returns the current status of the file transfer.
- *
- * @return Returns the current status of the file transfer.
- */
- public Status getStatus() {
- return status;
- }
-
- protected void setError(Error type) {
- this.error = type;
- }
-
- /**
- * When {@link #getStatus()} returns that there was an {@link Status#error}
- * during the transfer, the type of error can be retrieved through this
- * method.
- *
- * @return Returns the type of error that occurred if one has occurred.
- */
- public Error getError() {
- return error;
- }
-
- /**
- * If an exception occurs asynchronously it will be stored for later
- * retrieval. If there is an error there maybe an exception set.
- *
- * @return The exception that occurred or null if there was no exception.
- * @see #getError()
- */
- public Exception getException() {
- return exception;
- }
-
- public String getStreamID() {
- return streamID;
- }
-
- /**
- * Cancels the file transfer.
- */
- public abstract void cancel();
-
- protected void setException(Exception exception) {
- this.exception = exception;
- }
-
- protected void setStatus(Status status) {
- synchronized (statusMonitor) {
- this.status = status;
- }
- }
-
- protected boolean updateStatus(Status oldStatus, Status newStatus) {
- synchronized (statusMonitor) {
- if (oldStatus != status) {
- return false;
- }
- status = newStatus;
- return true;
- }
- }
-
- protected void writeToStream(final InputStream in, final OutputStream out)
- throws XMPPException
- {
- final byte[] b = new byte[BUFFER_SIZE];
- int count = 0;
- amountWritten = 0;
-
- do {
- // write to the output stream
- try {
- out.write(b, 0, count);
- } catch (IOException e) {
- throw new XMPPException("error writing to output stream", e);
- }
-
- amountWritten += count;
-
- // read more bytes from the input stream
- try {
- count = in.read(b);
- } catch (IOException e) {
- throw new XMPPException("error reading from input stream", e);
- }
- } while (count != -1 && !getStatus().equals(Status.cancelled));
-
- // the connection was likely terminated abrubtly if these are not equal
- if (!getStatus().equals(Status.cancelled) && getError() == Error.none
- && amountWritten != fileSize) {
- setStatus(Status.error);
- this.error = Error.connection;
- }
- }
-
- /**
- * A class to represent the current status of the file transfer.
- *
- * @author Alexander Wenckus
- *
- */
- public enum Status {
-
- /**
- * An error occurred during the transfer.
- *
- * @see FileTransfer#getError()
- */
- error("Error"),
-
- /**
- * The initial status of the file transfer.
- */
- initial("Initial"),
-
- /**
- * The file transfer is being negotiated with the peer. The party
- * Receiving the file has the option to accept or refuse a file transfer
- * request. If they accept, then the process of stream negotiation will
- * begin. If they refuse the file will not be transfered.
- *
- * @see #negotiating_stream
- */
- negotiating_transfer("Negotiating Transfer"),
-
- /**
- * The peer has refused the file transfer request halting the file
- * transfer negotiation process.
- */
- refused("Refused"),
-
- /**
- * The stream to transfer the file is being negotiated over the chosen
- * stream type. After the stream negotiating process is complete the
- * status becomes negotiated.
- *
- * @see #negotiated
- */
- negotiating_stream("Negotiating Stream"),
-
- /**
- * After the stream negotiation has completed the intermediate state
- * between the time when the negotiation is finished and the actual
- * transfer begins.
- */
- negotiated("Negotiated"),
-
- /**
- * The transfer is in progress.
- *
- * @see FileTransfer#getProgress()
- */
- in_progress("In Progress"),
-
- /**
- * The transfer has completed successfully.
- */
- complete("Complete"),
-
- /**
- * The file transfer was cancelled
- */
- cancelled("Cancelled");
-
- private String status;
-
- private Status(String status) {
- this.status = status;
- }
-
- public String toString() {
- return status;
- }
- }
-
- /**
- * Return the length of bytes written out to the stream.
- * @return the amount in bytes written out.
- */
- public long getAmountWritten(){
- return amountWritten;
- }
-
- public enum Error {
- /**
- * No error
- */
- none("No error"),
-
- /**
- * The peer did not find any of the provided stream mechanisms
- * acceptable.
- */
- not_acceptable("The peer did not find any of the provided stream mechanisms acceptable."),
-
- /**
- * The provided file to transfer does not exist or could not be read.
- */
- bad_file("The provided file to transfer does not exist or could not be read."),
-
- /**
- * The remote user did not respond or the connection timed out.
- */
- no_response("The remote user did not respond or the connection timed out."),
-
- /**
- * An error occurred over the socket connected to send the file.
- */
- connection("An error occured over the socket connected to send the file."),
-
- /**
- * An error occurred while sending or receiving the file
- */
- stream("An error occured while sending or recieving the file.");
-
- private final String msg;
-
- private Error(String msg) {
- this.msg = msg;
- }
-
- /**
- * Returns a String representation of this error.
- *
- * @return Returns a String representation of this error.
- */
- public String getMessage() {
- return msg;
- }
-
- public String toString() {
- return msg;
- }
- }
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+import org.jivesoftware.smack.XMPPException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Contains the generic file information and progress related to a particular
+ * file transfer.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+public abstract class FileTransfer {
+
+ private String fileName;
+
+ private String filePath;
+
+ private long fileSize;
+
+ private String peer;
+
+ private Status status = Status.initial;
+
+ private final Object statusMonitor = new Object();
+
+ protected FileTransferNegotiator negotiator;
+
+ protected String streamID;
+
+ protected long amountWritten = -1;
+
+ private Error error;
+
+ private Exception exception;
+
+ /**
+ * Buffer size between input and output
+ */
+ private static final int BUFFER_SIZE = 8192;
+
+ protected FileTransfer(String peer, String streamID,
+ FileTransferNegotiator negotiator) {
+ this.peer = peer;
+ this.streamID = streamID;
+ this.negotiator = negotiator;
+ }
+
+ protected void setFileInfo(String fileName, long fileSize) {
+ this.fileName = fileName;
+ this.fileSize = fileSize;
+ }
+
+ protected void setFileInfo(String path, String fileName, long fileSize) {
+ this.filePath = path;
+ this.fileName = fileName;
+ this.fileSize = fileSize;
+ }
+
+ /**
+ * Returns the size of the file being transfered.
+ *
+ * @return Returns the size of the file being transfered.
+ */
+ public long getFileSize() {
+ return fileSize;
+ }
+
+ /**
+ * Returns the name of the file being transfered.
+ *
+ * @return Returns the name of the file being transfered.
+ */
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Returns the local path of the file.
+ *
+ * @return Returns the local path of the file.
+ */
+ public String getFilePath() {
+ return filePath;
+ }
+
+ /**
+ * Returns the JID of the peer for this file transfer.
+ *
+ * @return Returns the JID of the peer for this file transfer.
+ */
+ public String getPeer() {
+ return peer;
+ }
+
+ /**
+ * Returns the progress of the file transfer as a number between 0 and 1.
+ *
+ * @return Returns the progress of the file transfer as a number between 0
+ * and 1.
+ */
+ public double getProgress() {
+ if (amountWritten <= 0 || fileSize <= 0) {
+ return 0;
+ }
+ return (double) amountWritten / (double) fileSize;
+ }
+
+ /**
+ * Returns true if the transfer has been cancelled, if it has stopped because
+ * of a an error, or the transfer completed successfully.
+ *
+ * @return Returns true if the transfer has been cancelled, if it has stopped
+ * because of a an error, or the transfer completed successfully.
+ */
+ public boolean isDone() {
+ return status == Status.cancelled || status == Status.error
+ || status == Status.complete || status == Status.refused;
+ }
+
+ /**
+ * Returns the current status of the file transfer.
+ *
+ * @return Returns the current status of the file transfer.
+ */
+ public Status getStatus() {
+ return status;
+ }
+
+ protected void setError(Error type) {
+ this.error = type;
+ }
+
+ /**
+ * When {@link #getStatus()} returns that there was an {@link Status#error}
+ * during the transfer, the type of error can be retrieved through this
+ * method.
+ *
+ * @return Returns the type of error that occurred if one has occurred.
+ */
+ public Error getError() {
+ return error;
+ }
+
+ /**
+ * If an exception occurs asynchronously it will be stored for later
+ * retrieval. If there is an error there maybe an exception set.
+ *
+ * @return The exception that occurred or null if there was no exception.
+ * @see #getError()
+ */
+ public Exception getException() {
+ return exception;
+ }
+
+ public String getStreamID() {
+ return streamID;
+ }
+
+ /**
+ * Cancels the file transfer.
+ */
+ public abstract void cancel();
+
+ protected void setException(Exception exception) {
+ this.exception = exception;
+ }
+
+ protected void setStatus(Status status) {
+ synchronized (statusMonitor) {
+ this.status = status;
+ }
+ }
+
+ protected boolean updateStatus(Status oldStatus, Status newStatus) {
+ synchronized (statusMonitor) {
+ if (oldStatus != status) {
+ return false;
+ }
+ status = newStatus;
+ return true;
+ }
+ }
+
+ protected void writeToStream(final InputStream in, final OutputStream out)
+ throws XMPPException
+ {
+ final byte[] b = new byte[BUFFER_SIZE];
+ int count = 0;
+ amountWritten = 0;
+
+ do {
+ // write to the output stream
+ try {
+ out.write(b, 0, count);
+ } catch (IOException e) {
+ throw new XMPPException("error writing to output stream", e);
+ }
+
+ amountWritten += count;
+
+ // read more bytes from the input stream
+ try {
+ count = in.read(b);
+ } catch (IOException e) {
+ throw new XMPPException("error reading from input stream", e);
+ }
+ } while (count != -1 && !getStatus().equals(Status.cancelled));
+
+ // the connection was likely terminated abrubtly if these are not equal
+ if (!getStatus().equals(Status.cancelled) && getError() == Error.none
+ && amountWritten != fileSize) {
+ setStatus(Status.error);
+ this.error = Error.connection;
+ }
+ }
+
+ /**
+ * A class to represent the current status of the file transfer.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+ public enum Status {
+
+ /**
+ * An error occurred during the transfer.
+ *
+ * @see FileTransfer#getError()
+ */
+ error("Error"),
+
+ /**
+ * The initial status of the file transfer.
+ */
+ initial("Initial"),
+
+ /**
+ * The file transfer is being negotiated with the peer. The party
+ * Receiving the file has the option to accept or refuse a file transfer
+ * request. If they accept, then the process of stream negotiation will
+ * begin. If they refuse the file will not be transfered.
+ *
+ * @see #negotiating_stream
+ */
+ negotiating_transfer("Negotiating Transfer"),
+
+ /**
+ * The peer has refused the file transfer request halting the file
+ * transfer negotiation process.
+ */
+ refused("Refused"),
+
+ /**
+ * The stream to transfer the file is being negotiated over the chosen
+ * stream type. After the stream negotiating process is complete the
+ * status becomes negotiated.
+ *
+ * @see #negotiated
+ */
+ negotiating_stream("Negotiating Stream"),
+
+ /**
+ * After the stream negotiation has completed the intermediate state
+ * between the time when the negotiation is finished and the actual
+ * transfer begins.
+ */
+ negotiated("Negotiated"),
+
+ /**
+ * The transfer is in progress.
+ *
+ * @see FileTransfer#getProgress()
+ */
+ in_progress("In Progress"),
+
+ /**
+ * The transfer has completed successfully.
+ */
+ complete("Complete"),
+
+ /**
+ * The file transfer was cancelled
+ */
+ cancelled("Cancelled");
+
+ private String status;
+
+ private Status(String status) {
+ this.status = status;
+ }
+
+ public String toString() {
+ return status;
+ }
+ }
+
+ /**
+ * Return the length of bytes written out to the stream.
+ * @return the amount in bytes written out.
+ */
+ public long getAmountWritten(){
+ return amountWritten;
+ }
+
+ public enum Error {
+ /**
+ * No error
+ */
+ none("No error"),
+
+ /**
+ * The peer did not find any of the provided stream mechanisms
+ * acceptable.
+ */
+ not_acceptable("The peer did not find any of the provided stream mechanisms acceptable."),
+
+ /**
+ * The provided file to transfer does not exist or could not be read.
+ */
+ bad_file("The provided file to transfer does not exist or could not be read."),
+
+ /**
+ * The remote user did not respond or the connection timed out.
+ */
+ no_response("The remote user did not respond or the connection timed out."),
+
+ /**
+ * An error occurred over the socket connected to send the file.
+ */
+ connection("An error occured over the socket connected to send the file."),
+
+ /**
+ * An error occurred while sending or receiving the file
+ */
+ stream("An error occured while sending or recieving the file.");
+
+ private final String msg;
+
+ private Error(String msg) {
+ this.msg = msg;
+ }
+
+ /**
+ * Returns a String representation of this error.
+ *
+ * @return Returns a String representation of this error.
+ */
+ public String getMessage() {
+ return msg;
+ }
+
+ public String toString() {
+ return msg;
+ }
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferListener.java
index 8e07543cb..904623cb9 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferListener.java
@@ -1,36 +1,36 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-/**
- * File transfers can cause several events to be raised. These events can be
- * monitored through this interface.
- *
- * @author Alexander Wenckus
- */
-public interface FileTransferListener {
- /**
- * A request to send a file has been recieved from another user.
- *
- * @param request
- * The request from the other user.
- */
- public void fileTransferRequest(final FileTransferRequest request);
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+/**
+ * File transfers can cause several events to be raised. These events can be
+ * monitored through this interface.
+ *
+ * @author Alexander Wenckus
+ */
+public interface FileTransferListener {
+ /**
+ * A request to send a file has been recieved from another user.
+ *
+ * @param request
+ * The request from the other user.
+ */
+ public void fileTransferRequest(final FileTransferRequest request);
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferManager.java
index 6e413fa31..493fda89b 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferManager.java
@@ -1,182 +1,182 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.IQTypeFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smackx.packet.StreamInitiation;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * The file transfer manager class handles the sending and recieving of files.
- * To send a file invoke the {@link #createOutgoingFileTransfer(String)} method.
- * <p>
- * And to recieve a file add a file transfer listener to the manager. The
- * listener will notify you when there is a new file transfer request. To create
- * the {@link IncomingFileTransfer} object accept the transfer, or, if the
- * transfer is not desirable reject it.
- *
- * @author Alexander Wenckus
- *
- */
-public class FileTransferManager {
-
- private final FileTransferNegotiator fileTransferNegotiator;
-
- private List<FileTransferListener> listeners;
-
- private Connection connection;
-
- /**
- * Creates a file transfer manager to initiate and receive file transfers.
- *
- * @param connection
- * The Connection that the file transfers will use.
- */
- public FileTransferManager(Connection connection) {
- this.connection = connection;
- this.fileTransferNegotiator = FileTransferNegotiator
- .getInstanceFor(connection);
- }
-
- /**
- * Add a file transfer listener to listen to incoming file transfer
- * requests.
- *
- * @param li
- * The listener
- * @see #removeFileTransferListener(FileTransferListener)
- * @see FileTransferListener
- */
- public void addFileTransferListener(final FileTransferListener li) {
- if (listeners == null) {
- initListeners();
- }
- synchronized (this.listeners) {
- listeners.add(li);
- }
- }
-
- private void initListeners() {
- listeners = new ArrayList<FileTransferListener>();
-
- connection.addPacketListener(new PacketListener() {
- public void processPacket(Packet packet) {
- fireNewRequest((StreamInitiation) packet);
- }
- }, new AndFilter(new PacketTypeFilter(StreamInitiation.class),
- new IQTypeFilter(IQ.Type.SET)));
- }
-
- protected void fireNewRequest(StreamInitiation initiation) {
- FileTransferListener[] listeners = null;
- synchronized (this.listeners) {
- listeners = new FileTransferListener[this.listeners.size()];
- this.listeners.toArray(listeners);
- }
- FileTransferRequest request = new FileTransferRequest(this, initiation);
- for (int i = 0; i < listeners.length; i++) {
- listeners[i].fileTransferRequest(request);
- }
- }
-
- /**
- * Removes a file transfer listener.
- *
- * @param li
- * The file transfer listener to be removed
- * @see FileTransferListener
- */
- public void removeFileTransferListener(final FileTransferListener li) {
- if (listeners == null) {
- return;
- }
- synchronized (this.listeners) {
- listeners.remove(li);
- }
- }
-
- /**
- * Creates an OutgoingFileTransfer to send a file to another user.
- *
- * @param userID
- * The fully qualified jabber ID (i.e. full JID) with resource of the user to
- * send the file to.
- * @return The send file object on which the negotiated transfer can be run.
- * @exception IllegalArgumentException if userID is null or not a full JID
- */
- public OutgoingFileTransfer createOutgoingFileTransfer(String userID) {
- if (userID == null) {
- throw new IllegalArgumentException("userID was null");
- }
- // We need to create outgoing file transfers with a full JID since this method will later
- // use XEP-0095 to negotiate the stream. This is done with IQ stanzas that need to be addressed to a full JID
- // in order to reach an client entity.
- else if (!StringUtils.isFullJID(userID)) {
- throw new IllegalArgumentException("The provided user id was not a full JID (i.e. with resource part)");
- }
-
- return new OutgoingFileTransfer(connection.getUser(), userID,
- fileTransferNegotiator.getNextStreamID(),
- fileTransferNegotiator);
- }
-
- /**
- * When the file transfer request is acceptable, this method should be
- * invoked. It will create an IncomingFileTransfer which allows the
- * transmission of the file to procede.
- *
- * @param request
- * The remote request that is being accepted.
- * @return The IncomingFileTransfer which manages the download of the file
- * from the transfer initiator.
- */
- protected IncomingFileTransfer createIncomingFileTransfer(
- FileTransferRequest request) {
- if (request == null) {
- throw new NullPointerException("RecieveRequest cannot be null");
- }
-
- IncomingFileTransfer transfer = new IncomingFileTransfer(request,
- fileTransferNegotiator);
- transfer.setFileInfo(request.getFileName(), request.getFileSize());
-
- return transfer;
- }
-
- protected void rejectIncomingFileTransfer(FileTransferRequest request) {
- StreamInitiation initiation = request.getStreamInitiation();
-
- IQ rejection = FileTransferNegotiator.createIQ(
- initiation.getPacketID(), initiation.getFrom(), initiation
- .getTo(), IQ.Type.ERROR);
- rejection.setError(new XMPPError(XMPPError.Condition.no_acceptable));
- connection.sendPacket(rejection);
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.IQTypeFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.packet.StreamInitiation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The file transfer manager class handles the sending and recieving of files.
+ * To send a file invoke the {@link #createOutgoingFileTransfer(String)} method.
+ * <p>
+ * And to recieve a file add a file transfer listener to the manager. The
+ * listener will notify you when there is a new file transfer request. To create
+ * the {@link IncomingFileTransfer} object accept the transfer, or, if the
+ * transfer is not desirable reject it.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+public class FileTransferManager {
+
+ private final FileTransferNegotiator fileTransferNegotiator;
+
+ private List<FileTransferListener> listeners;
+
+ private Connection connection;
+
+ /**
+ * Creates a file transfer manager to initiate and receive file transfers.
+ *
+ * @param connection
+ * The Connection that the file transfers will use.
+ */
+ public FileTransferManager(Connection connection) {
+ this.connection = connection;
+ this.fileTransferNegotiator = FileTransferNegotiator
+ .getInstanceFor(connection);
+ }
+
+ /**
+ * Add a file transfer listener to listen to incoming file transfer
+ * requests.
+ *
+ * @param li
+ * The listener
+ * @see #removeFileTransferListener(FileTransferListener)
+ * @see FileTransferListener
+ */
+ public void addFileTransferListener(final FileTransferListener li) {
+ if (listeners == null) {
+ initListeners();
+ }
+ synchronized (this.listeners) {
+ listeners.add(li);
+ }
+ }
+
+ private void initListeners() {
+ listeners = new ArrayList<FileTransferListener>();
+
+ connection.addPacketListener(new PacketListener() {
+ public void processPacket(Packet packet) {
+ fireNewRequest((StreamInitiation) packet);
+ }
+ }, new AndFilter(new PacketTypeFilter(StreamInitiation.class),
+ new IQTypeFilter(IQ.Type.SET)));
+ }
+
+ protected void fireNewRequest(StreamInitiation initiation) {
+ FileTransferListener[] listeners = null;
+ synchronized (this.listeners) {
+ listeners = new FileTransferListener[this.listeners.size()];
+ this.listeners.toArray(listeners);
+ }
+ FileTransferRequest request = new FileTransferRequest(this, initiation);
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].fileTransferRequest(request);
+ }
+ }
+
+ /**
+ * Removes a file transfer listener.
+ *
+ * @param li
+ * The file transfer listener to be removed
+ * @see FileTransferListener
+ */
+ public void removeFileTransferListener(final FileTransferListener li) {
+ if (listeners == null) {
+ return;
+ }
+ synchronized (this.listeners) {
+ listeners.remove(li);
+ }
+ }
+
+ /**
+ * Creates an OutgoingFileTransfer to send a file to another user.
+ *
+ * @param userID
+ * The fully qualified jabber ID (i.e. full JID) with resource of the user to
+ * send the file to.
+ * @return The send file object on which the negotiated transfer can be run.
+ * @exception IllegalArgumentException if userID is null or not a full JID
+ */
+ public OutgoingFileTransfer createOutgoingFileTransfer(String userID) {
+ if (userID == null) {
+ throw new IllegalArgumentException("userID was null");
+ }
+ // We need to create outgoing file transfers with a full JID since this method will later
+ // use XEP-0095 to negotiate the stream. This is done with IQ stanzas that need to be addressed to a full JID
+ // in order to reach an client entity.
+ else if (!StringUtils.isFullJID(userID)) {
+ throw new IllegalArgumentException("The provided user id was not a full JID (i.e. with resource part)");
+ }
+
+ return new OutgoingFileTransfer(connection.getUser(), userID,
+ fileTransferNegotiator.getNextStreamID(),
+ fileTransferNegotiator);
+ }
+
+ /**
+ * When the file transfer request is acceptable, this method should be
+ * invoked. It will create an IncomingFileTransfer which allows the
+ * transmission of the file to procede.
+ *
+ * @param request
+ * The remote request that is being accepted.
+ * @return The IncomingFileTransfer which manages the download of the file
+ * from the transfer initiator.
+ */
+ protected IncomingFileTransfer createIncomingFileTransfer(
+ FileTransferRequest request) {
+ if (request == null) {
+ throw new NullPointerException("RecieveRequest cannot be null");
+ }
+
+ IncomingFileTransfer transfer = new IncomingFileTransfer(request,
+ fileTransferNegotiator);
+ transfer.setFileInfo(request.getFileName(), request.getFileSize());
+
+ return transfer;
+ }
+
+ protected void rejectIncomingFileTransfer(FileTransferRequest request) {
+ StreamInitiation initiation = request.getStreamInitiation();
+
+ IQ rejection = FileTransferNegotiator.createIQ(
+ initiation.getPacketID(), initiation.getFrom(), initiation
+ .getTo(), IQ.Type.ERROR);
+ rejection.setError(new XMPPError(XMPPError.Condition.no_acceptable));
+ connection.sendPacket(rejection);
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java
index d1fb7bf3d..3b2b30d9d 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java
@@ -1,485 +1,485 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.ConnectionListener;
-import org.jivesoftware.smack.PacketCollector;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.PacketIDFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.FormField;
-import org.jivesoftware.smackx.ServiceDiscoveryManager;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
-import org.jivesoftware.smackx.packet.DataForm;
-import org.jivesoftware.smackx.packet.StreamInitiation;
-
-/**
- * Manages the negotiation of file transfers according to JEP-0096. If a file is
- * being sent the remote user chooses the type of stream under which the file
- * will be sent.
- *
- * @author Alexander Wenckus
- * @see <a href="http://xmpp.org/extensions/xep-0096.html">XEP-0096: SI File Transfer</a>
- */
-public class FileTransferNegotiator {
-
- // Static
-
- private static final String[] NAMESPACE = {
- "http://jabber.org/protocol/si/profile/file-transfer",
- "http://jabber.org/protocol/si"};
-
- private static final Map<Connection, FileTransferNegotiator> transferObject =
- new ConcurrentHashMap<Connection, FileTransferNegotiator>();
-
- private static final String STREAM_INIT_PREFIX = "jsi_";
-
- protected static final String STREAM_DATA_FIELD_NAME = "stream-method";
-
- private static final Random randomGenerator = new Random();
-
- /**
- * A static variable to use only offer IBB for file transfer. It is generally recommend to only
- * set this variable to true for testing purposes as IBB is the backup file transfer method
- * and shouldn't be used as the only transfer method in production systems.
- */
- public static boolean IBB_ONLY = (System.getProperty("ibb") != null);//true;
-
- /**
- * Returns the file transfer negotiator related to a particular connection.
- * When this class is requested on a particular connection the file transfer
- * service is automatically enabled.
- *
- * @param connection The connection for which the transfer manager is desired
- * @return The IMFileTransferManager
- */
- public static FileTransferNegotiator getInstanceFor(
- final Connection connection) {
- if (connection == null) {
- throw new IllegalArgumentException("Connection cannot be null");
- }
- if (!connection.isConnected()) {
- return null;
- }
-
- if (transferObject.containsKey(connection)) {
- return transferObject.get(connection);
- }
- else {
- FileTransferNegotiator transfer = new FileTransferNegotiator(
- connection);
- setServiceEnabled(connection, true);
- transferObject.put(connection, transfer);
- return transfer;
- }
- }
-
- /**
- * Enable the Jabber services related to file transfer on the particular
- * connection.
- *
- * @param connection The connection on which to enable or disable the services.
- * @param isEnabled True to enable, false to disable.
- */
- public static void setServiceEnabled(final Connection connection,
- final boolean isEnabled) {
- ServiceDiscoveryManager manager = ServiceDiscoveryManager
- .getInstanceFor(connection);
-
- List<String> namespaces = new ArrayList<String>();
- namespaces.addAll(Arrays.asList(NAMESPACE));
- namespaces.add(InBandBytestreamManager.NAMESPACE);
- if (!IBB_ONLY) {
- namespaces.add(Socks5BytestreamManager.NAMESPACE);
- }
-
- for (String namespace : namespaces) {
- if (isEnabled) {
- if (!manager.includesFeature(namespace)) {
- manager.addFeature(namespace);
- }
- } else {
- manager.removeFeature(namespace);
- }
- }
-
- }
-
- /**
- * Checks to see if all file transfer related services are enabled on the
- * connection.
- *
- * @param connection The connection to check
- * @return True if all related services are enabled, false if they are not.
- */
- public static boolean isServiceEnabled(final Connection connection) {
- ServiceDiscoveryManager manager = ServiceDiscoveryManager
- .getInstanceFor(connection);
-
- List<String> namespaces = new ArrayList<String>();
- namespaces.addAll(Arrays.asList(NAMESPACE));
- namespaces.add(InBandBytestreamManager.NAMESPACE);
- if (!IBB_ONLY) {
- namespaces.add(Socks5BytestreamManager.NAMESPACE);
- }
-
- for (String namespace : namespaces) {
- if (!manager.includesFeature(namespace)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * A convenience method to create an IQ packet.
- *
- * @param ID The packet ID of the
- * @param to To whom the packet is addressed.
- * @param from From whom the packet is sent.
- * @param type The IQ type of the packet.
- * @return The created IQ packet.
- */
- public static IQ createIQ(final String ID, final String to,
- final String from, final IQ.Type type) {
- IQ iqPacket = new IQ() {
- public String getChildElementXML() {
- return null;
- }
- };
- iqPacket.setPacketID(ID);
- iqPacket.setTo(to);
- iqPacket.setFrom(from);
- iqPacket.setType(type);
-
- return iqPacket;
- }
-
- /**
- * Returns a collection of the supported transfer protocols.
- *
- * @return Returns a collection of the supported transfer protocols.
- */
- public static Collection<String> getSupportedProtocols() {
- List<String> protocols = new ArrayList<String>();
- protocols.add(InBandBytestreamManager.NAMESPACE);
- if (!IBB_ONLY) {
- protocols.add(Socks5BytestreamManager.NAMESPACE);
- }
- return Collections.unmodifiableList(protocols);
- }
-
- // non-static
-
- private final Connection connection;
-
- private final StreamNegotiator byteStreamTransferManager;
-
- private final StreamNegotiator inbandTransferManager;
-
- private FileTransferNegotiator(final Connection connection) {
- configureConnection(connection);
-
- this.connection = connection;
- byteStreamTransferManager = new Socks5TransferNegotiator(connection);
- inbandTransferManager = new IBBTransferNegotiator(connection);
- }
-
- private void configureConnection(final Connection connection) {
- connection.addConnectionListener(new ConnectionListener() {
- public void connectionClosed() {
- cleanup(connection);
- }
-
- public void connectionClosedOnError(Exception e) {
- cleanup(connection);
- }
-
- public void reconnectionFailed(Exception e) {
- // ignore
- }
-
- public void reconnectionSuccessful() {
- // ignore
- }
-
- public void reconnectingIn(int seconds) {
- // ignore
- }
- });
- }
-
- private void cleanup(final Connection connection) {
- if (transferObject.remove(connection) != null) {
- inbandTransferManager.cleanup();
- }
- }
-
- /**
- * Selects an appropriate stream negotiator after examining the incoming file transfer request.
- *
- * @param request The related file transfer request.
- * @return The file transfer object that handles the transfer
- * @throws XMPPException If there are either no stream methods contained in the packet, or
- * there is not an appropriate stream method.
- */
- public StreamNegotiator selectStreamNegotiator(
- FileTransferRequest request) throws XMPPException {
- StreamInitiation si = request.getStreamInitiation();
- FormField streamMethodField = getStreamMethodField(si
- .getFeatureNegotiationForm());
-
- if (streamMethodField == null) {
- String errorMessage = "No stream methods contained in packet.";
- XMPPError error = new XMPPError(XMPPError.Condition.bad_request, errorMessage);
- IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
- IQ.Type.ERROR);
- iqPacket.setError(error);
- connection.sendPacket(iqPacket);
- throw new XMPPException(errorMessage, error);
- }
-
- // select the appropriate protocol
-
- StreamNegotiator selectedStreamNegotiator;
- try {
- selectedStreamNegotiator = getNegotiator(streamMethodField);
- }
- catch (XMPPException e) {
- IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
- IQ.Type.ERROR);
- iqPacket.setError(e.getXMPPError());
- connection.sendPacket(iqPacket);
- throw e;
- }
-
- // return the appropriate negotiator
-
- return selectedStreamNegotiator;
- }
-
- private FormField getStreamMethodField(DataForm form) {
- FormField field = null;
- for (Iterator<FormField> it = form.getFields(); it.hasNext();) {
- field = it.next();
- if (field.getVariable().equals(STREAM_DATA_FIELD_NAME)) {
- break;
- }
- field = null;
- }
- return field;
- }
-
- private StreamNegotiator getNegotiator(final FormField field)
- throws XMPPException {
- String variable;
- boolean isByteStream = false;
- boolean isIBB = false;
- for (Iterator<FormField.Option> it = field.getOptions(); it.hasNext();) {
- variable = it.next().getValue();
- if (variable.equals(Socks5BytestreamManager.NAMESPACE) && !IBB_ONLY) {
- isByteStream = true;
- }
- else if (variable.equals(InBandBytestreamManager.NAMESPACE)) {
- isIBB = true;
- }
- }
-
- if (!isByteStream && !isIBB) {
- XMPPError error = new XMPPError(XMPPError.Condition.bad_request,
- "No acceptable transfer mechanism");
- throw new XMPPException(error.getMessage(), error);
- }
-
- //if (isByteStream && isIBB && field.getType().equals(FormField.TYPE_LIST_MULTI)) {
- if (isByteStream && isIBB) {
- return new FaultTolerantNegotiator(connection,
- byteStreamTransferManager,
- inbandTransferManager);
- }
- else if (isByteStream) {
- return byteStreamTransferManager;
- }
- else {
- return inbandTransferManager;
- }
- }
-
- /**
- * Reject a stream initiation request from a remote user.
- *
- * @param si The Stream Initiation request to reject.
- */
- public void rejectStream(final StreamInitiation si) {
- XMPPError error = new XMPPError(XMPPError.Condition.forbidden, "Offer Declined");
- IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
- IQ.Type.ERROR);
- iqPacket.setError(error);
- connection.sendPacket(iqPacket);
- }
-
- /**
- * Returns a new, unique, stream ID to identify a file transfer.
- *
- * @return Returns a new, unique, stream ID to identify a file transfer.
- */
- public String getNextStreamID() {
- StringBuilder buffer = new StringBuilder();
- buffer.append(STREAM_INIT_PREFIX);
- buffer.append(Math.abs(randomGenerator.nextLong()));
-
- return buffer.toString();
- }
-
- /**
- * Send a request to another user to send them a file. The other user has
- * the option of, accepting, rejecting, or not responding to a received file
- * transfer request.
- * <p/>
- * If they accept, the packet will contain the other user's chosen stream
- * type to send the file across. The two choices this implementation
- * provides to the other user for file transfer are <a
- * href="http://www.jabber.org/jeps/jep-0065.html">SOCKS5 Bytestreams</a>,
- * which is the preferred method of transfer, and <a
- * href="http://www.jabber.org/jeps/jep-0047.html">In-Band Bytestreams</a>,
- * which is the fallback mechanism.
- * <p/>
- * The other user may choose to decline the file request if they do not
- * desire the file, their client does not support JEP-0096, or if there are
- * no acceptable means to transfer the file.
- * <p/>
- * Finally, if the other user does not respond this method will return null
- * after the specified timeout.
- *
- * @param userID The userID of the user to whom the file will be sent.
- * @param streamID The unique identifier for this file transfer.
- * @param fileName The name of this file. Preferably it should include an
- * extension as it is used to determine what type of file it is.
- * @param size The size, in bytes, of the file.
- * @param desc A description of the file.
- * @param responseTimeout The amount of time, in milliseconds, to wait for the remote
- * user to respond. If they do not respond in time, this
- * @return Returns the stream negotiator selected by the peer.
- * @throws XMPPException Thrown if there is an error negotiating the file transfer.
- */
- public StreamNegotiator negotiateOutgoingTransfer(final String userID,
- final String streamID, final String fileName, final long size,
- final String desc, int responseTimeout) throws XMPPException {
- StreamInitiation si = new StreamInitiation();
- si.setSesssionID(streamID);
- si.setMimeType(URLConnection.guessContentTypeFromName(fileName));
-
- StreamInitiation.File siFile = new StreamInitiation.File(fileName, size);
- siFile.setDesc(desc);
- si.setFile(siFile);
-
- si.setFeatureNegotiationForm(createDefaultInitiationForm());
-
- si.setFrom(connection.getUser());
- si.setTo(userID);
- si.setType(IQ.Type.SET);
-
- PacketCollector collector = connection
- .createPacketCollector(new PacketIDFilter(si.getPacketID()));
- connection.sendPacket(si);
- Packet siResponse = collector.nextResult(responseTimeout);
- collector.cancel();
-
- if (siResponse instanceof IQ) {
- IQ iqResponse = (IQ) siResponse;
- if (iqResponse.getType().equals(IQ.Type.RESULT)) {
- StreamInitiation response = (StreamInitiation) siResponse;
- return getOutgoingNegotiator(getStreamMethodField(response
- .getFeatureNegotiationForm()));
-
- }
- else if (iqResponse.getType().equals(IQ.Type.ERROR)) {
- throw new XMPPException(iqResponse.getError());
- }
- else {
- throw new XMPPException("File transfer response unreadable");
- }
- }
- else {
- return null;
- }
- }
-
- private StreamNegotiator getOutgoingNegotiator(final FormField field)
- throws XMPPException {
- String variable;
- boolean isByteStream = false;
- boolean isIBB = false;
- for (Iterator<String> it = field.getValues(); it.hasNext();) {
- variable = it.next();
- if (variable.equals(Socks5BytestreamManager.NAMESPACE) && !IBB_ONLY) {
- isByteStream = true;
- }
- else if (variable.equals(InBandBytestreamManager.NAMESPACE)) {
- isIBB = true;
- }
- }
-
- if (!isByteStream && !isIBB) {
- XMPPError error = new XMPPError(XMPPError.Condition.bad_request,
- "No acceptable transfer mechanism");
- throw new XMPPException(error.getMessage(), error);
- }
-
- if (isByteStream && isIBB) {
- return new FaultTolerantNegotiator(connection,
- byteStreamTransferManager, inbandTransferManager);
- }
- else if (isByteStream) {
- return byteStreamTransferManager;
- }
- else {
- return inbandTransferManager;
- }
- }
-
- private DataForm createDefaultInitiationForm() {
- DataForm form = new DataForm(Form.TYPE_FORM);
- FormField field = new FormField(STREAM_DATA_FIELD_NAME);
- field.setType(FormField.TYPE_LIST_SINGLE);
- if (!IBB_ONLY) {
- field.addOption(new FormField.Option(Socks5BytestreamManager.NAMESPACE));
- }
- field.addOption(new FormField.Option(InBandBytestreamManager.NAMESPACE));
- form.addField(field);
- return form;
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.ConnectionListener;
+import org.jivesoftware.smack.PacketCollector;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketIDFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.FormField;
+import org.jivesoftware.smackx.ServiceDiscoveryManager;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
+import org.jivesoftware.smackx.packet.DataForm;
+import org.jivesoftware.smackx.packet.StreamInitiation;
+
+/**
+ * Manages the negotiation of file transfers according to JEP-0096. If a file is
+ * being sent the remote user chooses the type of stream under which the file
+ * will be sent.
+ *
+ * @author Alexander Wenckus
+ * @see <a href="http://xmpp.org/extensions/xep-0096.html">XEP-0096: SI File Transfer</a>
+ */
+public class FileTransferNegotiator {
+
+ // Static
+
+ private static final String[] NAMESPACE = {
+ "http://jabber.org/protocol/si/profile/file-transfer",
+ "http://jabber.org/protocol/si"};
+
+ private static final Map<Connection, FileTransferNegotiator> transferObject =
+ new ConcurrentHashMap<Connection, FileTransferNegotiator>();
+
+ private static final String STREAM_INIT_PREFIX = "jsi_";
+
+ protected static final String STREAM_DATA_FIELD_NAME = "stream-method";
+
+ private static final Random randomGenerator = new Random();
+
+ /**
+ * A static variable to use only offer IBB for file transfer. It is generally recommend to only
+ * set this variable to true for testing purposes as IBB is the backup file transfer method
+ * and shouldn't be used as the only transfer method in production systems.
+ */
+ public static boolean IBB_ONLY = (System.getProperty("ibb") != null);//true;
+
+ /**
+ * Returns the file transfer negotiator related to a particular connection.
+ * When this class is requested on a particular connection the file transfer
+ * service is automatically enabled.
+ *
+ * @param connection The connection for which the transfer manager is desired
+ * @return The IMFileTransferManager
+ */
+ public static FileTransferNegotiator getInstanceFor(
+ final Connection connection) {
+ if (connection == null) {
+ throw new IllegalArgumentException("Connection cannot be null");
+ }
+ if (!connection.isConnected()) {
+ return null;
+ }
+
+ if (transferObject.containsKey(connection)) {
+ return transferObject.get(connection);
+ }
+ else {
+ FileTransferNegotiator transfer = new FileTransferNegotiator(
+ connection);
+ setServiceEnabled(connection, true);
+ transferObject.put(connection, transfer);
+ return transfer;
+ }
+ }
+
+ /**
+ * Enable the Jabber services related to file transfer on the particular
+ * connection.
+ *
+ * @param connection The connection on which to enable or disable the services.
+ * @param isEnabled True to enable, false to disable.
+ */
+ public static void setServiceEnabled(final Connection connection,
+ final boolean isEnabled) {
+ ServiceDiscoveryManager manager = ServiceDiscoveryManager
+ .getInstanceFor(connection);
+
+ List<String> namespaces = new ArrayList<String>();
+ namespaces.addAll(Arrays.asList(NAMESPACE));
+ namespaces.add(InBandBytestreamManager.NAMESPACE);
+ if (!IBB_ONLY) {
+ namespaces.add(Socks5BytestreamManager.NAMESPACE);
+ }
+
+ for (String namespace : namespaces) {
+ if (isEnabled) {
+ if (!manager.includesFeature(namespace)) {
+ manager.addFeature(namespace);
+ }
+ } else {
+ manager.removeFeature(namespace);
+ }
+ }
+
+ }
+
+ /**
+ * Checks to see if all file transfer related services are enabled on the
+ * connection.
+ *
+ * @param connection The connection to check
+ * @return True if all related services are enabled, false if they are not.
+ */
+ public static boolean isServiceEnabled(final Connection connection) {
+ ServiceDiscoveryManager manager = ServiceDiscoveryManager
+ .getInstanceFor(connection);
+
+ List<String> namespaces = new ArrayList<String>();
+ namespaces.addAll(Arrays.asList(NAMESPACE));
+ namespaces.add(InBandBytestreamManager.NAMESPACE);
+ if (!IBB_ONLY) {
+ namespaces.add(Socks5BytestreamManager.NAMESPACE);
+ }
+
+ for (String namespace : namespaces) {
+ if (!manager.includesFeature(namespace)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A convenience method to create an IQ packet.
+ *
+ * @param ID The packet ID of the
+ * @param to To whom the packet is addressed.
+ * @param from From whom the packet is sent.
+ * @param type The IQ type of the packet.
+ * @return The created IQ packet.
+ */
+ public static IQ createIQ(final String ID, final String to,
+ final String from, final IQ.Type type) {
+ IQ iqPacket = new IQ() {
+ public String getChildElementXML() {
+ return null;
+ }
+ };
+ iqPacket.setPacketID(ID);
+ iqPacket.setTo(to);
+ iqPacket.setFrom(from);
+ iqPacket.setType(type);
+
+ return iqPacket;
+ }
+
+ /**
+ * Returns a collection of the supported transfer protocols.
+ *
+ * @return Returns a collection of the supported transfer protocols.
+ */
+ public static Collection<String> getSupportedProtocols() {
+ List<String> protocols = new ArrayList<String>();
+ protocols.add(InBandBytestreamManager.NAMESPACE);
+ if (!IBB_ONLY) {
+ protocols.add(Socks5BytestreamManager.NAMESPACE);
+ }
+ return Collections.unmodifiableList(protocols);
+ }
+
+ // non-static
+
+ private final Connection connection;
+
+ private final StreamNegotiator byteStreamTransferManager;
+
+ private final StreamNegotiator inbandTransferManager;
+
+ private FileTransferNegotiator(final Connection connection) {
+ configureConnection(connection);
+
+ this.connection = connection;
+ byteStreamTransferManager = new Socks5TransferNegotiator(connection);
+ inbandTransferManager = new IBBTransferNegotiator(connection);
+ }
+
+ private void configureConnection(final Connection connection) {
+ connection.addConnectionListener(new ConnectionListener() {
+ public void connectionClosed() {
+ cleanup(connection);
+ }
+
+ public void connectionClosedOnError(Exception e) {
+ cleanup(connection);
+ }
+
+ public void reconnectionFailed(Exception e) {
+ // ignore
+ }
+
+ public void reconnectionSuccessful() {
+ // ignore
+ }
+
+ public void reconnectingIn(int seconds) {
+ // ignore
+ }
+ });
+ }
+
+ private void cleanup(final Connection connection) {
+ if (transferObject.remove(connection) != null) {
+ inbandTransferManager.cleanup();
+ }
+ }
+
+ /**
+ * Selects an appropriate stream negotiator after examining the incoming file transfer request.
+ *
+ * @param request The related file transfer request.
+ * @return The file transfer object that handles the transfer
+ * @throws XMPPException If there are either no stream methods contained in the packet, or
+ * there is not an appropriate stream method.
+ */
+ public StreamNegotiator selectStreamNegotiator(
+ FileTransferRequest request) throws XMPPException {
+ StreamInitiation si = request.getStreamInitiation();
+ FormField streamMethodField = getStreamMethodField(si
+ .getFeatureNegotiationForm());
+
+ if (streamMethodField == null) {
+ String errorMessage = "No stream methods contained in packet.";
+ XMPPError error = new XMPPError(XMPPError.Condition.bad_request, errorMessage);
+ IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
+ IQ.Type.ERROR);
+ iqPacket.setError(error);
+ connection.sendPacket(iqPacket);
+ throw new XMPPException(errorMessage, error);
+ }
+
+ // select the appropriate protocol
+
+ StreamNegotiator selectedStreamNegotiator;
+ try {
+ selectedStreamNegotiator = getNegotiator(streamMethodField);
+ }
+ catch (XMPPException e) {
+ IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
+ IQ.Type.ERROR);
+ iqPacket.setError(e.getXMPPError());
+ connection.sendPacket(iqPacket);
+ throw e;
+ }
+
+ // return the appropriate negotiator
+
+ return selectedStreamNegotiator;
+ }
+
+ private FormField getStreamMethodField(DataForm form) {
+ FormField field = null;
+ for (Iterator<FormField> it = form.getFields(); it.hasNext();) {
+ field = it.next();
+ if (field.getVariable().equals(STREAM_DATA_FIELD_NAME)) {
+ break;
+ }
+ field = null;
+ }
+ return field;
+ }
+
+ private StreamNegotiator getNegotiator(final FormField field)
+ throws XMPPException {
+ String variable;
+ boolean isByteStream = false;
+ boolean isIBB = false;
+ for (Iterator<FormField.Option> it = field.getOptions(); it.hasNext();) {
+ variable = it.next().getValue();
+ if (variable.equals(Socks5BytestreamManager.NAMESPACE) && !IBB_ONLY) {
+ isByteStream = true;
+ }
+ else if (variable.equals(InBandBytestreamManager.NAMESPACE)) {
+ isIBB = true;
+ }
+ }
+
+ if (!isByteStream && !isIBB) {
+ XMPPError error = new XMPPError(XMPPError.Condition.bad_request,
+ "No acceptable transfer mechanism");
+ throw new XMPPException(error.getMessage(), error);
+ }
+
+ //if (isByteStream && isIBB && field.getType().equals(FormField.TYPE_LIST_MULTI)) {
+ if (isByteStream && isIBB) {
+ return new FaultTolerantNegotiator(connection,
+ byteStreamTransferManager,
+ inbandTransferManager);
+ }
+ else if (isByteStream) {
+ return byteStreamTransferManager;
+ }
+ else {
+ return inbandTransferManager;
+ }
+ }
+
+ /**
+ * Reject a stream initiation request from a remote user.
+ *
+ * @param si The Stream Initiation request to reject.
+ */
+ public void rejectStream(final StreamInitiation si) {
+ XMPPError error = new XMPPError(XMPPError.Condition.forbidden, "Offer Declined");
+ IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(),
+ IQ.Type.ERROR);
+ iqPacket.setError(error);
+ connection.sendPacket(iqPacket);
+ }
+
+ /**
+ * Returns a new, unique, stream ID to identify a file transfer.
+ *
+ * @return Returns a new, unique, stream ID to identify a file transfer.
+ */
+ public String getNextStreamID() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(STREAM_INIT_PREFIX);
+ buffer.append(Math.abs(randomGenerator.nextLong()));
+
+ return buffer.toString();
+ }
+
+ /**
+ * Send a request to another user to send them a file. The other user has
+ * the option of, accepting, rejecting, or not responding to a received file
+ * transfer request.
+ * <p/>
+ * If they accept, the packet will contain the other user's chosen stream
+ * type to send the file across. The two choices this implementation
+ * provides to the other user for file transfer are <a
+ * href="http://www.jabber.org/jeps/jep-0065.html">SOCKS5 Bytestreams</a>,
+ * which is the preferred method of transfer, and <a
+ * href="http://www.jabber.org/jeps/jep-0047.html">In-Band Bytestreams</a>,
+ * which is the fallback mechanism.
+ * <p/>
+ * The other user may choose to decline the file request if they do not
+ * desire the file, their client does not support JEP-0096, or if there are
+ * no acceptable means to transfer the file.
+ * <p/>
+ * Finally, if the other user does not respond this method will return null
+ * after the specified timeout.
+ *
+ * @param userID The userID of the user to whom the file will be sent.
+ * @param streamID The unique identifier for this file transfer.
+ * @param fileName The name of this file. Preferably it should include an
+ * extension as it is used to determine what type of file it is.
+ * @param size The size, in bytes, of the file.
+ * @param desc A description of the file.
+ * @param responseTimeout The amount of time, in milliseconds, to wait for the remote
+ * user to respond. If they do not respond in time, this
+ * @return Returns the stream negotiator selected by the peer.
+ * @throws XMPPException Thrown if there is an error negotiating the file transfer.
+ */
+ public StreamNegotiator negotiateOutgoingTransfer(final String userID,
+ final String streamID, final String fileName, final long size,
+ final String desc, int responseTimeout) throws XMPPException {
+ StreamInitiation si = new StreamInitiation();
+ si.setSesssionID(streamID);
+ si.setMimeType(URLConnection.guessContentTypeFromName(fileName));
+
+ StreamInitiation.File siFile = new StreamInitiation.File(fileName, size);
+ siFile.setDesc(desc);
+ si.setFile(siFile);
+
+ si.setFeatureNegotiationForm(createDefaultInitiationForm());
+
+ si.setFrom(connection.getUser());
+ si.setTo(userID);
+ si.setType(IQ.Type.SET);
+
+ PacketCollector collector = connection
+ .createPacketCollector(new PacketIDFilter(si.getPacketID()));
+ connection.sendPacket(si);
+ Packet siResponse = collector.nextResult(responseTimeout);
+ collector.cancel();
+
+ if (siResponse instanceof IQ) {
+ IQ iqResponse = (IQ) siResponse;
+ if (iqResponse.getType().equals(IQ.Type.RESULT)) {
+ StreamInitiation response = (StreamInitiation) siResponse;
+ return getOutgoingNegotiator(getStreamMethodField(response
+ .getFeatureNegotiationForm()));
+
+ }
+ else if (iqResponse.getType().equals(IQ.Type.ERROR)) {
+ throw new XMPPException(iqResponse.getError());
+ }
+ else {
+ throw new XMPPException("File transfer response unreadable");
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ private StreamNegotiator getOutgoingNegotiator(final FormField field)
+ throws XMPPException {
+ String variable;
+ boolean isByteStream = false;
+ boolean isIBB = false;
+ for (Iterator<String> it = field.getValues(); it.hasNext();) {
+ variable = it.next();
+ if (variable.equals(Socks5BytestreamManager.NAMESPACE) && !IBB_ONLY) {
+ isByteStream = true;
+ }
+ else if (variable.equals(InBandBytestreamManager.NAMESPACE)) {
+ isIBB = true;
+ }
+ }
+
+ if (!isByteStream && !isIBB) {
+ XMPPError error = new XMPPError(XMPPError.Condition.bad_request,
+ "No acceptable transfer mechanism");
+ throw new XMPPException(error.getMessage(), error);
+ }
+
+ if (isByteStream && isIBB) {
+ return new FaultTolerantNegotiator(connection,
+ byteStreamTransferManager, inbandTransferManager);
+ }
+ else if (isByteStream) {
+ return byteStreamTransferManager;
+ }
+ else {
+ return inbandTransferManager;
+ }
+ }
+
+ private DataForm createDefaultInitiationForm() {
+ DataForm form = new DataForm(Form.TYPE_FORM);
+ FormField field = new FormField(STREAM_DATA_FIELD_NAME);
+ field.setType(FormField.TYPE_LIST_SINGLE);
+ if (!IBB_ONLY) {
+ field.addOption(new FormField.Option(Socks5BytestreamManager.NAMESPACE));
+ }
+ field.addOption(new FormField.Option(InBandBytestreamManager.NAMESPACE));
+ form.addField(field);
+ return form;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferRequest.java
index 6b5ccd858..69a073f67 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/FileTransferRequest.java
@@ -1,138 +1,138 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-import org.jivesoftware.smackx.packet.StreamInitiation;
-
-/**
- * A request to send a file recieved from another user.
- *
- * @author Alexander Wenckus
- *
- */
-public class FileTransferRequest {
- private final StreamInitiation streamInitiation;
-
- private final FileTransferManager manager;
-
- /**
- * A recieve request is constructed from the Stream Initiation request
- * received from the initator.
- *
- * @param manager
- * The manager handling this file transfer
- *
- * @param si
- * The Stream initiaton recieved from the initiator.
- */
- public FileTransferRequest(FileTransferManager manager, StreamInitiation si) {
- this.streamInitiation = si;
- this.manager = manager;
- }
-
- /**
- * Returns the name of the file.
- *
- * @return Returns the name of the file.
- */
- public String getFileName() {
- return streamInitiation.getFile().getName();
- }
-
- /**
- * Returns the size in bytes of the file.
- *
- * @return Returns the size in bytes of the file.
- */
- public long getFileSize() {
- return streamInitiation.getFile().getSize();
- }
-
- /**
- * Returns the description of the file provided by the requestor.
- *
- * @return Returns the description of the file provided by the requestor.
- */
- public String getDescription() {
- return streamInitiation.getFile().getDesc();
- }
-
- /**
- * Returns the mime-type of the file.
- *
- * @return Returns the mime-type of the file.
- */
- public String getMimeType() {
- return streamInitiation.getMimeType();
- }
-
- /**
- * Returns the fully-qualified jabber ID of the user that requested this
- * file transfer.
- *
- * @return Returns the fully-qualified jabber ID of the user that requested
- * this file transfer.
- */
- public String getRequestor() {
- return streamInitiation.getFrom();
- }
-
- /**
- * Returns the stream ID that uniquely identifies this file transfer.
- *
- * @return Returns the stream ID that uniquely identifies this file
- * transfer.
- */
- public String getStreamID() {
- return streamInitiation.getSessionID();
- }
-
- /**
- * Returns the stream initiation packet that was sent by the requestor which
- * contains the parameters of the file transfer being transfer and also the
- * methods available to transfer the file.
- *
- * @return Returns the stream initiation packet that was sent by the
- * requestor which contains the parameters of the file transfer
- * being transfer and also the methods available to transfer the
- * file.
- */
- protected StreamInitiation getStreamInitiation() {
- return streamInitiation;
- }
-
- /**
- * Accepts this file transfer and creates the incoming file transfer.
- *
- * @return Returns the <b><i>IncomingFileTransfer</b></i> on which the
- * file transfer can be carried out.
- */
- public IncomingFileTransfer accept() {
- return manager.createIncomingFileTransfer(this);
- }
-
- /**
- * Rejects the file transfer request.
- */
- public void reject() {
- manager.rejectIncomingFileTransfer(this);
- }
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+import org.jivesoftware.smackx.packet.StreamInitiation;
+
+/**
+ * A request to send a file recieved from another user.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+public class FileTransferRequest {
+ private final StreamInitiation streamInitiation;
+
+ private final FileTransferManager manager;
+
+ /**
+ * A recieve request is constructed from the Stream Initiation request
+ * received from the initator.
+ *
+ * @param manager
+ * The manager handling this file transfer
+ *
+ * @param si
+ * The Stream initiaton recieved from the initiator.
+ */
+ public FileTransferRequest(FileTransferManager manager, StreamInitiation si) {
+ this.streamInitiation = si;
+ this.manager = manager;
+ }
+
+ /**
+ * Returns the name of the file.
+ *
+ * @return Returns the name of the file.
+ */
+ public String getFileName() {
+ return streamInitiation.getFile().getName();
+ }
+
+ /**
+ * Returns the size in bytes of the file.
+ *
+ * @return Returns the size in bytes of the file.
+ */
+ public long getFileSize() {
+ return streamInitiation.getFile().getSize();
+ }
+
+ /**
+ * Returns the description of the file provided by the requestor.
+ *
+ * @return Returns the description of the file provided by the requestor.
+ */
+ public String getDescription() {
+ return streamInitiation.getFile().getDesc();
+ }
+
+ /**
+ * Returns the mime-type of the file.
+ *
+ * @return Returns the mime-type of the file.
+ */
+ public String getMimeType() {
+ return streamInitiation.getMimeType();
+ }
+
+ /**
+ * Returns the fully-qualified jabber ID of the user that requested this
+ * file transfer.
+ *
+ * @return Returns the fully-qualified jabber ID of the user that requested
+ * this file transfer.
+ */
+ public String getRequestor() {
+ return streamInitiation.getFrom();
+ }
+
+ /**
+ * Returns the stream ID that uniquely identifies this file transfer.
+ *
+ * @return Returns the stream ID that uniquely identifies this file
+ * transfer.
+ */
+ public String getStreamID() {
+ return streamInitiation.getSessionID();
+ }
+
+ /**
+ * Returns the stream initiation packet that was sent by the requestor which
+ * contains the parameters of the file transfer being transfer and also the
+ * methods available to transfer the file.
+ *
+ * @return Returns the stream initiation packet that was sent by the
+ * requestor which contains the parameters of the file transfer
+ * being transfer and also the methods available to transfer the
+ * file.
+ */
+ protected StreamInitiation getStreamInitiation() {
+ return streamInitiation;
+ }
+
+ /**
+ * Accepts this file transfer and creates the incoming file transfer.
+ *
+ * @return Returns the <b><i>IncomingFileTransfer</b></i> on which the
+ * file transfer can be carried out.
+ */
+ public IncomingFileTransfer accept() {
+ return manager.createIncomingFileTransfer(this);
+ }
+
+ /**
+ * Rejects the file transfer request.
+ */
+ public void reject() {
+ manager.rejectIncomingFileTransfer(this);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IBBTransferNegotiator.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IBBTransferNegotiator.java
index b32f49a66..7d5969c78 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IBBTransferNegotiator.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IBBTransferNegotiator.java
@@ -1,152 +1,152 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.FromContainsFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
-import org.jivesoftware.smackx.packet.StreamInitiation;
-
-/**
- * The In-Band Bytestream file transfer method, or IBB for short, transfers the
- * file over the same XML Stream used by XMPP. It is the fall-back mechanism in
- * case the SOCKS5 bytestream method of transferring files is not available.
- *
- * @author Alexander Wenckus
- * @author Henning Staib
- * @see <a href="http://xmpp.org/extensions/xep-0047.html">XEP-0047: In-Band
- * Bytestreams (IBB)</a>
- */
-public class IBBTransferNegotiator extends StreamNegotiator {
-
- private Connection connection;
-
- private InBandBytestreamManager manager;
-
- /**
- * The default constructor for the In-Band Bytestream Negotiator.
- *
- * @param connection The connection which this negotiator works on.
- */
- protected IBBTransferNegotiator(Connection connection) {
- this.connection = connection;
- this.manager = InBandBytestreamManager.getByteStreamManager(connection);
- }
-
- public OutputStream createOutgoingStream(String streamID, String initiator,
- String target) throws XMPPException {
- InBandBytestreamSession session = this.manager.establishSession(target, streamID);
- session.setCloseBothStreamsEnabled(true);
- return session.getOutputStream();
- }
-
- public InputStream createIncomingStream(StreamInitiation initiation)
- throws XMPPException {
- /*
- * In-Band Bytestream initiation listener must ignore next in-band
- * bytestream request with given session ID
- */
- this.manager.ignoreBytestreamRequestOnce(initiation.getSessionID());
-
- Packet streamInitiation = initiateIncomingStream(this.connection, initiation);
- return negotiateIncomingStream(streamInitiation);
- }
-
- public PacketFilter getInitiationPacketFilter(String from, String streamID) {
- /*
- * this method is always called prior to #negotiateIncomingStream() so
- * the In-Band Bytestream initiation listener must ignore the next
- * In-Band Bytestream request with the given session ID
- */
- this.manager.ignoreBytestreamRequestOnce(streamID);
-
- return new AndFilter(new FromContainsFilter(from), new IBBOpenSidFilter(streamID));
- }
-
- public String[] getNamespaces() {
- return new String[] { InBandBytestreamManager.NAMESPACE };
- }
-
- InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException {
- // build In-Band Bytestream request
- InBandBytestreamRequest request = new ByteStreamRequest(this.manager,
- (Open) streamInitiation);
-
- // always accept the request
- InBandBytestreamSession session = request.accept();
- session.setCloseBothStreamsEnabled(true);
- return session.getInputStream();
- }
-
- public void cleanup() {
- }
-
- /**
- * This PacketFilter accepts an incoming In-Band Bytestream open request
- * with a specified session ID.
- */
- private static class IBBOpenSidFilter extends PacketTypeFilter {
-
- private String sessionID;
-
- public IBBOpenSidFilter(String sessionID) {
- super(Open.class);
- if (sessionID == null) {
- throw new IllegalArgumentException("StreamID cannot be null");
- }
- this.sessionID = sessionID;
- }
-
- public boolean accept(Packet packet) {
- if (super.accept(packet)) {
- Open bytestream = (Open) packet;
-
- // packet must by of type SET and contains the given session ID
- return this.sessionID.equals(bytestream.getSessionID())
- && IQ.Type.SET.equals(bytestream.getType());
- }
- return false;
- }
- }
-
- /**
- * Derive from InBandBytestreamRequest to access protected constructor.
- */
- private static class ByteStreamRequest extends InBandBytestreamRequest {
-
- private ByteStreamRequest(InBandBytestreamManager manager, Open byteStreamRequest) {
- super(manager, byteStreamRequest);
- }
-
- }
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.FromContainsFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+import org.jivesoftware.smackx.packet.StreamInitiation;
+
+/**
+ * The In-Band Bytestream file transfer method, or IBB for short, transfers the
+ * file over the same XML Stream used by XMPP. It is the fall-back mechanism in
+ * case the SOCKS5 bytestream method of transferring files is not available.
+ *
+ * @author Alexander Wenckus
+ * @author Henning Staib
+ * @see <a href="http://xmpp.org/extensions/xep-0047.html">XEP-0047: In-Band
+ * Bytestreams (IBB)</a>
+ */
+public class IBBTransferNegotiator extends StreamNegotiator {
+
+ private Connection connection;
+
+ private InBandBytestreamManager manager;
+
+ /**
+ * The default constructor for the In-Band Bytestream Negotiator.
+ *
+ * @param connection The connection which this negotiator works on.
+ */
+ protected IBBTransferNegotiator(Connection connection) {
+ this.connection = connection;
+ this.manager = InBandBytestreamManager.getByteStreamManager(connection);
+ }
+
+ public OutputStream createOutgoingStream(String streamID, String initiator,
+ String target) throws XMPPException {
+ InBandBytestreamSession session = this.manager.establishSession(target, streamID);
+ session.setCloseBothStreamsEnabled(true);
+ return session.getOutputStream();
+ }
+
+ public InputStream createIncomingStream(StreamInitiation initiation)
+ throws XMPPException {
+ /*
+ * In-Band Bytestream initiation listener must ignore next in-band
+ * bytestream request with given session ID
+ */
+ this.manager.ignoreBytestreamRequestOnce(initiation.getSessionID());
+
+ Packet streamInitiation = initiateIncomingStream(this.connection, initiation);
+ return negotiateIncomingStream(streamInitiation);
+ }
+
+ public PacketFilter getInitiationPacketFilter(String from, String streamID) {
+ /*
+ * this method is always called prior to #negotiateIncomingStream() so
+ * the In-Band Bytestream initiation listener must ignore the next
+ * In-Band Bytestream request with the given session ID
+ */
+ this.manager.ignoreBytestreamRequestOnce(streamID);
+
+ return new AndFilter(new FromContainsFilter(from), new IBBOpenSidFilter(streamID));
+ }
+
+ public String[] getNamespaces() {
+ return new String[] { InBandBytestreamManager.NAMESPACE };
+ }
+
+ InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException {
+ // build In-Band Bytestream request
+ InBandBytestreamRequest request = new ByteStreamRequest(this.manager,
+ (Open) streamInitiation);
+
+ // always accept the request
+ InBandBytestreamSession session = request.accept();
+ session.setCloseBothStreamsEnabled(true);
+ return session.getInputStream();
+ }
+
+ public void cleanup() {
+ }
+
+ /**
+ * This PacketFilter accepts an incoming In-Band Bytestream open request
+ * with a specified session ID.
+ */
+ private static class IBBOpenSidFilter extends PacketTypeFilter {
+
+ private String sessionID;
+
+ public IBBOpenSidFilter(String sessionID) {
+ super(Open.class);
+ if (sessionID == null) {
+ throw new IllegalArgumentException("StreamID cannot be null");
+ }
+ this.sessionID = sessionID;
+ }
+
+ public boolean accept(Packet packet) {
+ if (super.accept(packet)) {
+ Open bytestream = (Open) packet;
+
+ // packet must by of type SET and contains the given session ID
+ return this.sessionID.equals(bytestream.getSessionID())
+ && IQ.Type.SET.equals(bytestream.getType());
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Derive from InBandBytestreamRequest to access protected constructor.
+ */
+ private static class ByteStreamRequest extends InBandBytestreamRequest {
+
+ private ByteStreamRequest(InBandBytestreamManager manager, Open byteStreamRequest) {
+ super(manager, byteStreamRequest);
+ }
+
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java
index 91a5a0d83..fc15b63fd 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/IncomingFileTransfer.java
@@ -1,215 +1,215 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-import org.jivesoftware.smack.XMPPException;
-
-import java.io.*;
-import java.util.concurrent.*;
-
-/**
- * An incoming file transfer is created when the
- * {@link FileTransferManager#createIncomingFileTransfer(FileTransferRequest)}
- * method is invoked. It is a file being sent to the local user from another
- * user on the jabber network. There are two stages of the file transfer to be
- * concerned with and they can be handled in different ways depending upon the
- * method that is invoked on this class.
- * <p/>
- * The first way that a file is recieved is by calling the
- * {@link #recieveFile()} method. This method, negotiates the appropriate stream
- * method and then returns the <b><i>InputStream</b></i> to read the file
- * data from.
- * <p/>
- * The second way that a file can be recieved through this class is by invoking
- * the {@link #recieveFile(File)} method. This method returns immediatly and
- * takes as its parameter a file on the local file system where the file
- * recieved from the transfer will be put.
- *
- * @author Alexander Wenckus
- */
-public class IncomingFileTransfer extends FileTransfer {
-
- private FileTransferRequest recieveRequest;
-
- private InputStream inputStream;
-
- protected IncomingFileTransfer(FileTransferRequest request,
- FileTransferNegotiator transferNegotiator) {
- super(request.getRequestor(), request.getStreamID(), transferNegotiator);
- this.recieveRequest = request;
- }
-
- /**
- * Negotiates the stream method to transfer the file over and then returns
- * the negotiated stream.
- *
- * @return The negotiated InputStream from which to read the data.
- * @throws XMPPException If there is an error in the negotiation process an exception
- * is thrown.
- */
- public InputStream recieveFile() throws XMPPException {
- if (inputStream != null) {
- throw new IllegalStateException("Transfer already negotiated!");
- }
-
- try {
- inputStream = negotiateStream();
- }
- catch (XMPPException e) {
- setException(e);
- throw e;
- }
-
- return inputStream;
- }
-
- /**
- * This method negotitates the stream and then transfer's the file over the
- * negotiated stream. The transfered file will be saved at the provided
- * location.
- * <p/>
- * This method will return immedialtly, file transfer progress can be
- * monitored through several methods:
- * <p/>
- * <UL>
- * <LI>{@link FileTransfer#getStatus()}
- * <LI>{@link FileTransfer#getProgress()}
- * <LI>{@link FileTransfer#isDone()}
- * </UL>
- *
- * @param file The location to save the file.
- * @throws XMPPException when the file transfer fails
- * @throws IllegalArgumentException This exception is thrown when the the provided file is
- * either null, or cannot be written to.
- */
- public void recieveFile(final File file) throws XMPPException {
- if (file != null) {
- if (!file.exists()) {
- try {
- file.createNewFile();
- }
- catch (IOException e) {
- throw new XMPPException(
- "Could not create file to write too", e);
- }
- }
- if (!file.canWrite()) {
- throw new IllegalArgumentException("Cannot write to provided file");
- }
- }
- else {
- throw new IllegalArgumentException("File cannot be null");
- }
-
- Thread transferThread = new Thread(new Runnable() {
- public void run() {
- try {
- inputStream = negotiateStream();
- }
- catch (XMPPException e) {
- handleXMPPException(e);
- return;
- }
-
- OutputStream outputStream = null;
- try {
- outputStream = new FileOutputStream(file);
- setStatus(Status.in_progress);
- writeToStream(inputStream, outputStream);
- }
- catch (XMPPException e) {
- setStatus(Status.error);
- setError(Error.stream);
- setException(e);
- }
- catch (FileNotFoundException e) {
- setStatus(Status.error);
- setError(Error.bad_file);
- setException(e);
- }
-
- if (getStatus().equals(Status.in_progress)) {
- setStatus(Status.complete);
- }
- if (inputStream != null) {
- try {
- inputStream.close();
- }
- catch (Throwable io) {
- /* Ignore */
- }
- }
- if (outputStream != null) {
- try {
- outputStream.close();
- }
- catch (Throwable io) {
- /* Ignore */
- }
- }
- }
- }, "File Transfer " + streamID);
- transferThread.start();
- }
-
- private void handleXMPPException(XMPPException e) {
- setStatus(FileTransfer.Status.error);
- setException(e);
- }
-
- private InputStream negotiateStream() throws XMPPException {
- setStatus(Status.negotiating_transfer);
- final StreamNegotiator streamNegotiator = negotiator
- .selectStreamNegotiator(recieveRequest);
- setStatus(Status.negotiating_stream);
- FutureTask<InputStream> streamNegotiatorTask = new FutureTask<InputStream>(
- new Callable<InputStream>() {
-
- public InputStream call() throws Exception {
- return streamNegotiator
- .createIncomingStream(recieveRequest.getStreamInitiation());
- }
- });
- streamNegotiatorTask.run();
- InputStream inputStream;
- try {
- inputStream = streamNegotiatorTask.get(15, TimeUnit.SECONDS);
- }
- catch (InterruptedException e) {
- throw new XMPPException("Interruption while executing", e);
- }
- catch (ExecutionException e) {
- throw new XMPPException("Error in execution", e);
- }
- catch (TimeoutException e) {
- throw new XMPPException("Request timed out", e);
- }
- finally {
- streamNegotiatorTask.cancel(true);
- }
- setStatus(Status.negotiated);
- return inputStream;
- }
-
- public void cancel() {
- setStatus(Status.cancelled);
- }
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+import org.jivesoftware.smack.XMPPException;
+
+import java.io.*;
+import java.util.concurrent.*;
+
+/**
+ * An incoming file transfer is created when the
+ * {@link FileTransferManager#createIncomingFileTransfer(FileTransferRequest)}
+ * method is invoked. It is a file being sent to the local user from another
+ * user on the jabber network. There are two stages of the file transfer to be
+ * concerned with and they can be handled in different ways depending upon the
+ * method that is invoked on this class.
+ * <p/>
+ * The first way that a file is recieved is by calling the
+ * {@link #recieveFile()} method. This method, negotiates the appropriate stream
+ * method and then returns the <b><i>InputStream</b></i> to read the file
+ * data from.
+ * <p/>
+ * The second way that a file can be recieved through this class is by invoking
+ * the {@link #recieveFile(File)} method. This method returns immediatly and
+ * takes as its parameter a file on the local file system where the file
+ * recieved from the transfer will be put.
+ *
+ * @author Alexander Wenckus
+ */
+public class IncomingFileTransfer extends FileTransfer {
+
+ private FileTransferRequest recieveRequest;
+
+ private InputStream inputStream;
+
+ protected IncomingFileTransfer(FileTransferRequest request,
+ FileTransferNegotiator transferNegotiator) {
+ super(request.getRequestor(), request.getStreamID(), transferNegotiator);
+ this.recieveRequest = request;
+ }
+
+ /**
+ * Negotiates the stream method to transfer the file over and then returns
+ * the negotiated stream.
+ *
+ * @return The negotiated InputStream from which to read the data.
+ * @throws XMPPException If there is an error in the negotiation process an exception
+ * is thrown.
+ */
+ public InputStream recieveFile() throws XMPPException {
+ if (inputStream != null) {
+ throw new IllegalStateException("Transfer already negotiated!");
+ }
+
+ try {
+ inputStream = negotiateStream();
+ }
+ catch (XMPPException e) {
+ setException(e);
+ throw e;
+ }
+
+ return inputStream;
+ }
+
+ /**
+ * This method negotitates the stream and then transfer's the file over the
+ * negotiated stream. The transfered file will be saved at the provided
+ * location.
+ * <p/>
+ * This method will return immedialtly, file transfer progress can be
+ * monitored through several methods:
+ * <p/>
+ * <UL>
+ * <LI>{@link FileTransfer#getStatus()}
+ * <LI>{@link FileTransfer#getProgress()}
+ * <LI>{@link FileTransfer#isDone()}
+ * </UL>
+ *
+ * @param file The location to save the file.
+ * @throws XMPPException when the file transfer fails
+ * @throws IllegalArgumentException This exception is thrown when the the provided file is
+ * either null, or cannot be written to.
+ */
+ public void recieveFile(final File file) throws XMPPException {
+ if (file != null) {
+ if (!file.exists()) {
+ try {
+ file.createNewFile();
+ }
+ catch (IOException e) {
+ throw new XMPPException(
+ "Could not create file to write too", e);
+ }
+ }
+ if (!file.canWrite()) {
+ throw new IllegalArgumentException("Cannot write to provided file");
+ }
+ }
+ else {
+ throw new IllegalArgumentException("File cannot be null");
+ }
+
+ Thread transferThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ inputStream = negotiateStream();
+ }
+ catch (XMPPException e) {
+ handleXMPPException(e);
+ return;
+ }
+
+ OutputStream outputStream = null;
+ try {
+ outputStream = new FileOutputStream(file);
+ setStatus(Status.in_progress);
+ writeToStream(inputStream, outputStream);
+ }
+ catch (XMPPException e) {
+ setStatus(Status.error);
+ setError(Error.stream);
+ setException(e);
+ }
+ catch (FileNotFoundException e) {
+ setStatus(Status.error);
+ setError(Error.bad_file);
+ setException(e);
+ }
+
+ if (getStatus().equals(Status.in_progress)) {
+ setStatus(Status.complete);
+ }
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ }
+ catch (Throwable io) {
+ /* Ignore */
+ }
+ }
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ }
+ catch (Throwable io) {
+ /* Ignore */
+ }
+ }
+ }
+ }, "File Transfer " + streamID);
+ transferThread.start();
+ }
+
+ private void handleXMPPException(XMPPException e) {
+ setStatus(FileTransfer.Status.error);
+ setException(e);
+ }
+
+ private InputStream negotiateStream() throws XMPPException {
+ setStatus(Status.negotiating_transfer);
+ final StreamNegotiator streamNegotiator = negotiator
+ .selectStreamNegotiator(recieveRequest);
+ setStatus(Status.negotiating_stream);
+ FutureTask<InputStream> streamNegotiatorTask = new FutureTask<InputStream>(
+ new Callable<InputStream>() {
+
+ public InputStream call() throws Exception {
+ return streamNegotiator
+ .createIncomingStream(recieveRequest.getStreamInitiation());
+ }
+ });
+ streamNegotiatorTask.run();
+ InputStream inputStream;
+ try {
+ inputStream = streamNegotiatorTask.get(15, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e) {
+ throw new XMPPException("Interruption while executing", e);
+ }
+ catch (ExecutionException e) {
+ throw new XMPPException("Error in execution", e);
+ }
+ catch (TimeoutException e) {
+ throw new XMPPException("Request timed out", e);
+ }
+ finally {
+ streamNegotiatorTask.cancel(true);
+ }
+ setStatus(Status.negotiated);
+ return inputStream;
+ }
+
+ public void cancel() {
+ setStatus(Status.cancelled);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java
index 13b8a57fc..ded096eef 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java
@@ -1,449 +1,449 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.XMPPError;
-
-import java.io.*;
-
-/**
- * Handles the sending of a file to another user. File transfer's in jabber have
- * several steps and there are several methods in this class that handle these
- * steps differently.
- *
- * @author Alexander Wenckus
- *
- */
-public class OutgoingFileTransfer extends FileTransfer {
-
- private static int RESPONSE_TIMEOUT = 60 * 1000;
- private NegotiationProgress callback;
-
- /**
- * Returns the time in milliseconds after which the file transfer
- * negotiation process will timeout if the other user has not responded.
- *
- * @return Returns the time in milliseconds after which the file transfer
- * negotiation process will timeout if the remote user has not
- * responded.
- */
- public static int getResponseTimeout() {
- return RESPONSE_TIMEOUT;
- }
-
- /**
- * Sets the time in milliseconds after which the file transfer negotiation
- * process will timeout if the other user has not responded.
- *
- * @param responseTimeout
- * The timeout time in milliseconds.
- */
- public static void setResponseTimeout(int responseTimeout) {
- RESPONSE_TIMEOUT = responseTimeout;
- }
-
- private OutputStream outputStream;
-
- private String initiator;
-
- private Thread transferThread;
-
- protected OutgoingFileTransfer(String initiator, String target,
- String streamID, FileTransferNegotiator transferNegotiator) {
- super(target, streamID, transferNegotiator);
- this.initiator = initiator;
- }
-
- protected void setOutputStream(OutputStream stream) {
- if (outputStream == null) {
- this.outputStream = stream;
- }
- }
-
- /**
- * Returns the output stream connected to the peer to transfer the file. It
- * is only available after it has been successfully negotiated by the
- * {@link StreamNegotiator}.
- *
- * @return Returns the output stream connected to the peer to transfer the
- * file.
- */
- protected OutputStream getOutputStream() {
- if (getStatus().equals(FileTransfer.Status.negotiated)) {
- return outputStream;
- } else {
- return null;
- }
- }
-
- /**
- * This method handles the negotiation of the file transfer and the stream,
- * it only returns the created stream after the negotiation has been completed.
- *
- * @param fileName
- * The name of the file that will be transmitted. It is
- * preferable for this name to have an extension as it will be
- * used to determine the type of file it is.
- * @param fileSize
- * The size in bytes of the file that will be transmitted.
- * @param description
- * A description of the file that will be transmitted.
- * @return The OutputStream that is connected to the peer to transmit the
- * file.
- * @throws XMPPException
- * Thrown if an error occurs during the file transfer
- * negotiation process.
- */
- public synchronized OutputStream sendFile(String fileName, long fileSize,
- String description) throws XMPPException {
- if (isDone() || outputStream != null) {
- throw new IllegalStateException(
- "The negotation process has already"
- + " been attempted on this file transfer");
- }
- try {
- setFileInfo(fileName, fileSize);
- this.outputStream = negotiateStream(fileName, fileSize, description);
- } catch (XMPPException e) {
- handleXMPPException(e);
- throw e;
- }
- return outputStream;
- }
-
- /**
- * This methods handles the transfer and stream negotiation process. It
- * returns immediately and its progress will be updated through the
- * {@link NegotiationProgress} callback.
- *
- * @param fileName
- * The name of the file that will be transmitted. It is
- * preferable for this name to have an extension as it will be
- * used to determine the type of file it is.
- * @param fileSize
- * The size in bytes of the file that will be transmitted.
- * @param description
- * A description of the file that will be transmitted.
- * @param progress
- * A callback to monitor the progress of the file transfer
- * negotiation process and to retrieve the OutputStream when it
- * is complete.
- */
- public synchronized void sendFile(final String fileName,
- final long fileSize, final String description,
- final NegotiationProgress progress)
- {
- if(progress == null) {
- throw new IllegalArgumentException("Callback progress cannot be null.");
- }
- checkTransferThread();
- if (isDone() || outputStream != null) {
- throw new IllegalStateException(
- "The negotation process has already"
- + " been attempted for this file transfer");
- }
- setFileInfo(fileName, fileSize);
- this.callback = progress;
- transferThread = new Thread(new Runnable() {
- public void run() {
- try {
- OutgoingFileTransfer.this.outputStream = negotiateStream(
- fileName, fileSize, description);
- progress.outputStreamEstablished(OutgoingFileTransfer.this.outputStream);
- }
- catch (XMPPException e) {
- handleXMPPException(e);
- }
- }
- }, "File Transfer Negotiation " + streamID);
- transferThread.start();
- }
-
- private void checkTransferThread() {
- if (transferThread != null && transferThread.isAlive() || isDone()) {
- throw new IllegalStateException(
- "File transfer in progress or has already completed.");
- }
- }
-
- /**
- * This method handles the stream negotiation process and transmits the file
- * to the remote user. It returns immediately and the progress of the file
- * transfer can be monitored through several methods:
- *
- * <UL>
- * <LI>{@link FileTransfer#getStatus()}
- * <LI>{@link FileTransfer#getProgress()}
- * <LI>{@link FileTransfer#isDone()}
- * </UL>
- *
- * @param file the file to transfer to the remote entity.
- * @param description a description for the file to transfer.
- * @throws XMPPException
- * If there is an error during the negotiation process or the
- * sending of the file.
- */
- public synchronized void sendFile(final File file, final String description)
- throws XMPPException {
- checkTransferThread();
- if (file == null || !file.exists() || !file.canRead()) {
- throw new IllegalArgumentException("Could not read file");
- } else {
- setFileInfo(file.getAbsolutePath(), file.getName(), file.length());
- }
-
- transferThread = new Thread(new Runnable() {
- public void run() {
- try {
- outputStream = negotiateStream(file.getName(), file
- .length(), description);
- } catch (XMPPException e) {
- handleXMPPException(e);
- return;
- }
- if (outputStream == null) {
- return;
- }
-
- if (!updateStatus(Status.negotiated, Status.in_progress)) {
- return;
- }
-
- InputStream inputStream = null;
- try {
- inputStream = new FileInputStream(file);
- writeToStream(inputStream, outputStream);
- } catch (FileNotFoundException e) {
- setStatus(FileTransfer.Status.error);
- setError(Error.bad_file);
- setException(e);
- } catch (XMPPException e) {
- setStatus(FileTransfer.Status.error);
- setException(e);
- } finally {
- try {
- if (inputStream != null) {
- inputStream.close();
- }
-
- outputStream.flush();
- outputStream.close();
- } catch (IOException e) {
- /* Do Nothing */
- }
- }
- updateStatus(Status.in_progress, FileTransfer.Status.complete);
- }
-
- }, "File Transfer " + streamID);
- transferThread.start();
- }
-
- /**
- * This method handles the stream negotiation process and transmits the file
- * to the remote user. It returns immediately and the progress of the file
- * transfer can be monitored through several methods:
- *
- * <UL>
- * <LI>{@link FileTransfer#getStatus()}
- * <LI>{@link FileTransfer#getProgress()}
- * <LI>{@link FileTransfer#isDone()}
- * </UL>
- *
- * @param in the stream to transfer to the remote entity.
- * @param fileName the name of the file that is transferred
- * @param fileSize the size of the file that is transferred
- * @param description a description for the file to transfer.
- */
- public synchronized void sendStream(final InputStream in, final String fileName, final long fileSize, final String description){
- checkTransferThread();
-
- setFileInfo(fileName, fileSize);
- transferThread = new Thread(new Runnable() {
- public void run() {
- //Create packet filter
- try {
- outputStream = negotiateStream(fileName, fileSize, description);
- } catch (XMPPException e) {
- handleXMPPException(e);
- return;
- }
- if (outputStream == null) {
- return;
- }
-
- if (!updateStatus(Status.negotiated, Status.in_progress)) {
- return;
- }
- try {
- writeToStream(in, outputStream);
- } catch (XMPPException e) {
- setStatus(FileTransfer.Status.error);
- setException(e);
- } finally {
- try {
- if (in != null) {
- in.close();
- }
-
- outputStream.flush();
- outputStream.close();
- } catch (IOException e) {
- /* Do Nothing */
- }
- }
- updateStatus(Status.in_progress, FileTransfer.Status.complete);
- }
-
- }, "File Transfer " + streamID);
- transferThread.start();
- }
-
- private void handleXMPPException(XMPPException e) {
- XMPPError error = e.getXMPPError();
- if (error != null) {
- int code = error.getCode();
- if (code == 403) {
- setStatus(Status.refused);
- return;
- }
- else if (code == 400) {
- setStatus(Status.error);
- setError(Error.not_acceptable);
- }
- else {
- setStatus(FileTransfer.Status.error);
- }
- }
-
- setException(e);
- }
-
- /**
- * Returns the amount of bytes that have been sent for the file transfer. Or
- * -1 if the file transfer has not started.
- * <p>
- * Note: This method is only useful when the {@link #sendFile(File, String)}
- * method is called, as it is the only method that actually transmits the
- * file.
- *
- * @return Returns the amount of bytes that have been sent for the file
- * transfer. Or -1 if the file transfer has not started.
- */
- public long getBytesSent() {
- return amountWritten;
- }
-
- private OutputStream negotiateStream(String fileName, long fileSize,
- String description) throws XMPPException {
- // Negotiate the file transfer profile
-
- if (!updateStatus(Status.initial, Status.negotiating_transfer)) {
- throw new XMPPException("Illegal state change");
- }
- StreamNegotiator streamNegotiator = negotiator.negotiateOutgoingTransfer(
- getPeer(), streamID, fileName, fileSize, description,
- RESPONSE_TIMEOUT);
-
- if (streamNegotiator == null) {
- setStatus(Status.error);
- setError(Error.no_response);
- return null;
- }
-
- // Negotiate the stream
- if (!updateStatus(Status.negotiating_transfer, Status.negotiating_stream)) {
- throw new XMPPException("Illegal state change");
- }
- outputStream = streamNegotiator.createOutgoingStream(streamID,
- initiator, getPeer());
-
- if (!updateStatus(Status.negotiating_stream, Status.negotiated)) {
- throw new XMPPException("Illegal state change");
- }
- return outputStream;
- }
-
- public void cancel() {
- setStatus(Status.cancelled);
- }
-
- @Override
- protected boolean updateStatus(Status oldStatus, Status newStatus) {
- boolean isUpdated = super.updateStatus(oldStatus, newStatus);
- if(callback != null && isUpdated) {
- callback.statusUpdated(oldStatus, newStatus);
- }
- return isUpdated;
- }
-
- @Override
- protected void setStatus(Status status) {
- Status oldStatus = getStatus();
- super.setStatus(status);
- if(callback != null) {
- callback.statusUpdated(oldStatus, status);
- }
- }
-
- @Override
- protected void setException(Exception exception) {
- super.setException(exception);
- if(callback != null) {
- callback.errorEstablishingStream(exception);
- }
- }
-
- /**
- * A callback class to retrieve the status of an outgoing transfer
- * negotiation process.
- *
- * @author Alexander Wenckus
- *
- */
- public interface NegotiationProgress {
-
- /**
- * Called when the status changes
- *
- * @param oldStatus the previous status of the file transfer.
- * @param newStatus the new status of the file transfer.
- */
- void statusUpdated(Status oldStatus, Status newStatus);
-
- /**
- * Once the negotiation process is completed the output stream can be
- * retrieved.
- *
- * @param stream the established stream which can be used to transfer the file to the remote
- * entity
- */
- void outputStreamEstablished(OutputStream stream);
-
- /**
- * Called when an exception occurs during the negotiation progress.
- *
- * @param e the exception that occurred.
- */
- void errorEstablishingStream(Exception e);
- }
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.XMPPError;
+
+import java.io.*;
+
+/**
+ * Handles the sending of a file to another user. File transfer's in jabber have
+ * several steps and there are several methods in this class that handle these
+ * steps differently.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+public class OutgoingFileTransfer extends FileTransfer {
+
+ private static int RESPONSE_TIMEOUT = 60 * 1000;
+ private NegotiationProgress callback;
+
+ /**
+ * Returns the time in milliseconds after which the file transfer
+ * negotiation process will timeout if the other user has not responded.
+ *
+ * @return Returns the time in milliseconds after which the file transfer
+ * negotiation process will timeout if the remote user has not
+ * responded.
+ */
+ public static int getResponseTimeout() {
+ return RESPONSE_TIMEOUT;
+ }
+
+ /**
+ * Sets the time in milliseconds after which the file transfer negotiation
+ * process will timeout if the other user has not responded.
+ *
+ * @param responseTimeout
+ * The timeout time in milliseconds.
+ */
+ public static void setResponseTimeout(int responseTimeout) {
+ RESPONSE_TIMEOUT = responseTimeout;
+ }
+
+ private OutputStream outputStream;
+
+ private String initiator;
+
+ private Thread transferThread;
+
+ protected OutgoingFileTransfer(String initiator, String target,
+ String streamID, FileTransferNegotiator transferNegotiator) {
+ super(target, streamID, transferNegotiator);
+ this.initiator = initiator;
+ }
+
+ protected void setOutputStream(OutputStream stream) {
+ if (outputStream == null) {
+ this.outputStream = stream;
+ }
+ }
+
+ /**
+ * Returns the output stream connected to the peer to transfer the file. It
+ * is only available after it has been successfully negotiated by the
+ * {@link StreamNegotiator}.
+ *
+ * @return Returns the output stream connected to the peer to transfer the
+ * file.
+ */
+ protected OutputStream getOutputStream() {
+ if (getStatus().equals(FileTransfer.Status.negotiated)) {
+ return outputStream;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * This method handles the negotiation of the file transfer and the stream,
+ * it only returns the created stream after the negotiation has been completed.
+ *
+ * @param fileName
+ * The name of the file that will be transmitted. It is
+ * preferable for this name to have an extension as it will be
+ * used to determine the type of file it is.
+ * @param fileSize
+ * The size in bytes of the file that will be transmitted.
+ * @param description
+ * A description of the file that will be transmitted.
+ * @return The OutputStream that is connected to the peer to transmit the
+ * file.
+ * @throws XMPPException
+ * Thrown if an error occurs during the file transfer
+ * negotiation process.
+ */
+ public synchronized OutputStream sendFile(String fileName, long fileSize,
+ String description) throws XMPPException {
+ if (isDone() || outputStream != null) {
+ throw new IllegalStateException(
+ "The negotation process has already"
+ + " been attempted on this file transfer");
+ }
+ try {
+ setFileInfo(fileName, fileSize);
+ this.outputStream = negotiateStream(fileName, fileSize, description);
+ } catch (XMPPException e) {
+ handleXMPPException(e);
+ throw e;
+ }
+ return outputStream;
+ }
+
+ /**
+ * This methods handles the transfer and stream negotiation process. It
+ * returns immediately and its progress will be updated through the
+ * {@link NegotiationProgress} callback.
+ *
+ * @param fileName
+ * The name of the file that will be transmitted. It is
+ * preferable for this name to have an extension as it will be
+ * used to determine the type of file it is.
+ * @param fileSize
+ * The size in bytes of the file that will be transmitted.
+ * @param description
+ * A description of the file that will be transmitted.
+ * @param progress
+ * A callback to monitor the progress of the file transfer
+ * negotiation process and to retrieve the OutputStream when it
+ * is complete.
+ */
+ public synchronized void sendFile(final String fileName,
+ final long fileSize, final String description,
+ final NegotiationProgress progress)
+ {
+ if(progress == null) {
+ throw new IllegalArgumentException("Callback progress cannot be null.");
+ }
+ checkTransferThread();
+ if (isDone() || outputStream != null) {
+ throw new IllegalStateException(
+ "The negotation process has already"
+ + " been attempted for this file transfer");
+ }
+ setFileInfo(fileName, fileSize);
+ this.callback = progress;
+ transferThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ OutgoingFileTransfer.this.outputStream = negotiateStream(
+ fileName, fileSize, description);
+ progress.outputStreamEstablished(OutgoingFileTransfer.this.outputStream);
+ }
+ catch (XMPPException e) {
+ handleXMPPException(e);
+ }
+ }
+ }, "File Transfer Negotiation " + streamID);
+ transferThread.start();
+ }
+
+ private void checkTransferThread() {
+ if (transferThread != null && transferThread.isAlive() || isDone()) {
+ throw new IllegalStateException(
+ "File transfer in progress or has already completed.");
+ }
+ }
+
+ /**
+ * This method handles the stream negotiation process and transmits the file
+ * to the remote user. It returns immediately and the progress of the file
+ * transfer can be monitored through several methods:
+ *
+ * <UL>
+ * <LI>{@link FileTransfer#getStatus()}
+ * <LI>{@link FileTransfer#getProgress()}
+ * <LI>{@link FileTransfer#isDone()}
+ * </UL>
+ *
+ * @param file the file to transfer to the remote entity.
+ * @param description a description for the file to transfer.
+ * @throws XMPPException
+ * If there is an error during the negotiation process or the
+ * sending of the file.
+ */
+ public synchronized void sendFile(final File file, final String description)
+ throws XMPPException {
+ checkTransferThread();
+ if (file == null || !file.exists() || !file.canRead()) {
+ throw new IllegalArgumentException("Could not read file");
+ } else {
+ setFileInfo(file.getAbsolutePath(), file.getName(), file.length());
+ }
+
+ transferThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ outputStream = negotiateStream(file.getName(), file
+ .length(), description);
+ } catch (XMPPException e) {
+ handleXMPPException(e);
+ return;
+ }
+ if (outputStream == null) {
+ return;
+ }
+
+ if (!updateStatus(Status.negotiated, Status.in_progress)) {
+ return;
+ }
+
+ InputStream inputStream = null;
+ try {
+ inputStream = new FileInputStream(file);
+ writeToStream(inputStream, outputStream);
+ } catch (FileNotFoundException e) {
+ setStatus(FileTransfer.Status.error);
+ setError(Error.bad_file);
+ setException(e);
+ } catch (XMPPException e) {
+ setStatus(FileTransfer.Status.error);
+ setException(e);
+ } finally {
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+
+ outputStream.flush();
+ outputStream.close();
+ } catch (IOException e) {
+ /* Do Nothing */
+ }
+ }
+ updateStatus(Status.in_progress, FileTransfer.Status.complete);
+ }
+
+ }, "File Transfer " + streamID);
+ transferThread.start();
+ }
+
+ /**
+ * This method handles the stream negotiation process and transmits the file
+ * to the remote user. It returns immediately and the progress of the file
+ * transfer can be monitored through several methods:
+ *
+ * <UL>
+ * <LI>{@link FileTransfer#getStatus()}
+ * <LI>{@link FileTransfer#getProgress()}
+ * <LI>{@link FileTransfer#isDone()}
+ * </UL>
+ *
+ * @param in the stream to transfer to the remote entity.
+ * @param fileName the name of the file that is transferred
+ * @param fileSize the size of the file that is transferred
+ * @param description a description for the file to transfer.
+ */
+ public synchronized void sendStream(final InputStream in, final String fileName, final long fileSize, final String description){
+ checkTransferThread();
+
+ setFileInfo(fileName, fileSize);
+ transferThread = new Thread(new Runnable() {
+ public void run() {
+ //Create packet filter
+ try {
+ outputStream = negotiateStream(fileName, fileSize, description);
+ } catch (XMPPException e) {
+ handleXMPPException(e);
+ return;
+ }
+ if (outputStream == null) {
+ return;
+ }
+
+ if (!updateStatus(Status.negotiated, Status.in_progress)) {
+ return;
+ }
+ try {
+ writeToStream(in, outputStream);
+ } catch (XMPPException e) {
+ setStatus(FileTransfer.Status.error);
+ setException(e);
+ } finally {
+ try {
+ if (in != null) {
+ in.close();
+ }
+
+ outputStream.flush();
+ outputStream.close();
+ } catch (IOException e) {
+ /* Do Nothing */
+ }
+ }
+ updateStatus(Status.in_progress, FileTransfer.Status.complete);
+ }
+
+ }, "File Transfer " + streamID);
+ transferThread.start();
+ }
+
+ private void handleXMPPException(XMPPException e) {
+ XMPPError error = e.getXMPPError();
+ if (error != null) {
+ int code = error.getCode();
+ if (code == 403) {
+ setStatus(Status.refused);
+ return;
+ }
+ else if (code == 400) {
+ setStatus(Status.error);
+ setError(Error.not_acceptable);
+ }
+ else {
+ setStatus(FileTransfer.Status.error);
+ }
+ }
+
+ setException(e);
+ }
+
+ /**
+ * Returns the amount of bytes that have been sent for the file transfer. Or
+ * -1 if the file transfer has not started.
+ * <p>
+ * Note: This method is only useful when the {@link #sendFile(File, String)}
+ * method is called, as it is the only method that actually transmits the
+ * file.
+ *
+ * @return Returns the amount of bytes that have been sent for the file
+ * transfer. Or -1 if the file transfer has not started.
+ */
+ public long getBytesSent() {
+ return amountWritten;
+ }
+
+ private OutputStream negotiateStream(String fileName, long fileSize,
+ String description) throws XMPPException {
+ // Negotiate the file transfer profile
+
+ if (!updateStatus(Status.initial, Status.negotiating_transfer)) {
+ throw new XMPPException("Illegal state change");
+ }
+ StreamNegotiator streamNegotiator = negotiator.negotiateOutgoingTransfer(
+ getPeer(), streamID, fileName, fileSize, description,
+ RESPONSE_TIMEOUT);
+
+ if (streamNegotiator == null) {
+ setStatus(Status.error);
+ setError(Error.no_response);
+ return null;
+ }
+
+ // Negotiate the stream
+ if (!updateStatus(Status.negotiating_transfer, Status.negotiating_stream)) {
+ throw new XMPPException("Illegal state change");
+ }
+ outputStream = streamNegotiator.createOutgoingStream(streamID,
+ initiator, getPeer());
+
+ if (!updateStatus(Status.negotiating_stream, Status.negotiated)) {
+ throw new XMPPException("Illegal state change");
+ }
+ return outputStream;
+ }
+
+ public void cancel() {
+ setStatus(Status.cancelled);
+ }
+
+ @Override
+ protected boolean updateStatus(Status oldStatus, Status newStatus) {
+ boolean isUpdated = super.updateStatus(oldStatus, newStatus);
+ if(callback != null && isUpdated) {
+ callback.statusUpdated(oldStatus, newStatus);
+ }
+ return isUpdated;
+ }
+
+ @Override
+ protected void setStatus(Status status) {
+ Status oldStatus = getStatus();
+ super.setStatus(status);
+ if(callback != null) {
+ callback.statusUpdated(oldStatus, status);
+ }
+ }
+
+ @Override
+ protected void setException(Exception exception) {
+ super.setException(exception);
+ if(callback != null) {
+ callback.errorEstablishingStream(exception);
+ }
+ }
+
+ /**
+ * A callback class to retrieve the status of an outgoing transfer
+ * negotiation process.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+ public interface NegotiationProgress {
+
+ /**
+ * Called when the status changes
+ *
+ * @param oldStatus the previous status of the file transfer.
+ * @param newStatus the new status of the file transfer.
+ */
+ void statusUpdated(Status oldStatus, Status newStatus);
+
+ /**
+ * Once the negotiation process is completed the output stream can be
+ * retrieved.
+ *
+ * @param stream the established stream which can be used to transfer the file to the remote
+ * entity
+ */
+ void outputStreamEstablished(OutputStream stream);
+
+ /**
+ * Called when an exception occurs during the negotiation progress.
+ *
+ * @param e the exception that occurred.
+ */
+ void errorEstablishingStream(Exception e);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java
index 3c07fdca8..8db0929a7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java
@@ -1,164 +1,164 @@
-/**
- * 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.filetransfer;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PushbackInputStream;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.FromMatchesFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
-import org.jivesoftware.smackx.packet.StreamInitiation;
-
-/**
- * Negotiates a SOCKS5 Bytestream to be used for file transfers. The implementation is based on the
- * {@link Socks5BytestreamManager} and the {@link Socks5BytestreamRequest}.
- *
- * @author Henning Staib
- * @see <a href="http://xmpp.org/extensions/xep-0065.html">XEP-0065: SOCKS5 Bytestreams</a>
- */
-public class Socks5TransferNegotiator extends StreamNegotiator {
-
- private Connection connection;
-
- private Socks5BytestreamManager manager;
-
- Socks5TransferNegotiator(Connection connection) {
- this.connection = connection;
- this.manager = Socks5BytestreamManager.getBytestreamManager(this.connection);
- }
-
- @Override
- public OutputStream createOutgoingStream(String streamID, String initiator, String target)
- throws XMPPException {
- try {
- return this.manager.establishSession(target, streamID).getOutputStream();
- }
- catch (IOException e) {
- throw new XMPPException("error establishing SOCKS5 Bytestream", e);
- }
- catch (InterruptedException e) {
- throw new XMPPException("error establishing SOCKS5 Bytestream", e);
- }
- }
-
- @Override
- public InputStream createIncomingStream(StreamInitiation initiation) throws XMPPException,
- InterruptedException {
- /*
- * SOCKS5 initiation listener must ignore next SOCKS5 Bytestream request with given session
- * ID
- */
- this.manager.ignoreBytestreamRequestOnce(initiation.getSessionID());
-
- Packet streamInitiation = initiateIncomingStream(this.connection, initiation);
- return negotiateIncomingStream(streamInitiation);
- }
-
- @Override
- public PacketFilter getInitiationPacketFilter(final String from, String streamID) {
- /*
- * this method is always called prior to #negotiateIncomingStream() so the SOCKS5
- * InitiationListener must ignore the next SOCKS5 Bytestream request with the given session
- * ID
- */
- this.manager.ignoreBytestreamRequestOnce(streamID);
-
- return new AndFilter(new FromMatchesFilter(from), new BytestreamSIDFilter(streamID));
- }
-
- @Override
- public String[] getNamespaces() {
- return new String[] { Socks5BytestreamManager.NAMESPACE };
- }
-
- @Override
- InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException,
- InterruptedException {
- // build SOCKS5 Bytestream request
- Socks5BytestreamRequest request = new ByteStreamRequest(this.manager,
- (Bytestream) streamInitiation);
-
- // always accept the request
- Socks5BytestreamSession session = request.accept();
-
- // test input stream
- try {
- PushbackInputStream stream = new PushbackInputStream(session.getInputStream());
- int firstByte = stream.read();
- stream.unread(firstByte);
- return stream;
- }
- catch (IOException e) {
- throw new XMPPException("Error establishing input stream", e);
- }
- }
-
- @Override
- public void cleanup() {
- /* do nothing */
- }
-
- /**
- * This PacketFilter accepts an incoming SOCKS5 Bytestream request with a specified session ID.
- */
- private static class BytestreamSIDFilter extends PacketTypeFilter {
-
- private String sessionID;
-
- public BytestreamSIDFilter(String sessionID) {
- super(Bytestream.class);
- if (sessionID == null) {
- throw new IllegalArgumentException("StreamID cannot be null");
- }
- this.sessionID = sessionID;
- }
-
- @Override
- public boolean accept(Packet packet) {
- if (super.accept(packet)) {
- Bytestream bytestream = (Bytestream) packet;
-
- // packet must by of type SET and contains the given session ID
- return this.sessionID.equals(bytestream.getSessionID())
- && IQ.Type.SET.equals(bytestream.getType());
- }
- return false;
- }
-
- }
-
- /**
- * Derive from Socks5BytestreamRequest to access protected constructor.
- */
- private static class ByteStreamRequest extends Socks5BytestreamRequest {
-
- private ByteStreamRequest(Socks5BytestreamManager manager, Bytestream byteStreamRequest) {
- super(manager, byteStreamRequest);
- }
-
- }
-
-}
+/**
+ * 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.filetransfer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PushbackInputStream;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.FromMatchesFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
+import org.jivesoftware.smackx.packet.StreamInitiation;
+
+/**
+ * Negotiates a SOCKS5 Bytestream to be used for file transfers. The implementation is based on the
+ * {@link Socks5BytestreamManager} and the {@link Socks5BytestreamRequest}.
+ *
+ * @author Henning Staib
+ * @see <a href="http://xmpp.org/extensions/xep-0065.html">XEP-0065: SOCKS5 Bytestreams</a>
+ */
+public class Socks5TransferNegotiator extends StreamNegotiator {
+
+ private Connection connection;
+
+ private Socks5BytestreamManager manager;
+
+ Socks5TransferNegotiator(Connection connection) {
+ this.connection = connection;
+ this.manager = Socks5BytestreamManager.getBytestreamManager(this.connection);
+ }
+
+ @Override
+ public OutputStream createOutgoingStream(String streamID, String initiator, String target)
+ throws XMPPException {
+ try {
+ return this.manager.establishSession(target, streamID).getOutputStream();
+ }
+ catch (IOException e) {
+ throw new XMPPException("error establishing SOCKS5 Bytestream", e);
+ }
+ catch (InterruptedException e) {
+ throw new XMPPException("error establishing SOCKS5 Bytestream", e);
+ }
+ }
+
+ @Override
+ public InputStream createIncomingStream(StreamInitiation initiation) throws XMPPException,
+ InterruptedException {
+ /*
+ * SOCKS5 initiation listener must ignore next SOCKS5 Bytestream request with given session
+ * ID
+ */
+ this.manager.ignoreBytestreamRequestOnce(initiation.getSessionID());
+
+ Packet streamInitiation = initiateIncomingStream(this.connection, initiation);
+ return negotiateIncomingStream(streamInitiation);
+ }
+
+ @Override
+ public PacketFilter getInitiationPacketFilter(final String from, String streamID) {
+ /*
+ * this method is always called prior to #negotiateIncomingStream() so the SOCKS5
+ * InitiationListener must ignore the next SOCKS5 Bytestream request with the given session
+ * ID
+ */
+ this.manager.ignoreBytestreamRequestOnce(streamID);
+
+ return new AndFilter(new FromMatchesFilter(from), new BytestreamSIDFilter(streamID));
+ }
+
+ @Override
+ public String[] getNamespaces() {
+ return new String[] { Socks5BytestreamManager.NAMESPACE };
+ }
+
+ @Override
+ InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException,
+ InterruptedException {
+ // build SOCKS5 Bytestream request
+ Socks5BytestreamRequest request = new ByteStreamRequest(this.manager,
+ (Bytestream) streamInitiation);
+
+ // always accept the request
+ Socks5BytestreamSession session = request.accept();
+
+ // test input stream
+ try {
+ PushbackInputStream stream = new PushbackInputStream(session.getInputStream());
+ int firstByte = stream.read();
+ stream.unread(firstByte);
+ return stream;
+ }
+ catch (IOException e) {
+ throw new XMPPException("Error establishing input stream", e);
+ }
+ }
+
+ @Override
+ public void cleanup() {
+ /* do nothing */
+ }
+
+ /**
+ * This PacketFilter accepts an incoming SOCKS5 Bytestream request with a specified session ID.
+ */
+ private static class BytestreamSIDFilter extends PacketTypeFilter {
+
+ private String sessionID;
+
+ public BytestreamSIDFilter(String sessionID) {
+ super(Bytestream.class);
+ if (sessionID == null) {
+ throw new IllegalArgumentException("StreamID cannot be null");
+ }
+ this.sessionID = sessionID;
+ }
+
+ @Override
+ public boolean accept(Packet packet) {
+ if (super.accept(packet)) {
+ Bytestream bytestream = (Bytestream) packet;
+
+ // packet must by of type SET and contains the given session ID
+ return this.sessionID.equals(bytestream.getSessionID())
+ && IQ.Type.SET.equals(bytestream.getType());
+ }
+ return false;
+ }
+
+ }
+
+ /**
+ * Derive from Socks5BytestreamRequest to access protected constructor.
+ */
+ private static class ByteStreamRequest extends Socks5BytestreamRequest {
+
+ private ByteStreamRequest(Socks5BytestreamManager manager, Bytestream byteStreamRequest) {
+ super(manager, byteStreamRequest);
+ }
+
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java
index 5eefe4370..fb60ee142 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java
@@ -1,167 +1,167 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.filetransfer;
-
-import org.jivesoftware.smack.PacketCollector;
-import org.jivesoftware.smack.SmackConfiguration;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.FormField;
-import org.jivesoftware.smackx.packet.DataForm;
-import org.jivesoftware.smackx.packet.StreamInitiation;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * After the file transfer negotiation process is completed according to
- * JEP-0096, the negotiation process is passed off to a particular stream
- * negotiator. The stream negotiator will then negotiate the chosen stream and
- * return the stream to transfer the file.
- *
- * @author Alexander Wenckus
- */
-public abstract class StreamNegotiator {
-
- /**
- * Creates the initiation acceptance packet to forward to the stream
- * initiator.
- *
- * @param streamInitiationOffer The offer from the stream initiator to connect for a stream.
- * @param namespaces The namespace that relates to the accepted means of transfer.
- * @return The response to be forwarded to the initiator.
- */
- public StreamInitiation createInitiationAccept(
- StreamInitiation streamInitiationOffer, String[] namespaces)
- {
- StreamInitiation response = new StreamInitiation();
- response.setTo(streamInitiationOffer.getFrom());
- response.setFrom(streamInitiationOffer.getTo());
- response.setType(IQ.Type.RESULT);
- response.setPacketID(streamInitiationOffer.getPacketID());
-
- DataForm form = new DataForm(Form.TYPE_SUBMIT);
- FormField field = new FormField(
- FileTransferNegotiator.STREAM_DATA_FIELD_NAME);
- for (String namespace : namespaces) {
- field.addValue(namespace);
- }
- form.addField(field);
-
- response.setFeatureNegotiationForm(form);
- return response;
- }
-
-
- public IQ createError(String from, String to, String packetID, XMPPError xmppError) {
- IQ iq = FileTransferNegotiator.createIQ(packetID, to, from, IQ.Type.ERROR);
- iq.setError(xmppError);
- return iq;
- }
-
- Packet initiateIncomingStream(Connection connection, StreamInitiation initiation) throws XMPPException {
- StreamInitiation response = createInitiationAccept(initiation,
- getNamespaces());
-
- // establish collector to await response
- PacketCollector collector = connection
- .createPacketCollector(getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID()));
- connection.sendPacket(response);
-
- Packet streamMethodInitiation = collector
- .nextResult(SmackConfiguration.getPacketReplyTimeout());
- collector.cancel();
- if (streamMethodInitiation == null) {
- throw new XMPPException("No response from file transfer initiator");
- }
-
- return streamMethodInitiation;
- }
-
- /**
- * Returns the packet filter that will return the initiation packet for the appropriate stream
- * initiation.
- *
- * @param from The initiator of the file transfer.
- * @param streamID The stream ID related to the transfer.
- * @return The <b><i>PacketFilter</b></i> that will return the packet relatable to the stream
- * initiation.
- */
- public abstract PacketFilter getInitiationPacketFilter(String from, String streamID);
-
-
- abstract InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException,
- InterruptedException;
-
- /**
- * This method handles the file stream download negotiation process. The
- * appropriate stream negotiator's initiate incoming stream is called after
- * an appropriate file transfer method is selected. The manager will respond
- * to the initiator with the selected means of transfer, then it will handle
- * any negotiation specific to the particular transfer method. This method
- * returns the InputStream, ready to transfer the file.
- *
- * @param initiation The initiation that triggered this download.
- * @return After the negotiation process is complete, the InputStream to
- * write a file to is returned.
- * @throws XMPPException If an error occurs during this process an XMPPException is
- * thrown.
- * @throws InterruptedException If thread is interrupted.
- */
- public abstract InputStream createIncomingStream(StreamInitiation initiation)
- throws XMPPException, InterruptedException;
-
- /**
- * This method handles the file upload stream negotiation process. The
- * particular stream negotiator is determined during the file transfer
- * negotiation process. This method returns the OutputStream to transmit the
- * file to the remote user.
- *
- * @param streamID The streamID that uniquely identifies the file transfer.
- * @param initiator The fully-qualified JID of the initiator of the file transfer.
- * @param target The fully-qualified JID of the target or receiver of the file
- * transfer.
- * @return The negotiated stream ready for data.
- * @throws XMPPException If an error occurs during the negotiation process an
- * exception will be thrown.
- */
- public abstract OutputStream createOutgoingStream(String streamID,
- String initiator, String target) throws XMPPException;
-
- /**
- * Returns the XMPP namespace reserved for this particular type of file
- * transfer.
- *
- * @return Returns the XMPP namespace reserved for this particular type of
- * file transfer.
- */
- public abstract String[] getNamespaces();
-
- /**
- * Cleanup any and all resources associated with this negotiator.
- */
- public abstract void cleanup();
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.filetransfer;
+
+import org.jivesoftware.smack.PacketCollector;
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.FormField;
+import org.jivesoftware.smackx.packet.DataForm;
+import org.jivesoftware.smackx.packet.StreamInitiation;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * After the file transfer negotiation process is completed according to
+ * JEP-0096, the negotiation process is passed off to a particular stream
+ * negotiator. The stream negotiator will then negotiate the chosen stream and
+ * return the stream to transfer the file.
+ *
+ * @author Alexander Wenckus
+ */
+public abstract class StreamNegotiator {
+
+ /**
+ * Creates the initiation acceptance packet to forward to the stream
+ * initiator.
+ *
+ * @param streamInitiationOffer The offer from the stream initiator to connect for a stream.
+ * @param namespaces The namespace that relates to the accepted means of transfer.
+ * @return The response to be forwarded to the initiator.
+ */
+ public StreamInitiation createInitiationAccept(
+ StreamInitiation streamInitiationOffer, String[] namespaces)
+ {
+ StreamInitiation response = new StreamInitiation();
+ response.setTo(streamInitiationOffer.getFrom());
+ response.setFrom(streamInitiationOffer.getTo());
+ response.setType(IQ.Type.RESULT);
+ response.setPacketID(streamInitiationOffer.getPacketID());
+
+ DataForm form = new DataForm(Form.TYPE_SUBMIT);
+ FormField field = new FormField(
+ FileTransferNegotiator.STREAM_DATA_FIELD_NAME);
+ for (String namespace : namespaces) {
+ field.addValue(namespace);
+ }
+ form.addField(field);
+
+ response.setFeatureNegotiationForm(form);
+ return response;
+ }
+
+
+ public IQ createError(String from, String to, String packetID, XMPPError xmppError) {
+ IQ iq = FileTransferNegotiator.createIQ(packetID, to, from, IQ.Type.ERROR);
+ iq.setError(xmppError);
+ return iq;
+ }
+
+ Packet initiateIncomingStream(Connection connection, StreamInitiation initiation) throws XMPPException {
+ StreamInitiation response = createInitiationAccept(initiation,
+ getNamespaces());
+
+ // establish collector to await response
+ PacketCollector collector = connection
+ .createPacketCollector(getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID()));
+ connection.sendPacket(response);
+
+ Packet streamMethodInitiation = collector
+ .nextResult(SmackConfiguration.getPacketReplyTimeout());
+ collector.cancel();
+ if (streamMethodInitiation == null) {
+ throw new XMPPException("No response from file transfer initiator");
+ }
+
+ return streamMethodInitiation;
+ }
+
+ /**
+ * Returns the packet filter that will return the initiation packet for the appropriate stream
+ * initiation.
+ *
+ * @param from The initiator of the file transfer.
+ * @param streamID The stream ID related to the transfer.
+ * @return The <b><i>PacketFilter</b></i> that will return the packet relatable to the stream
+ * initiation.
+ */
+ public abstract PacketFilter getInitiationPacketFilter(String from, String streamID);
+
+
+ abstract InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException,
+ InterruptedException;
+
+ /**
+ * This method handles the file stream download negotiation process. The
+ * appropriate stream negotiator's initiate incoming stream is called after
+ * an appropriate file transfer method is selected. The manager will respond
+ * to the initiator with the selected means of transfer, then it will handle
+ * any negotiation specific to the particular transfer method. This method
+ * returns the InputStream, ready to transfer the file.
+ *
+ * @param initiation The initiation that triggered this download.
+ * @return After the negotiation process is complete, the InputStream to
+ * write a file to is returned.
+ * @throws XMPPException If an error occurs during this process an XMPPException is
+ * thrown.
+ * @throws InterruptedException If thread is interrupted.
+ */
+ public abstract InputStream createIncomingStream(StreamInitiation initiation)
+ throws XMPPException, InterruptedException;
+
+ /**
+ * This method handles the file upload stream negotiation process. The
+ * particular stream negotiator is determined during the file transfer
+ * negotiation process. This method returns the OutputStream to transmit the
+ * file to the remote user.
+ *
+ * @param streamID The streamID that uniquely identifies the file transfer.
+ * @param initiator The fully-qualified JID of the initiator of the file transfer.
+ * @param target The fully-qualified JID of the target or receiver of the file
+ * transfer.
+ * @return The negotiated stream ready for data.
+ * @throws XMPPException If an error occurs during the negotiation process an
+ * exception will be thrown.
+ */
+ public abstract OutputStream createOutgoingStream(String streamID,
+ String initiator, String target) throws XMPPException;
+
+ /**
+ * Returns the XMPP namespace reserved for this particular type of file
+ * transfer.
+ *
+ * @return Returns the XMPP namespace reserved for this particular type of
+ * file transfer.
+ */
+ public abstract String[] getNamespaces();
+
+ /**
+ * Cleanup any and all resources associated with this negotiator.
+ */
+ public abstract void cleanup();
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AdHocCommandData.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AdHocCommandData.java
index bceffcdba..37ba14d66 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AdHocCommandData.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AdHocCommandData.java
@@ -1,279 +1,279 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2005-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.
- * 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.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.commands.AdHocCommand;
-import org.jivesoftware.smackx.commands.AdHocCommand.Action;
-import org.jivesoftware.smackx.commands.AdHocCommand.SpecificErrorCondition;
-import org.jivesoftware.smackx.commands.AdHocCommandNote;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Represents the state and the request of the execution of an adhoc command.
- *
- * @author Gabriel Guardincerri
- */
-public class AdHocCommandData extends IQ {
-
- /* JID of the command host */
- private String id;
-
- /* Command name */
- private String name;
-
- /* Command identifier */
- private String node;
-
- /* Unique ID of the execution */
- private String sessionID;
-
- private List<AdHocCommandNote> notes = new ArrayList<AdHocCommandNote>();
-
- private DataForm form;
-
- /* Action request to be executed */
- private AdHocCommand.Action action;
-
- /* Current execution status */
- private AdHocCommand.Status status;
-
- private ArrayList<AdHocCommand.Action> actions = new ArrayList<AdHocCommand.Action>();
-
- private AdHocCommand.Action executeAction;
-
- private String lang;
-
- public AdHocCommandData() {
- }
-
- @Override
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<command xmlns=\"http://jabber.org/protocol/commands\"");
- buf.append(" node=\"").append(node).append("\"");
- if (sessionID != null) {
- if (!sessionID.equals("")) {
- buf.append(" sessionid=\"").append(sessionID).append("\"");
- }
- }
- if (status != null) {
- buf.append(" status=\"").append(status).append("\"");
- }
- if (action != null) {
- buf.append(" action=\"").append(action).append("\"");
- }
-
- if (lang != null) {
- if (!lang.equals("")) {
- buf.append(" lang=\"").append(lang).append("\"");
- }
- }
- buf.append(">");
-
- if (getType() == Type.RESULT) {
- buf.append("<actions");
-
- if (executeAction != null) {
- buf.append(" execute=\"").append(executeAction).append("\"");
- }
- if (actions.size() == 0) {
- buf.append("/>");
- } else {
- buf.append(">");
-
- for (AdHocCommand.Action action : actions) {
- buf.append("<").append(action).append("/>");
- }
- buf.append("</actions>");
- }
- }
-
- if (form != null) {
- buf.append(form.toXML());
- }
-
- for (AdHocCommandNote note : notes) {
- buf.append("<note type=\"").append(note.getType().toString()).append("\">");
- buf.append(note.getValue());
- buf.append("</note>");
- }
-
- // TODO ERRORS
-// if (getError() != null) {
-// buf.append(getError().toXML());
-// }
-
- buf.append("</command>");
- return buf.toString();
- }
-
- /**
- * Returns the JID of the command host.
- *
- * @return the JID of the command host.
- */
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- /**
- * Returns the human name of the command
- *
- * @return the name of the command.
- */
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Returns the identifier of the command
- *
- * @return the node.
- */
- public String getNode() {
- return node;
- }
-
- public void setNode(String node) {
- this.node = node;
- }
-
- /**
- * Returns the list of notes that the command has.
- *
- * @return the notes.
- */
- public List<AdHocCommandNote> getNotes() {
- return notes;
- }
-
- public void addNote(AdHocCommandNote note) {
- this.notes.add(note);
- }
-
- public void remveNote(AdHocCommandNote note) {
- this.notes.remove(note);
- }
-
- /**
- * Returns the form of the command.
- *
- * @return the data form associated with the command.
- */
- public DataForm getForm() {
- return form;
- }
-
- public void setForm(DataForm form) {
- this.form = form;
- }
-
- /**
- * Returns the action to execute. The action is set only on a request.
- *
- * @return the action to execute.
- */
- public AdHocCommand.Action getAction() {
- return action;
- }
-
- public void setAction(AdHocCommand.Action action) {
- this.action = action;
- }
-
- /**
- * Returns the status of the execution.
- *
- * @return the status.
- */
- public AdHocCommand.Status getStatus() {
- return status;
- }
-
- public void setStatus(AdHocCommand.Status status) {
- this.status = status;
- }
-
- public List<Action> getActions() {
- return actions;
- }
-
- public void addAction(Action action) {
- actions.add(action);
- }
-
- public void setExecuteAction(Action executeAction) {
- this.executeAction = executeAction;
- }
-
- public Action getExecuteAction() {
- return executeAction;
- }
-
- public void setSessionID(String sessionID) {
- this.sessionID = sessionID;
- }
-
- public String getSessionID() {
- return sessionID;
- }
-
- public static class SpecificError implements PacketExtension {
-
- public static final String namespace = "http://jabber.org/protocol/commands";
-
- public SpecificErrorCondition condition;
-
- public SpecificError(SpecificErrorCondition condition) {
- this.condition = condition;
- }
-
- public String getElementName() {
- return condition.toString();
- }
- public String getNamespace() {
- return namespace;
- }
-
- public SpecificErrorCondition getCondition() {
- return condition;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(getElementName());
- buf.append(" xmlns=\"").append(getNamespace()).append("\"/>");
- return buf.toString();
- }
- }
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2005-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.
+ * 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.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.commands.AdHocCommand;
+import org.jivesoftware.smackx.commands.AdHocCommand.Action;
+import org.jivesoftware.smackx.commands.AdHocCommand.SpecificErrorCondition;
+import org.jivesoftware.smackx.commands.AdHocCommandNote;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents the state and the request of the execution of an adhoc command.
+ *
+ * @author Gabriel Guardincerri
+ */
+public class AdHocCommandData extends IQ {
+
+ /* JID of the command host */
+ private String id;
+
+ /* Command name */
+ private String name;
+
+ /* Command identifier */
+ private String node;
+
+ /* Unique ID of the execution */
+ private String sessionID;
+
+ private List<AdHocCommandNote> notes = new ArrayList<AdHocCommandNote>();
+
+ private DataForm form;
+
+ /* Action request to be executed */
+ private AdHocCommand.Action action;
+
+ /* Current execution status */
+ private AdHocCommand.Status status;
+
+ private ArrayList<AdHocCommand.Action> actions = new ArrayList<AdHocCommand.Action>();
+
+ private AdHocCommand.Action executeAction;
+
+ private String lang;
+
+ public AdHocCommandData() {
+ }
+
+ @Override
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<command xmlns=\"http://jabber.org/protocol/commands\"");
+ buf.append(" node=\"").append(node).append("\"");
+ if (sessionID != null) {
+ if (!sessionID.equals("")) {
+ buf.append(" sessionid=\"").append(sessionID).append("\"");
+ }
+ }
+ if (status != null) {
+ buf.append(" status=\"").append(status).append("\"");
+ }
+ if (action != null) {
+ buf.append(" action=\"").append(action).append("\"");
+ }
+
+ if (lang != null) {
+ if (!lang.equals("")) {
+ buf.append(" lang=\"").append(lang).append("\"");
+ }
+ }
+ buf.append(">");
+
+ if (getType() == Type.RESULT) {
+ buf.append("<actions");
+
+ if (executeAction != null) {
+ buf.append(" execute=\"").append(executeAction).append("\"");
+ }
+ if (actions.size() == 0) {
+ buf.append("/>");
+ } else {
+ buf.append(">");
+
+ for (AdHocCommand.Action action : actions) {
+ buf.append("<").append(action).append("/>");
+ }
+ buf.append("</actions>");
+ }
+ }
+
+ if (form != null) {
+ buf.append(form.toXML());
+ }
+
+ for (AdHocCommandNote note : notes) {
+ buf.append("<note type=\"").append(note.getType().toString()).append("\">");
+ buf.append(note.getValue());
+ buf.append("</note>");
+ }
+
+ // TODO ERRORS
+// if (getError() != null) {
+// buf.append(getError().toXML());
+// }
+
+ buf.append("</command>");
+ return buf.toString();
+ }
+
+ /**
+ * Returns the JID of the command host.
+ *
+ * @return the JID of the command host.
+ */
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns the human name of the command
+ *
+ * @return the name of the command.
+ */
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the identifier of the command
+ *
+ * @return the node.
+ */
+ public String getNode() {
+ return node;
+ }
+
+ public void setNode(String node) {
+ this.node = node;
+ }
+
+ /**
+ * Returns the list of notes that the command has.
+ *
+ * @return the notes.
+ */
+ public List<AdHocCommandNote> getNotes() {
+ return notes;
+ }
+
+ public void addNote(AdHocCommandNote note) {
+ this.notes.add(note);
+ }
+
+ public void remveNote(AdHocCommandNote note) {
+ this.notes.remove(note);
+ }
+
+ /**
+ * Returns the form of the command.
+ *
+ * @return the data form associated with the command.
+ */
+ public DataForm getForm() {
+ return form;
+ }
+
+ public void setForm(DataForm form) {
+ this.form = form;
+ }
+
+ /**
+ * Returns the action to execute. The action is set only on a request.
+ *
+ * @return the action to execute.
+ */
+ public AdHocCommand.Action getAction() {
+ return action;
+ }
+
+ public void setAction(AdHocCommand.Action action) {
+ this.action = action;
+ }
+
+ /**
+ * Returns the status of the execution.
+ *
+ * @return the status.
+ */
+ public AdHocCommand.Status getStatus() {
+ return status;
+ }
+
+ public void setStatus(AdHocCommand.Status status) {
+ this.status = status;
+ }
+
+ public List<Action> getActions() {
+ return actions;
+ }
+
+ public void addAction(Action action) {
+ actions.add(action);
+ }
+
+ public void setExecuteAction(Action executeAction) {
+ this.executeAction = executeAction;
+ }
+
+ public Action getExecuteAction() {
+ return executeAction;
+ }
+
+ public void setSessionID(String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ public static class SpecificError implements PacketExtension {
+
+ public static final String namespace = "http://jabber.org/protocol/commands";
+
+ public SpecificErrorCondition condition;
+
+ public SpecificError(SpecificErrorCondition condition) {
+ this.condition = condition;
+ }
+
+ public String getElementName() {
+ return condition.toString();
+ }
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public SpecificErrorCondition getCondition() {
+ return condition;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(getElementName());
+ buf.append(" xmlns=\"").append(getNamespace()).append("\"/>");
+ return buf.toString();
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AttentionExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AttentionExtension.java
index d86fa419e..ad4085146 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AttentionExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/AttentionExtension.java
@@ -1,100 +1,100 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2010 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
- *
- * 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.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * A PacketExtension that implements XEP-0224: Attention
- *
- * This extension is expected to be added to message stanzas of type 'headline.'
- * Please refer to the XEP for more implementation guidelines.
- *
- * @author Guus der Kinderen, guus.der.kinderen@gmail.com
- * @see <a
- * href="http://xmpp.org/extensions/xep-0224.html">XEP-0224:&nbsp;Attention</a>
- */
-public class AttentionExtension implements PacketExtension {
-
- /**
- * The XML element name of an 'attention' extension.
- */
- public static final String ELEMENT_NAME = "attention";
-
- /**
- * The namespace that qualifies the XML element of an 'attention' extension.
- */
- public static final String NAMESPACE = "urn:xmpp:attention:0";
-
- /*
- * (non-Javadoc)
- *
- * @see org.jivesoftware.smack.packet.PacketExtension#getElementName()
- */
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.jivesoftware.smack.packet.PacketExtension#getNamespace()
- */
- public String getNamespace() {
- return NAMESPACE;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.jivesoftware.smack.packet.PacketExtension#toXML()
- */
- public String toXML() {
- final StringBuilder sb = new StringBuilder();
- sb.append("<").append(getElementName()).append(" xmlns=\"").append(
- getNamespace()).append("\"/>");
- return sb.toString();
- }
-
- /**
- * A {@link PacketExtensionProvider} for the {@link AttentionExtension}. As
- * Attention elements have no state/information other than the element name
- * and namespace, this implementation simply returns new instances of
- * {@link AttentionExtension}.
- *
- * @author Guus der Kinderen, guus.der.kinderen@gmail.com
-s */
- public static class Provider implements PacketExtensionProvider {
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.jivesoftware.smack.provider.PacketExtensionProvider#parseExtension
- * (org.xmlpull.v1.XmlPullParser)
- */
- public PacketExtension parseExtension(XmlPullParser arg0)
- throws Exception {
- return new AttentionExtension();
- }
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2010 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
+ *
+ * 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.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * A PacketExtension that implements XEP-0224: Attention
+ *
+ * This extension is expected to be added to message stanzas of type 'headline.'
+ * Please refer to the XEP for more implementation guidelines.
+ *
+ * @author Guus der Kinderen, guus.der.kinderen@gmail.com
+ * @see <a
+ * href="http://xmpp.org/extensions/xep-0224.html">XEP-0224:&nbsp;Attention</a>
+ */
+public class AttentionExtension implements PacketExtension {
+
+ /**
+ * The XML element name of an 'attention' extension.
+ */
+ public static final String ELEMENT_NAME = "attention";
+
+ /**
+ * The namespace that qualifies the XML element of an 'attention' extension.
+ */
+ public static final String NAMESPACE = "urn:xmpp:attention:0";
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.packet.PacketExtension#getElementName()
+ */
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.packet.PacketExtension#getNamespace()
+ */
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.packet.PacketExtension#toXML()
+ */
+ public String toXML() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("<").append(getElementName()).append(" xmlns=\"").append(
+ getNamespace()).append("\"/>");
+ return sb.toString();
+ }
+
+ /**
+ * A {@link PacketExtensionProvider} for the {@link AttentionExtension}. As
+ * Attention elements have no state/information other than the element name
+ * and namespace, this implementation simply returns new instances of
+ * {@link AttentionExtension}.
+ *
+ * @author Guus der Kinderen, guus.der.kinderen@gmail.com
+s */
+ public static class Provider implements PacketExtensionProvider {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.jivesoftware.smack.provider.PacketExtensionProvider#parseExtension
+ * (org.xmlpull.v1.XmlPullParser)
+ */
+ public PacketExtension parseExtension(XmlPullParser arg0)
+ throws Exception {
+ return new AttentionExtension();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/ChatStateExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/ChatStateExtension.java
index ecc6acce4..a9fbbb46a 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/ChatStateExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/ChatStateExtension.java
@@ -1,73 +1,73 @@
-/**
- * $RCSfile$
- * $Revision: 2407 $
- * $Date: 2004-11-02 15:37:00 -0800 (Tue, 02 Nov 2004) $
- *
- * 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
- *
- * 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.packet;
-
-import org.jivesoftware.smackx.ChatState;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Represents a chat state which is an extension to message packets which is used to indicate
- * the current status of a chat participant.
- *
- * @author Alexander Wenckus
- * @see org.jivesoftware.smackx.ChatState
- */
-public class ChatStateExtension implements PacketExtension {
-
- private ChatState state;
-
- /**
- * Default constructor. The argument provided is the state that the extension will represent.
- *
- * @param state the state that the extension represents.
- */
- public ChatStateExtension(ChatState state) {
- this.state = state;
- }
-
- public String getElementName() {
- return state.name();
- }
-
- public String getNamespace() {
- return "http://jabber.org/protocol/chatstates";
- }
-
- public String toXML() {
- return "<" + getElementName() + " xmlns=\"" + getNamespace() + "\" />";
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- ChatState state;
- try {
- state = ChatState.valueOf(parser.getName());
- }
- catch (Exception ex) {
- state = ChatState.active;
- }
- return new ChatStateExtension(state);
- }
- }
-}
+/**
+ * $RCSfile$
+ * $Revision: 2407 $
+ * $Date: 2004-11-02 15:37:00 -0800 (Tue, 02 Nov 2004) $
+ *
+ * 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
+ *
+ * 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.packet;
+
+import org.jivesoftware.smackx.ChatState;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Represents a chat state which is an extension to message packets which is used to indicate
+ * the current status of a chat participant.
+ *
+ * @author Alexander Wenckus
+ * @see org.jivesoftware.smackx.ChatState
+ */
+public class ChatStateExtension implements PacketExtension {
+
+ private ChatState state;
+
+ /**
+ * Default constructor. The argument provided is the state that the extension will represent.
+ *
+ * @param state the state that the extension represents.
+ */
+ public ChatStateExtension(ChatState state) {
+ this.state = state;
+ }
+
+ public String getElementName() {
+ return state.name();
+ }
+
+ public String getNamespace() {
+ return "http://jabber.org/protocol/chatstates";
+ }
+
+ public String toXML() {
+ return "<" + getElementName() + " xmlns=\"" + getNamespace() + "\" />";
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ ChatState state;
+ try {
+ state = ChatState.valueOf(parser.getName());
+ }
+ catch (Exception ex) {
+ state = ChatState.active;
+ }
+ return new ChatStateExtension(state);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/DelayInfo.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/DelayInfo.java
index f5ba78fa1..5e8f11a4a 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/DelayInfo.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/DelayInfo.java
@@ -1,105 +1,105 @@
-/**
- * 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.packet;
-
-import java.util.Date;
-
-import org.jivesoftware.smack.util.StringUtils;
-
-/**
- * A decorator for the {@link DelayInformation} class to transparently support
- * both the new <b>Delay Delivery</b> specification <a href="http://xmpp.org/extensions/xep-0203.html">XEP-0203</a> and
- * the old one <a href="http://xmpp.org/extensions/xep-0091.html">XEP-0091</a>.
- *
- * Existing code can be backward compatible.
- *
- * @author Robin Collier
- */
-public class DelayInfo extends DelayInformation
-{
-
- DelayInformation wrappedInfo;
-
- /**
- * Creates a new instance with given delay information.
- * @param delay the delay information
- */
- public DelayInfo(DelayInformation delay)
- {
- super(delay.getStamp());
- wrappedInfo = delay;
- }
-
- @Override
- public String getFrom()
- {
- return wrappedInfo.getFrom();
- }
-
- @Override
- public String getReason()
- {
- return wrappedInfo.getReason();
- }
-
- @Override
- public Date getStamp()
- {
- return wrappedInfo.getStamp();
- }
-
- @Override
- public void setFrom(String from)
- {
- wrappedInfo.setFrom(from);
- }
-
- @Override
- public void setReason(String reason)
- {
- wrappedInfo.setReason(reason);
- }
-
- @Override
- public String getElementName()
- {
- return "delay";
- }
-
- @Override
- public String getNamespace()
- {
- return "urn:xmpp:delay";
- }
-
- @Override
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
- "\"");
- buf.append(" stamp=\"");
- buf.append(StringUtils.formatXEP0082Date(getStamp()));
- buf.append("\"");
- if (getFrom() != null && getFrom().length() > 0) {
- buf.append(" from=\"").append(getFrom()).append("\"");
- }
- buf.append(">");
- if (getReason() != null && getReason().length() > 0) {
- buf.append(getReason());
- }
- buf.append("</").append(getElementName()).append(">");
- return buf.toString();
- }
-
-}
+/**
+ * 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.packet;
+
+import java.util.Date;
+
+import org.jivesoftware.smack.util.StringUtils;
+
+/**
+ * A decorator for the {@link DelayInformation} class to transparently support
+ * both the new <b>Delay Delivery</b> specification <a href="http://xmpp.org/extensions/xep-0203.html">XEP-0203</a> and
+ * the old one <a href="http://xmpp.org/extensions/xep-0091.html">XEP-0091</a>.
+ *
+ * Existing code can be backward compatible.
+ *
+ * @author Robin Collier
+ */
+public class DelayInfo extends DelayInformation
+{
+
+ DelayInformation wrappedInfo;
+
+ /**
+ * Creates a new instance with given delay information.
+ * @param delay the delay information
+ */
+ public DelayInfo(DelayInformation delay)
+ {
+ super(delay.getStamp());
+ wrappedInfo = delay;
+ }
+
+ @Override
+ public String getFrom()
+ {
+ return wrappedInfo.getFrom();
+ }
+
+ @Override
+ public String getReason()
+ {
+ return wrappedInfo.getReason();
+ }
+
+ @Override
+ public Date getStamp()
+ {
+ return wrappedInfo.getStamp();
+ }
+
+ @Override
+ public void setFrom(String from)
+ {
+ wrappedInfo.setFrom(from);
+ }
+
+ @Override
+ public void setReason(String reason)
+ {
+ wrappedInfo.setReason(reason);
+ }
+
+ @Override
+ public String getElementName()
+ {
+ return "delay";
+ }
+
+ @Override
+ public String getNamespace()
+ {
+ return "urn:xmpp:delay";
+ }
+
+ @Override
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
+ "\"");
+ buf.append(" stamp=\"");
+ buf.append(StringUtils.formatXEP0082Date(getStamp()));
+ buf.append("\"");
+ if (getFrom() != null && getFrom().length() > 0) {
+ buf.append(" from=\"").append(getFrom()).append("\"");
+ }
+ buf.append(">");
+ if (getReason() != null && getReason().length() > 0) {
+ buf.append(getReason());
+ }
+ buf.append("</").append(getElementName()).append(">");
+ return buf.toString();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Header.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Header.java
index 3fa838662..44533f87e 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Header.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Header.java
@@ -1,59 +1,59 @@
-/*
- * 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.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * Represents a <b>Header</b> entry as specified by the <a href="http://xmpp.org/extensions/xep-031.html">Stanza Headers and Internet Metadata (SHIM)</a>
-
- * @author Robin Collier
- */
-public class Header implements PacketExtension
-{
- private String name;
- private String value;
-
- public Header(String name, String value)
- {
- this.name = name;
- this.value = value;
- }
-
- public String getName()
- {
- return name;
- }
-
- public String getValue()
- {
- return value;
- }
-
- public String getElementName()
- {
- return "header";
- }
-
- public String getNamespace()
- {
- return HeadersExtension.NAMESPACE;
- }
-
- public String toXML()
- {
- return "<header name='" + name + "'>" + value + "</header>";
- }
-
-}
+/*
+ * 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.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * Represents a <b>Header</b> entry as specified by the <a href="http://xmpp.org/extensions/xep-031.html">Stanza Headers and Internet Metadata (SHIM)</a>
+
+ * @author Robin Collier
+ */
+public class Header implements PacketExtension
+{
+ private String name;
+ private String value;
+
+ public Header(String name, String value)
+ {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public String getElementName()
+ {
+ return "header";
+ }
+
+ public String getNamespace()
+ {
+ return HeadersExtension.NAMESPACE;
+ }
+
+ public String toXML()
+ {
+ return "<header name='" + name + "'>" + value + "</header>";
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/HeadersExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/HeadersExtension.java
index 78564dbbf..03fde1722 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/HeadersExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/HeadersExtension.java
@@ -1,69 +1,69 @@
-/**
- * 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.packet;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * Extension representing a list of headers as specified in <a href="http://xmpp.org/extensions/xep-0131">Stanza Headers and Internet Metadata (SHIM)</a>
- *
- * @see Header
- *
- * @author Robin Collier
- */
-public class HeadersExtension implements PacketExtension
-{
- public static final String NAMESPACE = "http://jabber.org/protocol/shim";
-
- private Collection<Header> headers = Collections.EMPTY_LIST;
-
- public HeadersExtension(Collection<Header> headerList)
- {
- if (headerList != null)
- headers = headerList;
- }
-
- public Collection<Header> getHeaders()
- {
- return headers;
- }
-
- public String getElementName()
- {
- return "headers";
- }
-
- public String getNamespace()
- {
- return NAMESPACE;
- }
-
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<" + getElementName() + " xmlns='" + getNamespace() + "'>");
-
- for (Header header : headers)
- {
- builder.append(header.toXML());
- }
- builder.append("</" + getElementName() + '>');
-
- return builder.toString();
- }
-
-}
+/**
+ * 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.packet;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * Extension representing a list of headers as specified in <a href="http://xmpp.org/extensions/xep-0131">Stanza Headers and Internet Metadata (SHIM)</a>
+ *
+ * @see Header
+ *
+ * @author Robin Collier
+ */
+public class HeadersExtension implements PacketExtension
+{
+ public static final String NAMESPACE = "http://jabber.org/protocol/shim";
+
+ private Collection<Header> headers = Collections.EMPTY_LIST;
+
+ public HeadersExtension(Collection<Header> headerList)
+ {
+ if (headerList != null)
+ headers = headerList;
+ }
+
+ public Collection<Header> getHeaders()
+ {
+ return headers;
+ }
+
+ public String getElementName()
+ {
+ return "headers";
+ }
+
+ public String getNamespace()
+ {
+ return NAMESPACE;
+ }
+
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<" + getElementName() + " xmlns='" + getNamespace() + "'>");
+
+ for (Header header : headers)
+ {
+ builder.append(header.toXML());
+ }
+ builder.append("</" + getElementName() + '>');
+
+ return builder.toString();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Nick.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Nick.java
index 9a64eaa42..61d791210 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Nick.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Nick.java
@@ -1,112 +1,112 @@
-/**
- * $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
- *
- * 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.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * A minimalistic implementation of a {@link PacketExtension} for nicknames.
- *
- * @author Guus der Kinderen, guus.der.kinderen@gmail.com
- * @see <a href="http://xmpp.org/extensions/xep-0172.html">XEP-0172: User Nickname</a>
- */
-public class Nick implements PacketExtension {
-
- public static final String NAMESPACE = "http://jabber.org/protocol/nick";
-
- public static final String ELEMENT_NAME = "nick";
-
- private String name = null;
-
- public Nick(String name) {
- this.name = name;
- }
-
- /**
- * The value of this nickname
- *
- * @return the nickname
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the value of this nickname
- *
- * @param name
- * the name to set
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.jivesoftware.smack.packet.PacketExtension#getElementName()
- */
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.jivesoftware.smack.packet.PacketExtension#getNamespace()
- */
- public String getNamespace() {
- return NAMESPACE;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.jivesoftware.smack.packet.PacketExtension#toXML()
- */
- public String toXML() {
- final StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(
- NAMESPACE).append("\">");
- buf.append(getName());
- buf.append("</").append(ELEMENT_NAME).append('>');
-
- return buf.toString();
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser)
- throws Exception {
-
- parser.next();
- final String name = parser.getText();
-
- // Advance to end of extension.
- while(parser.getEventType() != XmlPullParser.END_TAG) {
- parser.next();
- }
-
- return new Nick(name);
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * A minimalistic implementation of a {@link PacketExtension} for nicknames.
+ *
+ * @author Guus der Kinderen, guus.der.kinderen@gmail.com
+ * @see <a href="http://xmpp.org/extensions/xep-0172.html">XEP-0172: User Nickname</a>
+ */
+public class Nick implements PacketExtension {
+
+ public static final String NAMESPACE = "http://jabber.org/protocol/nick";
+
+ public static final String ELEMENT_NAME = "nick";
+
+ private String name = null;
+
+ public Nick(String name) {
+ this.name = name;
+ }
+
+ /**
+ * The value of this nickname
+ *
+ * @return the nickname
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of this nickname
+ *
+ * @param name
+ * the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.packet.PacketExtension#getElementName()
+ */
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.packet.PacketExtension#getNamespace()
+ */
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.packet.PacketExtension#toXML()
+ */
+ public String toXML() {
+ final StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(
+ NAMESPACE).append("\">");
+ buf.append(getName());
+ buf.append("</").append(ELEMENT_NAME).append('>');
+
+ return buf.toString();
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser)
+ throws Exception {
+
+ parser.next();
+ final String name = parser.getText();
+
+ // Advance to end of extension.
+ while(parser.getEventType() != XmlPullParser.END_TAG) {
+ parser.next();
+ }
+
+ return new Nick(name);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/SharedGroupsInfo.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/SharedGroupsInfo.java
index 59bd98e7c..f4f1c827f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/SharedGroupsInfo.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/SharedGroupsInfo.java
@@ -17,76 +17,76 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smackx.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * IQ packet used for discovering the user's shared groups and for getting the answer back
- * from the server.<p>
- *
- * Important note: This functionality is not part of the XMPP spec and it will only work
- * with Wildfire.
- *
- * @author Gaston Dombiak
- */
-public class SharedGroupsInfo extends IQ {
-
- private List<String> groups = new ArrayList<String>();
-
- /**
- * Returns a collection with the shared group names returned from the server.
- *
- * @return collection with the shared group names returned from the server.
- */
- public List<String> getGroups() {
- return groups;
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<sharedgroup xmlns=\"http://www.jivesoftware.org/protocol/sharedgroup\">");
- for (Iterator<String> it=groups.iterator(); it.hasNext();) {
- buf.append("<group>").append(it.next()).append("</group>");
- }
- buf.append("</sharedgroup>");
- return buf.toString();
- }
-
- /**
- * Internal Search service Provider.
- */
- public static class Provider implements IQProvider {
-
- /**
- * Provider Constructor.
- */
- public Provider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- SharedGroupsInfo groupsInfo = new SharedGroupsInfo();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG && parser.getName().equals("group")) {
- groupsInfo.getGroups().add(parser.nextText());
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("sharedgroup")) {
- done = true;
- }
- }
- }
- return groupsInfo;
- }
- }
-}
+package org.jivesoftware.smackx.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * IQ packet used for discovering the user's shared groups and for getting the answer back
+ * from the server.<p>
+ *
+ * Important note: This functionality is not part of the XMPP spec and it will only work
+ * with Wildfire.
+ *
+ * @author Gaston Dombiak
+ */
+public class SharedGroupsInfo extends IQ {
+
+ private List<String> groups = new ArrayList<String>();
+
+ /**
+ * Returns a collection with the shared group names returned from the server.
+ *
+ * @return collection with the shared group names returned from the server.
+ */
+ public List<String> getGroups() {
+ return groups;
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<sharedgroup xmlns=\"http://www.jivesoftware.org/protocol/sharedgroup\">");
+ for (Iterator<String> it=groups.iterator(); it.hasNext();) {
+ buf.append("<group>").append(it.next()).append("</group>");
+ }
+ buf.append("</sharedgroup>");
+ return buf.toString();
+ }
+
+ /**
+ * Internal Search service Provider.
+ */
+ public static class Provider implements IQProvider {
+
+ /**
+ * Provider Constructor.
+ */
+ public Provider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ SharedGroupsInfo groupsInfo = new SharedGroupsInfo();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG && parser.getName().equals("group")) {
+ groupsInfo.getGroups().add(parser.nextText());
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("sharedgroup")) {
+ done = true;
+ }
+ }
+ }
+ return groupsInfo;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/StreamInitiation.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/StreamInitiation.java
index 7856c1bfa..e9b6681ed 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/StreamInitiation.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/StreamInitiation.java
@@ -1,419 +1,419 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.packet;
-
-import java.util.Date;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.util.StringUtils;
-
-/**
- * The process by which two entities initiate a stream.
- *
- * @author Alexander Wenckus
- */
-public class StreamInitiation extends IQ {
-
- private String id;
-
- private String mimeType;
-
- private File file;
-
- private Feature featureNegotiation;
-
- /**
- * The "id" attribute is an opaque identifier. This attribute MUST be
- * present on type='set', and MUST be a valid string. This SHOULD NOT be
- * sent back on type='result', since the <iq/> "id" attribute provides the
- * only context needed. This value is generated by the Sender, and the same
- * value MUST be used throughout a session when talking to the Receiver.
- *
- * @param id The "id" attribute.
- */
- public void setSesssionID(final String id) {
- this.id = id;
- }
-
- /**
- * Uniquely identifies a stream initiation to the recipient.
- *
- * @return The "id" attribute.
- * @see #setSesssionID(String)
- */
- public String getSessionID() {
- return id;
- }
-
- /**
- * The "mime-type" attribute identifies the MIME-type for the data across
- * the stream. This attribute MUST be a valid MIME-type as registered with
- * the Internet Assigned Numbers Authority (IANA) [3] (specifically, as
- * listed at <http://www.iana.org/assignments/media-types>). During
- * negotiation, this attribute SHOULD be present, and is otherwise not
- * required. If not included during negotiation, its value is assumed to be
- * "binary/octect-stream".
- *
- * @param mimeType The valid mime-type.
- */
- public void setMimeType(final String mimeType) {
- this.mimeType = mimeType;
- }
-
- /**
- * Identifies the type of file that is desired to be transfered.
- *
- * @return The mime-type.
- * @see #setMimeType(String)
- */
- public String getMimeType() {
- return mimeType;
- }
-
- /**
- * Sets the file which contains the information pertaining to the file to be
- * transfered.
- *
- * @param file The file identified by the stream initiator to be sent.
- */
- public void setFile(final File file) {
- this.file = file;
- }
-
- /**
- * Returns the file containing the information about the request.
- *
- * @return Returns the file containing the information about the request.
- */
- public File getFile() {
- return file;
- }
-
- /**
- * Sets the data form which contains the valid methods of stream neotiation
- * and transfer.
- *
- * @param form The dataform containing the methods.
- */
- public void setFeatureNegotiationForm(final DataForm form) {
- this.featureNegotiation = new Feature(form);
- }
-
- /**
- * Returns the data form which contains the valid methods of stream
- * neotiation and transfer.
- *
- * @return Returns the data form which contains the valid methods of stream
- * neotiation and transfer.
- */
- public DataForm getFeatureNegotiationForm() {
- return featureNegotiation.getData();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.jivesoftware.smack.packet.IQ#getChildElementXML()
- */
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- if (this.getType().equals(IQ.Type.SET)) {
- buf.append("<si xmlns=\"http://jabber.org/protocol/si\" ");
- if (getSessionID() != null) {
- buf.append("id=\"").append(getSessionID()).append("\" ");
- }
- if (getMimeType() != null) {
- buf.append("mime-type=\"").append(getMimeType()).append("\" ");
- }
- buf
- .append("profile=\"http://jabber.org/protocol/si/profile/file-transfer\">");
-
- // Add the file section if there is one.
- String fileXML = file.toXML();
- if (fileXML != null) {
- buf.append(fileXML);
- }
- }
- else if (this.getType().equals(IQ.Type.RESULT)) {
- buf.append("<si xmlns=\"http://jabber.org/protocol/si\">");
- }
- else {
- throw new IllegalArgumentException("IQ Type not understood");
- }
- if (featureNegotiation != null) {
- buf.append(featureNegotiation.toXML());
- }
- buf.append("</si>");
- return buf.toString();
- }
-
- /**
- * <ul>
- * <li>size: The size, in bytes, of the data to be sent.</li>
- * <li>name: The name of the file that the Sender wishes to send.</li>
- * <li>date: The last modification time of the file. This is specified
- * using the DateTime profile as described in Jabber Date and Time Profiles.</li>
- * <li>hash: The MD5 sum of the file contents.</li>
- * </ul>
- * <p/>
- * <p/>
- * &lt;desc&gt; is used to provide a sender-generated description of the
- * file so the receiver can better understand what is being sent. It MUST
- * NOT be sent in the result.
- * <p/>
- * <p/>
- * When &lt;range&gt; is sent in the offer, it should have no attributes.
- * This signifies that the sender can do ranged transfers. When a Stream
- * Initiation result is sent with the <range> element, it uses these
- * attributes:
- * <p/>
- * <ul>
- * <li>offset: Specifies the position, in bytes, to start transferring the
- * file data from. This defaults to zero (0) if not specified.</li>
- * <li>length - Specifies the number of bytes to retrieve starting at
- * offset. This defaults to the length of the file from offset to the end.</li>
- * </ul>
- * <p/>
- * <p/>
- * Both attributes are OPTIONAL on the &lt;range&gt; element. Sending no
- * attributes is synonymous with not sending the &lt;range&gt; element. When
- * no &lt;range&gt; element is sent in the Stream Initiation result, the
- * Sender MUST send the complete file starting at offset 0. More generally,
- * data is sent over the stream byte for byte starting at the offset
- * position for the length specified.
- *
- * @author Alexander Wenckus
- */
- public static class File implements PacketExtension {
-
- private final String name;
-
- private final long size;
-
- private String hash;
-
- private Date date;
-
- private String desc;
-
- private boolean isRanged;
-
- /**
- * Constructor providing the name of the file and its size.
- *
- * @param name The name of the file.
- * @param size The size of the file in bytes.
- */
- public File(final String name, final long size) {
- if (name == null) {
- throw new NullPointerException("name cannot be null");
- }
-
- this.name = name;
- this.size = size;
- }
-
- /**
- * Returns the file's name.
- *
- * @return Returns the file's name.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the file's size.
- *
- * @return Returns the file's size.
- */
- public long getSize() {
- return size;
- }
-
- /**
- * Sets the MD5 sum of the file's contents
- *
- * @param hash The MD5 sum of the file's contents.
- */
- public void setHash(final String hash) {
- this.hash = hash;
- }
-
- /**
- * Returns the MD5 sum of the file's contents
- *
- * @return Returns the MD5 sum of the file's contents
- */
- public String getHash() {
- return hash;
- }
-
- /**
- * Sets the date that the file was last modified.
- *
- * @param date The date that the file was last modified.
- */
- public void setDate(Date date) {
- this.date = date;
- }
-
- /**
- * Returns the date that the file was last modified.
- *
- * @return Returns the date that the file was last modified.
- */
- public Date getDate() {
- return date;
- }
-
- /**
- * Sets the description of the file.
- *
- * @param desc The description of the file so that the file reciever can
- * know what file it is.
- */
- public void setDesc(final String desc) {
- this.desc = desc;
- }
-
- /**
- * Returns the description of the file.
- *
- * @return Returns the description of the file.
- */
- public String getDesc() {
- return desc;
- }
-
- /**
- * True if a range can be provided and false if it cannot.
- *
- * @param isRanged True if a range can be provided and false if it cannot.
- */
- public void setRanged(final boolean isRanged) {
- this.isRanged = isRanged;
- }
-
- /**
- * Returns whether or not the initiator can support a range for the file
- * tranfer.
- *
- * @return Returns whether or not the initiator can support a range for
- * the file tranfer.
- */
- public boolean isRanged() {
- return isRanged;
- }
-
- public String getElementName() {
- return "file";
- }
-
- public String getNamespace() {
- return "http://jabber.org/protocol/si/profile/file-transfer";
- }
-
- public String toXML() {
- StringBuilder buffer = new StringBuilder();
-
- buffer.append("<").append(getElementName()).append(" xmlns=\"")
- .append(getNamespace()).append("\" ");
-
- if (getName() != null) {
- buffer.append("name=\"").append(StringUtils.escapeForXML(getName())).append("\" ");
- }
-
- if (getSize() > 0) {
- buffer.append("size=\"").append(getSize()).append("\" ");
- }
-
- if (getDate() != null) {
- buffer.append("date=\"").append(StringUtils.formatXEP0082Date(date)).append("\" ");
- }
-
- if (getHash() != null) {
- buffer.append("hash=\"").append(getHash()).append("\" ");
- }
-
- if ((desc != null && desc.length() > 0) || isRanged) {
- buffer.append(">");
- if (getDesc() != null && desc.length() > 0) {
- buffer.append("<desc>").append(StringUtils.escapeForXML(getDesc())).append("</desc>");
- }
- if (isRanged()) {
- buffer.append("<range/>");
- }
- buffer.append("</").append(getElementName()).append(">");
- }
- else {
- buffer.append("/>");
- }
- return buffer.toString();
- }
- }
-
- /**
- * The feature negotiation portion of the StreamInitiation packet.
- *
- * @author Alexander Wenckus
- *
- */
- public class Feature implements PacketExtension {
-
- private final DataForm data;
-
- /**
- * The dataform can be provided as part of the constructor.
- *
- * @param data The dataform.
- */
- public Feature(final DataForm data) {
- this.data = data;
- }
-
- /**
- * Returns the dataform associated with the feature negotiation.
- *
- * @return Returns the dataform associated with the feature negotiation.
- */
- public DataForm getData() {
- return data;
- }
-
- public String getNamespace() {
- return "http://jabber.org/protocol/feature-neg";
- }
-
- public String getElementName() {
- return "feature";
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf
- .append("<feature xmlns=\"http://jabber.org/protocol/feature-neg\">");
- buf.append(data.toXML());
- buf.append("</feature>");
- return buf.toString();
- }
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.packet;
+
+import java.util.Date;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.util.StringUtils;
+
+/**
+ * The process by which two entities initiate a stream.
+ *
+ * @author Alexander Wenckus
+ */
+public class StreamInitiation extends IQ {
+
+ private String id;
+
+ private String mimeType;
+
+ private File file;
+
+ private Feature featureNegotiation;
+
+ /**
+ * The "id" attribute is an opaque identifier. This attribute MUST be
+ * present on type='set', and MUST be a valid string. This SHOULD NOT be
+ * sent back on type='result', since the <iq/> "id" attribute provides the
+ * only context needed. This value is generated by the Sender, and the same
+ * value MUST be used throughout a session when talking to the Receiver.
+ *
+ * @param id The "id" attribute.
+ */
+ public void setSesssionID(final String id) {
+ this.id = id;
+ }
+
+ /**
+ * Uniquely identifies a stream initiation to the recipient.
+ *
+ * @return The "id" attribute.
+ * @see #setSesssionID(String)
+ */
+ public String getSessionID() {
+ return id;
+ }
+
+ /**
+ * The "mime-type" attribute identifies the MIME-type for the data across
+ * the stream. This attribute MUST be a valid MIME-type as registered with
+ * the Internet Assigned Numbers Authority (IANA) [3] (specifically, as
+ * listed at <http://www.iana.org/assignments/media-types>). During
+ * negotiation, this attribute SHOULD be present, and is otherwise not
+ * required. If not included during negotiation, its value is assumed to be
+ * "binary/octect-stream".
+ *
+ * @param mimeType The valid mime-type.
+ */
+ public void setMimeType(final String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+ /**
+ * Identifies the type of file that is desired to be transfered.
+ *
+ * @return The mime-type.
+ * @see #setMimeType(String)
+ */
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ /**
+ * Sets the file which contains the information pertaining to the file to be
+ * transfered.
+ *
+ * @param file The file identified by the stream initiator to be sent.
+ */
+ public void setFile(final File file) {
+ this.file = file;
+ }
+
+ /**
+ * Returns the file containing the information about the request.
+ *
+ * @return Returns the file containing the information about the request.
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * Sets the data form which contains the valid methods of stream neotiation
+ * and transfer.
+ *
+ * @param form The dataform containing the methods.
+ */
+ public void setFeatureNegotiationForm(final DataForm form) {
+ this.featureNegotiation = new Feature(form);
+ }
+
+ /**
+ * Returns the data form which contains the valid methods of stream
+ * neotiation and transfer.
+ *
+ * @return Returns the data form which contains the valid methods of stream
+ * neotiation and transfer.
+ */
+ public DataForm getFeatureNegotiationForm() {
+ return featureNegotiation.getData();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.packet.IQ#getChildElementXML()
+ */
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ if (this.getType().equals(IQ.Type.SET)) {
+ buf.append("<si xmlns=\"http://jabber.org/protocol/si\" ");
+ if (getSessionID() != null) {
+ buf.append("id=\"").append(getSessionID()).append("\" ");
+ }
+ if (getMimeType() != null) {
+ buf.append("mime-type=\"").append(getMimeType()).append("\" ");
+ }
+ buf
+ .append("profile=\"http://jabber.org/protocol/si/profile/file-transfer\">");
+
+ // Add the file section if there is one.
+ String fileXML = file.toXML();
+ if (fileXML != null) {
+ buf.append(fileXML);
+ }
+ }
+ else if (this.getType().equals(IQ.Type.RESULT)) {
+ buf.append("<si xmlns=\"http://jabber.org/protocol/si\">");
+ }
+ else {
+ throw new IllegalArgumentException("IQ Type not understood");
+ }
+ if (featureNegotiation != null) {
+ buf.append(featureNegotiation.toXML());
+ }
+ buf.append("</si>");
+ return buf.toString();
+ }
+
+ /**
+ * <ul>
+ * <li>size: The size, in bytes, of the data to be sent.</li>
+ * <li>name: The name of the file that the Sender wishes to send.</li>
+ * <li>date: The last modification time of the file. This is specified
+ * using the DateTime profile as described in Jabber Date and Time Profiles.</li>
+ * <li>hash: The MD5 sum of the file contents.</li>
+ * </ul>
+ * <p/>
+ * <p/>
+ * &lt;desc&gt; is used to provide a sender-generated description of the
+ * file so the receiver can better understand what is being sent. It MUST
+ * NOT be sent in the result.
+ * <p/>
+ * <p/>
+ * When &lt;range&gt; is sent in the offer, it should have no attributes.
+ * This signifies that the sender can do ranged transfers. When a Stream
+ * Initiation result is sent with the <range> element, it uses these
+ * attributes:
+ * <p/>
+ * <ul>
+ * <li>offset: Specifies the position, in bytes, to start transferring the
+ * file data from. This defaults to zero (0) if not specified.</li>
+ * <li>length - Specifies the number of bytes to retrieve starting at
+ * offset. This defaults to the length of the file from offset to the end.</li>
+ * </ul>
+ * <p/>
+ * <p/>
+ * Both attributes are OPTIONAL on the &lt;range&gt; element. Sending no
+ * attributes is synonymous with not sending the &lt;range&gt; element. When
+ * no &lt;range&gt; element is sent in the Stream Initiation result, the
+ * Sender MUST send the complete file starting at offset 0. More generally,
+ * data is sent over the stream byte for byte starting at the offset
+ * position for the length specified.
+ *
+ * @author Alexander Wenckus
+ */
+ public static class File implements PacketExtension {
+
+ private final String name;
+
+ private final long size;
+
+ private String hash;
+
+ private Date date;
+
+ private String desc;
+
+ private boolean isRanged;
+
+ /**
+ * Constructor providing the name of the file and its size.
+ *
+ * @param name The name of the file.
+ * @param size The size of the file in bytes.
+ */
+ public File(final String name, final long size) {
+ if (name == null) {
+ throw new NullPointerException("name cannot be null");
+ }
+
+ this.name = name;
+ this.size = size;
+ }
+
+ /**
+ * Returns the file's name.
+ *
+ * @return Returns the file's name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the file's size.
+ *
+ * @return Returns the file's size.
+ */
+ public long getSize() {
+ return size;
+ }
+
+ /**
+ * Sets the MD5 sum of the file's contents
+ *
+ * @param hash The MD5 sum of the file's contents.
+ */
+ public void setHash(final String hash) {
+ this.hash = hash;
+ }
+
+ /**
+ * Returns the MD5 sum of the file's contents
+ *
+ * @return Returns the MD5 sum of the file's contents
+ */
+ public String getHash() {
+ return hash;
+ }
+
+ /**
+ * Sets the date that the file was last modified.
+ *
+ * @param date The date that the file was last modified.
+ */
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ /**
+ * Returns the date that the file was last modified.
+ *
+ * @return Returns the date that the file was last modified.
+ */
+ public Date getDate() {
+ return date;
+ }
+
+ /**
+ * Sets the description of the file.
+ *
+ * @param desc The description of the file so that the file reciever can
+ * know what file it is.
+ */
+ public void setDesc(final String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * Returns the description of the file.
+ *
+ * @return Returns the description of the file.
+ */
+ public String getDesc() {
+ return desc;
+ }
+
+ /**
+ * True if a range can be provided and false if it cannot.
+ *
+ * @param isRanged True if a range can be provided and false if it cannot.
+ */
+ public void setRanged(final boolean isRanged) {
+ this.isRanged = isRanged;
+ }
+
+ /**
+ * Returns whether or not the initiator can support a range for the file
+ * tranfer.
+ *
+ * @return Returns whether or not the initiator can support a range for
+ * the file tranfer.
+ */
+ public boolean isRanged() {
+ return isRanged;
+ }
+
+ public String getElementName() {
+ return "file";
+ }
+
+ public String getNamespace() {
+ return "http://jabber.org/protocol/si/profile/file-transfer";
+ }
+
+ public String toXML() {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append("<").append(getElementName()).append(" xmlns=\"")
+ .append(getNamespace()).append("\" ");
+
+ if (getName() != null) {
+ buffer.append("name=\"").append(StringUtils.escapeForXML(getName())).append("\" ");
+ }
+
+ if (getSize() > 0) {
+ buffer.append("size=\"").append(getSize()).append("\" ");
+ }
+
+ if (getDate() != null) {
+ buffer.append("date=\"").append(StringUtils.formatXEP0082Date(date)).append("\" ");
+ }
+
+ if (getHash() != null) {
+ buffer.append("hash=\"").append(getHash()).append("\" ");
+ }
+
+ if ((desc != null && desc.length() > 0) || isRanged) {
+ buffer.append(">");
+ if (getDesc() != null && desc.length() > 0) {
+ buffer.append("<desc>").append(StringUtils.escapeForXML(getDesc())).append("</desc>");
+ }
+ if (isRanged()) {
+ buffer.append("<range/>");
+ }
+ buffer.append("</").append(getElementName()).append(">");
+ }
+ else {
+ buffer.append("/>");
+ }
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * The feature negotiation portion of the StreamInitiation packet.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+ public class Feature implements PacketExtension {
+
+ private final DataForm data;
+
+ /**
+ * The dataform can be provided as part of the constructor.
+ *
+ * @param data The dataform.
+ */
+ public Feature(final DataForm data) {
+ this.data = data;
+ }
+
+ /**
+ * Returns the dataform associated with the feature negotiation.
+ *
+ * @return Returns the dataform associated with the feature negotiation.
+ */
+ public DataForm getData() {
+ return data;
+ }
+
+ public String getNamespace() {
+ return "http://jabber.org/protocol/feature-neg";
+ }
+
+ public String getElementName() {
+ return "feature";
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf
+ .append("<feature xmlns=\"http://jabber.org/protocol/feature-neg\">");
+ buf.append(data.toXML());
+ buf.append("</feature>");
+ return buf.toString();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/AdHocCommandDataProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/AdHocCommandDataProvider.java
index 63d24ec38..3bc445ee5 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/AdHocCommandDataProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/AdHocCommandDataProvider.java
@@ -1,155 +1,155 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2005-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
- *
- * 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.provider;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.jivesoftware.smackx.commands.AdHocCommand;
-import org.jivesoftware.smackx.commands.AdHocCommand.Action;
-import org.jivesoftware.smackx.commands.AdHocCommandNote;
-import org.jivesoftware.smackx.packet.AdHocCommandData;
-import org.jivesoftware.smackx.packet.DataForm;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * The AdHocCommandDataProvider parses AdHocCommandData packets.
- *
- * @author Gabriel Guardincerri
- */
-public class AdHocCommandDataProvider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- boolean done = false;
- AdHocCommandData adHocCommandData = new AdHocCommandData();
- DataFormProvider dataFormProvider = new DataFormProvider();
-
- int eventType;
- String elementName;
- String namespace;
- adHocCommandData.setSessionID(parser.getAttributeValue("", "sessionid"));
- adHocCommandData.setNode(parser.getAttributeValue("", "node"));
-
- // Status
- String status = parser.getAttributeValue("", "status");
- if (AdHocCommand.Status.executing.toString().equalsIgnoreCase(status)) {
- adHocCommandData.setStatus(AdHocCommand.Status.executing);
- }
- else if (AdHocCommand.Status.completed.toString().equalsIgnoreCase(status)) {
- adHocCommandData.setStatus(AdHocCommand.Status.completed);
- }
- else if (AdHocCommand.Status.canceled.toString().equalsIgnoreCase(status)) {
- adHocCommandData.setStatus(AdHocCommand.Status.canceled);
- }
-
- // Action
- String action = parser.getAttributeValue("", "action");
- if (action != null) {
- Action realAction = AdHocCommand.Action.valueOf(action);
- if (realAction == null || realAction.equals(Action.unknown)) {
- adHocCommandData.setAction(Action.unknown);
- }
- else {
- adHocCommandData.setAction(realAction);
- }
- }
- while (!done) {
- eventType = parser.next();
- elementName = parser.getName();
- namespace = parser.getNamespace();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("actions")) {
- String execute = parser.getAttributeValue("", "execute");
- if (execute != null) {
- adHocCommandData.setExecuteAction(AdHocCommand.Action.valueOf(execute));
- }
- }
- else if (parser.getName().equals("next")) {
- adHocCommandData.addAction(AdHocCommand.Action.next);
- }
- else if (parser.getName().equals("complete")) {
- adHocCommandData.addAction(AdHocCommand.Action.complete);
- }
- else if (parser.getName().equals("prev")) {
- adHocCommandData.addAction(AdHocCommand.Action.prev);
- }
- else if (elementName.equals("x") && namespace.equals("jabber:x:data")) {
- adHocCommandData.setForm((DataForm) dataFormProvider.parseExtension(parser));
- }
- else if (parser.getName().equals("note")) {
- AdHocCommandNote.Type type = AdHocCommandNote.Type.valueOf(
- parser.getAttributeValue("", "type"));
- String value = parser.nextText();
- adHocCommandData.addNote(new AdHocCommandNote(type, value));
- }
- else if (parser.getName().equals("error")) {
- XMPPError error = PacketParserUtils.parseError(parser);
- adHocCommandData.setError(error);
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("command")) {
- done = true;
- }
- }
- }
- return adHocCommandData;
- }
-
- public static class BadActionError implements PacketExtensionProvider {
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.badAction);
- }
- }
-
- public static class MalformedActionError implements PacketExtensionProvider {
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.malformedAction);
- }
- }
-
- public static class BadLocaleError implements PacketExtensionProvider {
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.badLocale);
- }
- }
-
- public static class BadPayloadError implements PacketExtensionProvider {
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.badPayload);
- }
- }
-
- public static class BadSessionIDError implements PacketExtensionProvider {
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.badSessionid);
- }
- }
-
- public static class SessionExpiredError implements PacketExtensionProvider {
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.sessionExpired);
- }
- }
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2005-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
+ *
+ * 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.provider;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.commands.AdHocCommand;
+import org.jivesoftware.smackx.commands.AdHocCommand.Action;
+import org.jivesoftware.smackx.commands.AdHocCommandNote;
+import org.jivesoftware.smackx.packet.AdHocCommandData;
+import org.jivesoftware.smackx.packet.DataForm;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * The AdHocCommandDataProvider parses AdHocCommandData packets.
+ *
+ * @author Gabriel Guardincerri
+ */
+public class AdHocCommandDataProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ AdHocCommandData adHocCommandData = new AdHocCommandData();
+ DataFormProvider dataFormProvider = new DataFormProvider();
+
+ int eventType;
+ String elementName;
+ String namespace;
+ adHocCommandData.setSessionID(parser.getAttributeValue("", "sessionid"));
+ adHocCommandData.setNode(parser.getAttributeValue("", "node"));
+
+ // Status
+ String status = parser.getAttributeValue("", "status");
+ if (AdHocCommand.Status.executing.toString().equalsIgnoreCase(status)) {
+ adHocCommandData.setStatus(AdHocCommand.Status.executing);
+ }
+ else if (AdHocCommand.Status.completed.toString().equalsIgnoreCase(status)) {
+ adHocCommandData.setStatus(AdHocCommand.Status.completed);
+ }
+ else if (AdHocCommand.Status.canceled.toString().equalsIgnoreCase(status)) {
+ adHocCommandData.setStatus(AdHocCommand.Status.canceled);
+ }
+
+ // Action
+ String action = parser.getAttributeValue("", "action");
+ if (action != null) {
+ Action realAction = AdHocCommand.Action.valueOf(action);
+ if (realAction == null || realAction.equals(Action.unknown)) {
+ adHocCommandData.setAction(Action.unknown);
+ }
+ else {
+ adHocCommandData.setAction(realAction);
+ }
+ }
+ while (!done) {
+ eventType = parser.next();
+ elementName = parser.getName();
+ namespace = parser.getNamespace();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("actions")) {
+ String execute = parser.getAttributeValue("", "execute");
+ if (execute != null) {
+ adHocCommandData.setExecuteAction(AdHocCommand.Action.valueOf(execute));
+ }
+ }
+ else if (parser.getName().equals("next")) {
+ adHocCommandData.addAction(AdHocCommand.Action.next);
+ }
+ else if (parser.getName().equals("complete")) {
+ adHocCommandData.addAction(AdHocCommand.Action.complete);
+ }
+ else if (parser.getName().equals("prev")) {
+ adHocCommandData.addAction(AdHocCommand.Action.prev);
+ }
+ else if (elementName.equals("x") && namespace.equals("jabber:x:data")) {
+ adHocCommandData.setForm((DataForm) dataFormProvider.parseExtension(parser));
+ }
+ else if (parser.getName().equals("note")) {
+ AdHocCommandNote.Type type = AdHocCommandNote.Type.valueOf(
+ parser.getAttributeValue("", "type"));
+ String value = parser.nextText();
+ adHocCommandData.addNote(new AdHocCommandNote(type, value));
+ }
+ else if (parser.getName().equals("error")) {
+ XMPPError error = PacketParserUtils.parseError(parser);
+ adHocCommandData.setError(error);
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("command")) {
+ done = true;
+ }
+ }
+ }
+ return adHocCommandData;
+ }
+
+ public static class BadActionError implements PacketExtensionProvider {
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.badAction);
+ }
+ }
+
+ public static class MalformedActionError implements PacketExtensionProvider {
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.malformedAction);
+ }
+ }
+
+ public static class BadLocaleError implements PacketExtensionProvider {
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.badLocale);
+ }
+ }
+
+ public static class BadPayloadError implements PacketExtensionProvider {
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.badPayload);
+ }
+ }
+
+ public static class BadSessionIDError implements PacketExtensionProvider {
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.badSessionid);
+ }
+ }
+
+ public static class SessionExpiredError implements PacketExtensionProvider {
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ return new AdHocCommandData.SpecificError(AdHocCommand.SpecificErrorCondition.sessionExpired);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/DelayInfoProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/DelayInfoProvider.java
index 9d1dcd8f4..6fa52b7e7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/DelayInfoProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/DelayInfoProvider.java
@@ -1,42 +1,42 @@
-/**
- * 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.provider;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.packet.DelayInfo;
-import org.jivesoftware.smackx.packet.DelayInformation;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * This provider simply creates a {@link DelayInfo} decorator for the {@link DelayInformation} that
- * is returned by the superclass. This allows the new code using
- * <a href="http://xmpp.org/extensions/xep-0203.html">Delay Information XEP-0203</a> to be
- * backward compatible with <a href="http://xmpp.org/extensions/xep-0091.html">XEP-0091</a>.
- *
- * <p>This provider must be registered in the <b>smack.properties</b> file for the element
- * <b>delay</b> with namespace <b>urn:xmpp:delay</b></p>
- *
- * @author Robin Collier
- */
-public class DelayInfoProvider extends DelayInformationProvider
-{
-
- @Override
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception
- {
- return new DelayInfo((DelayInformation)super.parseExtension(parser));
- }
-
-}
+/**
+ * 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.provider;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.packet.DelayInfo;
+import org.jivesoftware.smackx.packet.DelayInformation;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * This provider simply creates a {@link DelayInfo} decorator for the {@link DelayInformation} that
+ * is returned by the superclass. This allows the new code using
+ * <a href="http://xmpp.org/extensions/xep-0203.html">Delay Information XEP-0203</a> to be
+ * backward compatible with <a href="http://xmpp.org/extensions/xep-0091.html">XEP-0091</a>.
+ *
+ * <p>This provider must be registered in the <b>smack.properties</b> file for the element
+ * <b>delay</b> with namespace <b>urn:xmpp:delay</b></p>
+ *
+ * @author Robin Collier
+ */
+public class DelayInfoProvider extends DelayInformationProvider
+{
+
+ @Override
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception
+ {
+ return new DelayInfo((DelayInformation)super.parseExtension(parser));
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/EmbeddedExtensionProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/EmbeddedExtensionProvider.java
index 3d5ceb458..55c6726d2 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/EmbeddedExtensionProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/EmbeddedExtensionProvider.java
@@ -1,111 +1,111 @@
-/**
- * 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.provider;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
-import org.jivesoftware.smackx.pubsub.provider.ItemsProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- *
- * This class simplifies parsing of embedded elements by using the
- * <a href="http://en.wikipedia.org/wiki/Template_method_pattern">Template Method Pattern</a>.
- * After extracting the current element attributes and content of any child elements, the template method
- * ({@link #createReturnExtension(String, String, Map, List)} is called. Subclasses
- * then override this method to create the specific return type.
- *
- * <p>To use this class, you simply register your subclasses as extension providers in the
- * <b>smack.properties</b> file. Then they will be automatically picked up and used to parse
- * any child elements.
- *
- * <pre>
- * For example, given the following message
- *
- * &lt;message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo&gt;
- * &lt;event xmlns='http://jabber.org/protocol/pubsub#event&gt;
- * &lt;items node='princely_musings'&gt;
- * &lt;item id='asdjkwei3i34234n356'&gt;
- * &lt;entry xmlns='http://www.w3.org/2005/Atom'&gt;
- * &lt;title&gt;Soliloquy&lt;/title&gt;
- * &lt;link rel='alternative' type='text/html'/&gt;
- * &lt;id>tag:denmark.lit,2003:entry-32397&lt;/id&gt;
- * &lt;/entry&gt;
- * &lt;/item&gt;
- * &lt;/items&gt;
- * &lt;/event&gt;
- * &lt;/message&gt;
- *
- * I would have a classes
- * {@link ItemsProvider} extends {@link EmbeddedExtensionProvider}
- * {@link ItemProvider} extends {@link EmbeddedExtensionProvider}
- * and
- * AtomProvider extends {@link PacketExtensionProvider}
- *
- * These classes are then registered in the meta-inf/smack.providers file
- * as follows.
- *
- * &lt;extensionProvider&gt;
- * &lt;elementName&gt;items&lt;/elementName&gt;
- * &lt;namespace&gt;http://jabber.org/protocol/pubsub#event&lt;/namespace&gt;
- * &lt;className&gt;org.jivesoftware.smackx.provider.ItemsEventProvider&lt;/className&gt;
- * &lt;/extensionProvider&gt;
- * &lt;extensionProvider&gt;
- * &lt;elementName&gt;item&lt;/elementName&gt;
- * &lt;namespace&gt;http://jabber.org/protocol/pubsub#event&lt;/namespace&gt;
- * &lt;className&gt;org.jivesoftware.smackx.provider.ItemProvider&lt;/className&gt;
- * &lt;/extensionProvider&gt;
- *
- * </pre>
- *
- * @author Robin Collier
- *
- * @deprecated This has been moved to {@link org.jivesoftware.smack.provider.EmbeddedExtensionProvider}
- */
-abstract public class EmbeddedExtensionProvider implements PacketExtensionProvider
-{
-
- final public PacketExtension parseExtension(XmlPullParser parser) throws Exception
- {
- String namespace = parser.getNamespace();
- String name = parser.getName();
- Map<String, String> attMap = new HashMap<String, String>();
-
- for(int i=0; i<parser.getAttributeCount(); i++)
- {
- attMap.put(parser.getAttributeName(i), parser.getAttributeValue(i));
- }
- List<PacketExtension> extensions = new ArrayList<PacketExtension>();
-
- do
- {
- int tag = parser.next();
-
- if (tag == XmlPullParser.START_TAG)
- extensions.add(PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser));
- } while (!name.equals(parser.getName()));
-
- return createReturnExtension(name, namespace, attMap, extensions);
- }
-
- abstract protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content);
-}
+/**
+ * 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.provider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
+import org.jivesoftware.smackx.pubsub.provider.ItemsProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ *
+ * This class simplifies parsing of embedded elements by using the
+ * <a href="http://en.wikipedia.org/wiki/Template_method_pattern">Template Method Pattern</a>.
+ * After extracting the current element attributes and content of any child elements, the template method
+ * ({@link #createReturnExtension(String, String, Map, List)} is called. Subclasses
+ * then override this method to create the specific return type.
+ *
+ * <p>To use this class, you simply register your subclasses as extension providers in the
+ * <b>smack.properties</b> file. Then they will be automatically picked up and used to parse
+ * any child elements.
+ *
+ * <pre>
+ * For example, given the following message
+ *
+ * &lt;message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo&gt;
+ * &lt;event xmlns='http://jabber.org/protocol/pubsub#event&gt;
+ * &lt;items node='princely_musings'&gt;
+ * &lt;item id='asdjkwei3i34234n356'&gt;
+ * &lt;entry xmlns='http://www.w3.org/2005/Atom'&gt;
+ * &lt;title&gt;Soliloquy&lt;/title&gt;
+ * &lt;link rel='alternative' type='text/html'/&gt;
+ * &lt;id>tag:denmark.lit,2003:entry-32397&lt;/id&gt;
+ * &lt;/entry&gt;
+ * &lt;/item&gt;
+ * &lt;/items&gt;
+ * &lt;/event&gt;
+ * &lt;/message&gt;
+ *
+ * I would have a classes
+ * {@link ItemsProvider} extends {@link EmbeddedExtensionProvider}
+ * {@link ItemProvider} extends {@link EmbeddedExtensionProvider}
+ * and
+ * AtomProvider extends {@link PacketExtensionProvider}
+ *
+ * These classes are then registered in the meta-inf/smack.providers file
+ * as follows.
+ *
+ * &lt;extensionProvider&gt;
+ * &lt;elementName&gt;items&lt;/elementName&gt;
+ * &lt;namespace&gt;http://jabber.org/protocol/pubsub#event&lt;/namespace&gt;
+ * &lt;className&gt;org.jivesoftware.smackx.provider.ItemsEventProvider&lt;/className&gt;
+ * &lt;/extensionProvider&gt;
+ * &lt;extensionProvider&gt;
+ * &lt;elementName&gt;item&lt;/elementName&gt;
+ * &lt;namespace&gt;http://jabber.org/protocol/pubsub#event&lt;/namespace&gt;
+ * &lt;className&gt;org.jivesoftware.smackx.provider.ItemProvider&lt;/className&gt;
+ * &lt;/extensionProvider&gt;
+ *
+ * </pre>
+ *
+ * @author Robin Collier
+ *
+ * @deprecated This has been moved to {@link org.jivesoftware.smack.provider.EmbeddedExtensionProvider}
+ */
+abstract public class EmbeddedExtensionProvider implements PacketExtensionProvider
+{
+
+ final public PacketExtension parseExtension(XmlPullParser parser) throws Exception
+ {
+ String namespace = parser.getNamespace();
+ String name = parser.getName();
+ Map<String, String> attMap = new HashMap<String, String>();
+
+ for(int i=0; i<parser.getAttributeCount(); i++)
+ {
+ attMap.put(parser.getAttributeName(i), parser.getAttributeValue(i));
+ }
+ List<PacketExtension> extensions = new ArrayList<PacketExtension>();
+
+ do
+ {
+ int tag = parser.next();
+
+ if (tag == XmlPullParser.START_TAG)
+ extensions.add(PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser));
+ } while (!name.equals(parser.getName()));
+
+ return createReturnExtension(name, namespace, attMap, extensions);
+ }
+
+ abstract protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content);
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeaderProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeaderProvider.java
index 7344880ab..b6e55a36b 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeaderProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeaderProvider.java
@@ -1,44 +1,44 @@
-/**
- * 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.provider;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smackx.packet.Header;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Parses the header element as defined in <a href="http://xmpp.org/extensions/xep-0131">Stanza Headers and Internet Metadata (SHIM)</a>.
- *
- * @author Robin Collier
- */
-public class HeaderProvider implements PacketExtensionProvider
-{
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception
- {
- String name = parser.getAttributeValue(null, "name");
- String value = null;
-
- parser.next();
-
- if (parser.getEventType() == XmlPullParser.TEXT)
- value = parser.getText();
-
- while(parser.getEventType() != XmlPullParser.END_TAG)
- parser.next();
-
- return new Header(name, value);
- }
-
-}
+/**
+ * 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.provider;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smackx.packet.Header;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses the header element as defined in <a href="http://xmpp.org/extensions/xep-0131">Stanza Headers and Internet Metadata (SHIM)</a>.
+ *
+ * @author Robin Collier
+ */
+public class HeaderProvider implements PacketExtensionProvider
+{
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception
+ {
+ String name = parser.getAttributeValue(null, "name");
+ String value = null;
+
+ parser.next();
+
+ if (parser.getEventType() == XmlPullParser.TEXT)
+ value = parser.getText();
+
+ while(parser.getEventType() != XmlPullParser.END_TAG)
+ parser.next();
+
+ return new Header(name, value);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeadersProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeadersProvider.java
index 056dd5826..0c3158dba 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeadersProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/HeadersProvider.java
@@ -1,37 +1,37 @@
-/**
- * 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.provider;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.packet.Header;
-import org.jivesoftware.smackx.packet.HeadersExtension;
-
-/**
- * Parses the headers element as defined in <a href="http://xmpp.org/extensions/xep-0131">Stanza Headers and Internet Metadata (SHIM)</a>.
- *
- * @author Robin Collier
- */
-public class HeadersProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new HeadersExtension((Collection<Header>)content);
- }
-
-}
+/**
+ * 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.provider;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.packet.Header;
+import org.jivesoftware.smackx.packet.HeadersExtension;
+
+/**
+ * Parses the headers element as defined in <a href="http://xmpp.org/extensions/xep-0131">Stanza Headers and Internet Metadata (SHIM)</a>.
+ *
+ * @author Robin Collier
+ */
+public class HeadersProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new HeadersExtension((Collection<Header>)content);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/StreamInitiationProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/StreamInitiationProvider.java
index 11ab33976..d5998110b 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/StreamInitiationProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/provider/StreamInitiationProvider.java
@@ -1,124 +1,124 @@
-/**
- * $RCSfile$
- * $Revision$
- * $Date$
- *
- * Copyright 2003-2006 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
- *
- * 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.provider;
-
-import java.text.ParseException;
-import java.util.Date;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smackx.packet.DataForm;
-import org.jivesoftware.smackx.packet.StreamInitiation;
-import org.jivesoftware.smackx.packet.StreamInitiation.File;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * The StreamInitiationProvider parses StreamInitiation packets.
- *
- * @author Alexander Wenckus
- *
- */
-public class StreamInitiationProvider implements IQProvider {
-
- public IQ parseIQ(final XmlPullParser parser) throws Exception {
- boolean done = false;
-
- // si
- String id = parser.getAttributeValue("", "id");
- String mimeType = parser.getAttributeValue("", "mime-type");
-
- StreamInitiation initiation = new StreamInitiation();
-
- // file
- String name = null;
- String size = null;
- String hash = null;
- String date = null;
- String desc = null;
- boolean isRanged = false;
-
- // feature
- DataForm form = null;
- DataFormProvider dataFormProvider = new DataFormProvider();
-
- int eventType;
- String elementName;
- String namespace;
- while (!done) {
- eventType = parser.next();
- elementName = parser.getName();
- namespace = parser.getNamespace();
- if (eventType == XmlPullParser.START_TAG) {
- if (elementName.equals("file")) {
- name = parser.getAttributeValue("", "name");
- size = parser.getAttributeValue("", "size");
- hash = parser.getAttributeValue("", "hash");
- date = parser.getAttributeValue("", "date");
- } else if (elementName.equals("desc")) {
- desc = parser.nextText();
- } else if (elementName.equals("range")) {
- isRanged = true;
- } else if (elementName.equals("x")
- && namespace.equals("jabber:x:data")) {
- form = (DataForm) dataFormProvider.parseExtension(parser);
- }
- } else if (eventType == XmlPullParser.END_TAG) {
- if (elementName.equals("si")) {
- done = true;
- } else if (elementName.equals("file")) {
- long fileSize = 0;
- if(size != null && size.trim().length() !=0){
- try {
- fileSize = Long.parseLong(size);
- }
- catch (NumberFormatException e) {
- e.printStackTrace();
- }
- }
-
- Date fileDate = new Date();
- if (date != null) {
- try {
- fileDate = StringUtils.parseXEP0082Date(date);
- } catch (ParseException e) {
- // couldn't parse date, use current date-time
- }
- }
-
- File file = new File(name, fileSize);
- file.setHash(hash);
- file.setDate(fileDate);
- file.setDesc(desc);
- file.setRanged(isRanged);
- initiation.setFile(file);
- }
- }
- }
-
- initiation.setSesssionID(id);
- initiation.setMimeType(mimeType);
-
- initiation.setFeatureNegotiationForm(form);
-
- return initiation;
- }
-
-}
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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
+ *
+ * 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.provider;
+
+import java.text.ParseException;
+import java.util.Date;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.packet.DataForm;
+import org.jivesoftware.smackx.packet.StreamInitiation;
+import org.jivesoftware.smackx.packet.StreamInitiation.File;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * The StreamInitiationProvider parses StreamInitiation packets.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+public class StreamInitiationProvider implements IQProvider {
+
+ public IQ parseIQ(final XmlPullParser parser) throws Exception {
+ boolean done = false;
+
+ // si
+ String id = parser.getAttributeValue("", "id");
+ String mimeType = parser.getAttributeValue("", "mime-type");
+
+ StreamInitiation initiation = new StreamInitiation();
+
+ // file
+ String name = null;
+ String size = null;
+ String hash = null;
+ String date = null;
+ String desc = null;
+ boolean isRanged = false;
+
+ // feature
+ DataForm form = null;
+ DataFormProvider dataFormProvider = new DataFormProvider();
+
+ int eventType;
+ String elementName;
+ String namespace;
+ while (!done) {
+ eventType = parser.next();
+ elementName = parser.getName();
+ namespace = parser.getNamespace();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (elementName.equals("file")) {
+ name = parser.getAttributeValue("", "name");
+ size = parser.getAttributeValue("", "size");
+ hash = parser.getAttributeValue("", "hash");
+ date = parser.getAttributeValue("", "date");
+ } else if (elementName.equals("desc")) {
+ desc = parser.nextText();
+ } else if (elementName.equals("range")) {
+ isRanged = true;
+ } else if (elementName.equals("x")
+ && namespace.equals("jabber:x:data")) {
+ form = (DataForm) dataFormProvider.parseExtension(parser);
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (elementName.equals("si")) {
+ done = true;
+ } else if (elementName.equals("file")) {
+ long fileSize = 0;
+ if(size != null && size.trim().length() !=0){
+ try {
+ fileSize = Long.parseLong(size);
+ }
+ catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ }
+
+ Date fileDate = new Date();
+ if (date != null) {
+ try {
+ fileDate = StringUtils.parseXEP0082Date(date);
+ } catch (ParseException e) {
+ // couldn't parse date, use current date-time
+ }
+ }
+
+ File file = new File(name, fileSize);
+ file.setHash(hash);
+ file.setDate(fileDate);
+ file.setDesc(desc);
+ file.setRanged(isRanged);
+ initiation.setFile(file);
+ }
+ }
+ }
+
+ initiation.setSesssionID(id);
+ initiation.setMimeType(mimeType);
+
+ initiation.setFeatureNegotiationForm(form);
+
+ return initiation;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AccessModel.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AccessModel.java
index c1fa5461a..bd0294cf1 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AccessModel.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AccessModel.java
@@ -1,38 +1,38 @@
-/**
- * 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.pubsub;
-
-/**
- * This enumeration represents the access models for the pubsub node
- * as defined in the pubsub specification section <a href="http://xmpp.org/extensions/xep-0060.html#registrar-formtypes-config">16.4.3</a>
- *
- * @author Robin Collier
- */
-public enum AccessModel
-{
- /** Anyone may subscribe and retrieve items */
- open,
-
- /** Subscription request must be approved and only subscribers may retrieve items */
- authorize,
-
- /** Anyone with a presence subscription of both or from may subscribe and retrieve items */
- presence,
-
- /** Anyone in the specified roster group(s) may subscribe and retrieve items */
- roster,
-
- /** Only those on a whitelist may subscribe and retrieve items */
- whitelist;
-}
+/**
+ * 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.pubsub;
+
+/**
+ * This enumeration represents the access models for the pubsub node
+ * as defined in the pubsub specification section <a href="http://xmpp.org/extensions/xep-0060.html#registrar-formtypes-config">16.4.3</a>
+ *
+ * @author Robin Collier
+ */
+public enum AccessModel
+{
+ /** Anyone may subscribe and retrieve items */
+ open,
+
+ /** Subscription request must be approved and only subscribers may retrieve items */
+ authorize,
+
+ /** Anyone with a presence subscription of both or from may subscribe and retrieve items */
+ presence,
+
+ /** Anyone in the specified roster group(s) may subscribe and retrieve items */
+ roster,
+
+ /** Only those on a whitelist may subscribe and retrieve items */
+ whitelist;
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Affiliation.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Affiliation.java
index d0fc7dcf4..c2208c1fa 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Affiliation.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Affiliation.java
@@ -1,90 +1,90 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * Represents a affiliation between a user and a node, where the {@link #type} defines
- * the type of affiliation.
- *
- * Affiliations are retrieved from the {@link PubSubManager#getAffiliations()} method, which
- * gets affiliations for the calling user, based on the identity that is associated with
- * the {@link Connection}.
- *
- * @author Robin Collier
- */
-public class Affiliation implements PacketExtension
-{
- protected String node;
- protected Type type;
-
- public enum Type
- {
- member, none, outcast, owner, publisher
- }
-
- /**
- * Constructs an affiliation.
- *
- * @param nodeId The node the user is affiliated with.
- * @param affiliation The type of affiliation.
- */
- public Affiliation(String nodeId, Type affiliation)
- {
- node = nodeId;
- type = affiliation;
- }
-
- public String getNodeId()
- {
- return node;
- }
-
- public Type getType()
- {
- return type;
- }
-
- public String getElementName()
- {
- return "subscription";
- }
-
- public String getNamespace()
- {
- return null;
- }
-
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
- appendAttribute(builder, "node", node);
- appendAttribute(builder, "affiliation", type.toString());
-
- builder.append("/>");
- return builder.toString();
- }
-
- private void appendAttribute(StringBuilder builder, String att, String value)
- {
- builder.append(" ");
- builder.append(att);
- builder.append("='");
- builder.append(value);
- builder.append("'");
- }
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * Represents a affiliation between a user and a node, where the {@link #type} defines
+ * the type of affiliation.
+ *
+ * Affiliations are retrieved from the {@link PubSubManager#getAffiliations()} method, which
+ * gets affiliations for the calling user, based on the identity that is associated with
+ * the {@link Connection}.
+ *
+ * @author Robin Collier
+ */
+public class Affiliation implements PacketExtension
+{
+ protected String node;
+ protected Type type;
+
+ public enum Type
+ {
+ member, none, outcast, owner, publisher
+ }
+
+ /**
+ * Constructs an affiliation.
+ *
+ * @param nodeId The node the user is affiliated with.
+ * @param affiliation The type of affiliation.
+ */
+ public Affiliation(String nodeId, Type affiliation)
+ {
+ node = nodeId;
+ type = affiliation;
+ }
+
+ public String getNodeId()
+ {
+ return node;
+ }
+
+ public Type getType()
+ {
+ return type;
+ }
+
+ public String getElementName()
+ {
+ return "subscription";
+ }
+
+ public String getNamespace()
+ {
+ return null;
+ }
+
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+ appendAttribute(builder, "node", node);
+ appendAttribute(builder, "affiliation", type.toString());
+
+ builder.append("/>");
+ return builder.toString();
+ }
+
+ private void appendAttribute(StringBuilder builder, String att, String value)
+ {
+ builder.append(" ");
+ builder.append(att);
+ builder.append("='");
+ builder.append(value);
+ builder.append("'");
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java
index aa82dcbab..4c0cb6141 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java
@@ -1,69 +1,69 @@
-/**
- * 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.pubsub;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Represents the <b>affiliations</b> element of the reply to a request for affiliations.
- * It is defined in the specification in section <a href="http://xmpp.org/extensions/xep-0060.html#entity-affiliations">5.7 Retrieve Affiliations</a>.
- *
- * @author Robin Collier
- */
-public class AffiliationsExtension extends NodeExtension
-{
- protected List<Affiliation> items = Collections.EMPTY_LIST;
-
- public AffiliationsExtension()
- {
- super(PubSubElementType.AFFILIATIONS);
- }
-
- public AffiliationsExtension(List<Affiliation> subList)
- {
- super(PubSubElementType.AFFILIATIONS);
- items = subList;
- }
-
- public List<Affiliation> getAffiliations()
- {
- return items;
- }
-
- @Override
- public String toXML()
- {
- if ((items == null) || (items.size() == 0))
- {
- return super.toXML();
- }
- else
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
- builder.append(">");
-
- for (Affiliation item : items)
- {
- builder.append(item.toXML());
- }
-
- builder.append("</");
- builder.append(getElementName());
- builder.append(">");
- return builder.toString();
- }
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents the <b>affiliations</b> element of the reply to a request for affiliations.
+ * It is defined in the specification in section <a href="http://xmpp.org/extensions/xep-0060.html#entity-affiliations">5.7 Retrieve Affiliations</a>.
+ *
+ * @author Robin Collier
+ */
+public class AffiliationsExtension extends NodeExtension
+{
+ protected List<Affiliation> items = Collections.EMPTY_LIST;
+
+ public AffiliationsExtension()
+ {
+ super(PubSubElementType.AFFILIATIONS);
+ }
+
+ public AffiliationsExtension(List<Affiliation> subList)
+ {
+ super(PubSubElementType.AFFILIATIONS);
+ items = subList;
+ }
+
+ public List<Affiliation> getAffiliations()
+ {
+ return items;
+ }
+
+ @Override
+ public String toXML()
+ {
+ if ((items == null) || (items.size() == 0))
+ {
+ return super.toXML();
+ }
+ else
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+ builder.append(">");
+
+ for (Affiliation item : items)
+ {
+ builder.append(item.toXML());
+ }
+
+ builder.append("</");
+ builder.append(getElementName());
+ builder.append(">");
+ return builder.toString();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ChildrenAssociationPolicy.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ChildrenAssociationPolicy.java
index 933a39ece..13fabe911 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ChildrenAssociationPolicy.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ChildrenAssociationPolicy.java
@@ -1,32 +1,32 @@
-/**
- * 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.pubsub;
-
-/**
- * This enumeration represents the children association policy for associating leaf nodes
- * with collection nodes as defined in the pubsub specification section <a href="http://xmpp.org/extensions/xep-0060.html#registrar-formtypes-config">16.4.3</a>
- *
- * @author Robin Collier
- */
-public enum ChildrenAssociationPolicy
-{
- /** Anyone may associate leaf nodes with the collection */
- all,
-
- /** Only collection node owners may associate leaf nodes with the collection. */
- owners,
-
- /** Only those on a whitelist may associate leaf nodes with the collection. */
- whitelist;
-}
+/**
+ * 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.pubsub;
+
+/**
+ * This enumeration represents the children association policy for associating leaf nodes
+ * with collection nodes as defined in the pubsub specification section <a href="http://xmpp.org/extensions/xep-0060.html#registrar-formtypes-config">16.4.3</a>
+ *
+ * @author Robin Collier
+ */
+public enum ChildrenAssociationPolicy
+{
+ /** Anyone may associate leaf nodes with the collection */
+ all,
+
+ /** Only collection node owners may associate leaf nodes with the collection. */
+ owners,
+
+ /** Only those on a whitelist may associate leaf nodes with the collection. */
+ whitelist;
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/CollectionNode.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/CollectionNode.java
index dcd1cc4a4..73b916546 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/CollectionNode.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/CollectionNode.java
@@ -17,15 +17,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smackx.pubsub;
-
-import org.jivesoftware.smack.Connection;
-
-public class CollectionNode extends Node
-{
- CollectionNode(Connection connection, String nodeId)
- {
- super(connection, nodeId);
- }
-
-}
+package org.jivesoftware.smackx.pubsub;
+
+import org.jivesoftware.smack.Connection;
+
+public class CollectionNode extends Node
+{
+ CollectionNode(Connection connection, String nodeId)
+ {
+ super(connection, nodeId);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigurationEvent.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigurationEvent.java
index 67b8304a4..3f002cba7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigurationEvent.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigurationEvent.java
@@ -1,56 +1,56 @@
-/**
- * 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.pubsub;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * Represents the <b>configuration</b> element of a pubsub message event which
- * associates a configuration form to the node which was configured. The form
- * contains the current node configuration.
- *
- * @author Robin Collier
- */
-public class ConfigurationEvent extends NodeExtension implements EmbeddedPacketExtension
-{
- private ConfigureForm form;
-
- public ConfigurationEvent(String nodeId)
- {
- super(PubSubElementType.CONFIGURATION, nodeId);
- }
-
- public ConfigurationEvent(String nodeId, ConfigureForm configForm)
- {
- super(PubSubElementType.CONFIGURATION, nodeId);
- form = configForm;
- }
-
- public ConfigureForm getConfiguration()
- {
- return form;
- }
-
- public List<PacketExtension> getExtensions()
- {
- if (getConfiguration() == null)
- return Collections.EMPTY_LIST;
- else
- return Arrays.asList(((PacketExtension)getConfiguration().getDataFormToSend()));
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * Represents the <b>configuration</b> element of a pubsub message event which
+ * associates a configuration form to the node which was configured. The form
+ * contains the current node configuration.
+ *
+ * @author Robin Collier
+ */
+public class ConfigurationEvent extends NodeExtension implements EmbeddedPacketExtension
+{
+ private ConfigureForm form;
+
+ public ConfigurationEvent(String nodeId)
+ {
+ super(PubSubElementType.CONFIGURATION, nodeId);
+ }
+
+ public ConfigurationEvent(String nodeId, ConfigureForm configForm)
+ {
+ super(PubSubElementType.CONFIGURATION, nodeId);
+ form = configForm;
+ }
+
+ public ConfigureForm getConfiguration()
+ {
+ return form;
+ }
+
+ public List<PacketExtension> getExtensions()
+ {
+ if (getConfiguration() == null)
+ return Collections.EMPTY_LIST;
+ else
+ return Arrays.asList(((PacketExtension)getConfiguration().getDataFormToSend()));
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureForm.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureForm.java
index f6fe1409a..127c8494c 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureForm.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureForm.java
@@ -1,709 +1,709 @@
-/**
- * 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.pubsub;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.FormField;
-import org.jivesoftware.smackx.packet.DataForm;
-
-/**
- * A decorator for a {@link Form} to easily enable reading and updating
- * of node configuration. All operations read or update the underlying {@link DataForm}.
- *
- * <p>Unlike the {@link Form}.setAnswer(XXX)} methods, which throw an exception if the field does not
- * exist, all <b>ConfigureForm.setXXX</b> methods will create the field in the wrapped form
- * if it does not already exist.
- *
- * @author Robin Collier
- */
-public class ConfigureForm extends Form
-{
- /**
- * Create a decorator from an existing {@link DataForm} that has been
- * retrieved from parsing a node configuration request.
- *
- * @param configDataForm
- */
- public ConfigureForm(DataForm configDataForm)
- {
- super(configDataForm);
- }
-
- /**
- * Create a decorator from an existing {@link Form} for node configuration.
- * Typically, this can be used to create a decorator for an answer form
- * by using the result of {@link #createAnswerForm()} as the input parameter.
- *
- * @param nodeConfigForm
- */
- public ConfigureForm(Form nodeConfigForm)
- {
- super(nodeConfigForm.getDataFormToSend());
- }
-
- /**
- * Create a new form for configuring a node. This would typically only be used
- * when creating and configuring a node at the same time via {@link PubSubManager#createNode(String, Form)}, since
- * configuration of an existing node is typically accomplished by calling {@link LeafNode#getNodeConfiguration()} and
- * using the resulting form to create a answer form. See {@link #ConfigureForm(Form)}.
- * @param formType
- */
- public ConfigureForm(FormType formType)
- {
- super(formType.toString());
- }
-
- /**
- * Get the currently configured {@link AccessModel}, null if it is not set.
- *
- * @return The current {@link AccessModel}
- */
- public AccessModel getAccessModel()
- {
- String value = getFieldValue(ConfigureNodeFields.access_model);
-
- if (value == null)
- return null;
- else
- return AccessModel.valueOf(value);
- }
-
- /**
- * Sets the value of access model.
- *
- * @param accessModel
- */
- public void setAccessModel(AccessModel accessModel)
- {
- addField(ConfigureNodeFields.access_model, FormField.TYPE_LIST_SINGLE);
- setAnswer(ConfigureNodeFields.access_model.getFieldName(), getListSingle(accessModel.toString()));
- }
-
- /**
- * Returns the URL of an XSL transformation which can be applied to payloads in order to
- * generate an appropriate message body element.
- *
- * @return URL to an XSL
- */
- public String getBodyXSLT()
- {
- return getFieldValue(ConfigureNodeFields.body_xslt);
- }
-
- /**
- * Set the URL of an XSL transformation which can be applied to payloads in order to
- * generate an appropriate message body element.
- *
- * @param bodyXslt The URL of an XSL
- */
- public void setBodyXSLT(String bodyXslt)
- {
- addField(ConfigureNodeFields.body_xslt, FormField.TYPE_TEXT_SINGLE);
- setAnswer(ConfigureNodeFields.body_xslt.getFieldName(), bodyXslt);
- }
-
- /**
- * The id's of the child nodes associated with a collection node (both leaf and collection).
- *
- * @return Iterator over the list of child nodes.
- */
- public Iterator<String> getChildren()
- {
- return getFieldValues(ConfigureNodeFields.children);
- }
-
- /**
- * Set the list of child node ids that are associated with a collection node.
- *
- * @param children
- */
- public void setChildren(List<String> children)
- {
- addField(ConfigureNodeFields.children, FormField.TYPE_TEXT_MULTI);
- setAnswer(ConfigureNodeFields.children.getFieldName(), children);
- }
-
- /**
- * Returns the policy that determines who may associate children with the node.
- *
- * @return The current policy
- */
- public ChildrenAssociationPolicy getChildrenAssociationPolicy()
- {
- String value = getFieldValue(ConfigureNodeFields.children_association_policy);
-
- if (value == null)
- return null;
- else
- return ChildrenAssociationPolicy.valueOf(value);
- }
-
- /**
- * Sets the policy that determines who may associate children with the node.
- *
- * @param policy The policy being set
- */
- public void setChildrenAssociationPolicy(ChildrenAssociationPolicy policy)
- {
- addField(ConfigureNodeFields.children_association_policy, FormField.TYPE_LIST_SINGLE);
- List<String> values = new ArrayList<String>(1);
- values.add(policy.toString());
- setAnswer(ConfigureNodeFields.children_association_policy.getFieldName(), values);
- }
-
- /**
- * Iterator of JID's that are on the whitelist that determines who can associate child nodes
- * with the collection node. This is only relevant if {@link #getChildrenAssociationPolicy()} is set to
- * {@link ChildrenAssociationPolicy#whitelist}.
- *
- * @return Iterator over whitelist
- */
- public Iterator<String> getChildrenAssociationWhitelist()
- {
- return getFieldValues(ConfigureNodeFields.children_association_whitelist);
- }
-
- /**
- * Set the JID's in the whitelist of users that can associate child nodes with the collection
- * node. This is only relevant if {@link #getChildrenAssociationPolicy()} is set to
- * {@link ChildrenAssociationPolicy#whitelist}.
- *
- * @param whitelist The list of JID's
- */
- public void setChildrenAssociationWhitelist(List<String> whitelist)
- {
- addField(ConfigureNodeFields.children_association_whitelist, FormField.TYPE_JID_MULTI);
- setAnswer(ConfigureNodeFields.children_association_whitelist.getFieldName(), whitelist);
- }
-
- /**
- * Gets the maximum number of child nodes that can be associated with the collection node.
- *
- * @return The maximum number of child nodes
- */
- public int getChildrenMax()
- {
- return Integer.parseInt(getFieldValue(ConfigureNodeFields.children_max));
- }
-
- /**
- * Set the maximum number of child nodes that can be associated with a collection node.
- *
- * @param max The maximum number of child nodes.
- */
- public void setChildrenMax(int max)
- {
- addField(ConfigureNodeFields.children_max, FormField.TYPE_TEXT_SINGLE);
- setAnswer(ConfigureNodeFields.children_max.getFieldName(), max);
- }
-
- /**
- * Gets the collection node which the node is affiliated with.
- *
- * @return The collection node id
- */
- public String getCollection()
- {
- return getFieldValue(ConfigureNodeFields.collection);
- }
-
- /**
- * Sets the collection node which the node is affiliated with.
- *
- * @param collection The node id of the collection node
- */
- public void setCollection(String collection)
- {
- addField(ConfigureNodeFields.collection, FormField.TYPE_TEXT_SINGLE);
- setAnswer(ConfigureNodeFields.collection.getFieldName(), collection);
- }
-
- /**
- * Gets the URL of an XSL transformation which can be applied to the payload
- * format in order to generate a valid Data Forms result that the client could
- * display using a generic Data Forms rendering engine.
- *
- * @return The URL of an XSL transformation
- */
- public String getDataformXSLT()
- {
- return getFieldValue(ConfigureNodeFields.dataform_xslt);
- }
-
- /**
- * Sets the URL of an XSL transformation which can be applied to the payload
- * format in order to generate a valid Data Forms result that the client could
- * display using a generic Data Forms rendering engine.
- *
- * @param url The URL of an XSL transformation
- */
- public void setDataformXSLT(String url)
- {
- addField(ConfigureNodeFields.dataform_xslt, FormField.TYPE_TEXT_SINGLE);
- setAnswer(ConfigureNodeFields.dataform_xslt.getFieldName(), url);
- }
-
- /**
- * Does the node deliver payloads with event notifications.
- *
- * @return true if it does, false otherwise
- */
- public boolean isDeliverPayloads()
- {
- return parseBoolean(getFieldValue(ConfigureNodeFields.deliver_payloads));
- }
-
- /**
- * Sets whether the node will deliver payloads with event notifications.
- *
- * @param deliver true if the payload will be delivered, false otherwise
- */
- public void setDeliverPayloads(boolean deliver)
- {
- addField(ConfigureNodeFields.deliver_payloads, FormField.TYPE_BOOLEAN);
- setAnswer(ConfigureNodeFields.deliver_payloads.getFieldName(), deliver);
- }
-
- /**
- * Determines who should get replies to items
- *
- * @return Who should get the reply
- */
- public ItemReply getItemReply()
- {
- String value = getFieldValue(ConfigureNodeFields.itemreply);
-
- if (value == null)
- return null;
- else
- return ItemReply.valueOf(value);
- }
-
- /**
- * Sets who should get the replies to items
- *
- * @param reply Defines who should get the reply
- */
- public void setItemReply(ItemReply reply)
- {
- addField(ConfigureNodeFields.itemreply, FormField.TYPE_LIST_SINGLE);
- setAnswer(ConfigureNodeFields.itemreply.getFieldName(), getListSingle(reply.toString()));
- }
-
- /**
- * Gets the maximum number of items to persisted to this node if {@link #isPersistItems()} is
- * true.
- *
- * @return The maximum number of items to persist
- */
- public int getMaxItems()
- {
- return Integer.parseInt(getFieldValue(ConfigureNodeFields.max_items));
- }
-
- /**
- * Set the maximum number of items to persisted to this node if {@link #isPersistItems()} is
- * true.
- *
- * @param max The maximum number of items to persist
- */
- public void setMaxItems(int max)
- {
- addField(ConfigureNodeFields.max_items, FormField.TYPE_TEXT_SINGLE);
- setAnswer(ConfigureNodeFields.max_items.getFieldName(), max);
- }
-
- /**
- * Gets the maximum payload size in bytes.
- *
- * @return The maximum payload size
- */
- public int getMaxPayloadSize()
- {
- return Integer.parseInt(getFieldValue(ConfigureNodeFields.max_payload_size));
- }
-
- /**
- * Sets the maximum payload size in bytes
- *
- * @param max The maximum payload size
- */
- public void setMaxPayloadSize(int max)
- {
- addField(ConfigureNodeFields.max_payload_size, FormField.TYPE_TEXT_SINGLE);
- setAnswer(ConfigureNodeFields.max_payload_size.getFieldName(), max);
- }
-
- /**
- * Gets the node type
- *
- * @return The node type
- */
- public NodeType getNodeType()
- {
- String value = getFieldValue(ConfigureNodeFields.node_type);
-
- if (value == null)
- return null;
- else
- return NodeType.valueOf(value);
- }
-
- /**
- * Sets the node type
- *
- * @param type The node type
- */
- public void setNodeType(NodeType type)
- {
- addField(ConfigureNodeFields.node_type, FormField.TYPE_LIST_SINGLE);
- setAnswer(ConfigureNodeFields.node_type.getFieldName(), getListSingle(type.toString()));
- }
-
- /**
- * Determines if subscribers should be notified when the configuration changes.
- *
- * @return true if they should be notified, false otherwise
- */
- public boolean isNotifyConfig()
- {
- return parseBoolean(getFieldValue(ConfigureNodeFields.notify_config));
- }
-
- /**
- * Sets whether subscribers should be notified when the configuration changes.
- *
- * @param notify true if subscribers should be notified, false otherwise
- */
- public void setNotifyConfig(boolean notify)
- {
- addField(ConfigureNodeFields.notify_config, FormField.TYPE_BOOLEAN);
- setAnswer(ConfigureNodeFields.notify_config.getFieldName(), notify);
- }
-
- /**
- * Determines whether subscribers should be notified when the node is deleted.
- *
- * @return true if subscribers should be notified, false otherwise
- */
- public boolean isNotifyDelete()
- {
- return parseBoolean(getFieldValue(ConfigureNodeFields.notify_delete));
- }
-
- /**
- * Sets whether subscribers should be notified when the node is deleted.
- *
- * @param notify true if subscribers should be notified, false otherwise
- */
- public void setNotifyDelete(boolean notify)
- {
- addField(ConfigureNodeFields.notify_delete, FormField.TYPE_BOOLEAN);
- setAnswer(ConfigureNodeFields.notify_delete.getFieldName(), notify);
- }
-
- /**
- * Determines whether subscribers should be notified when items are deleted
- * from the node.
- *
- * @return true if subscribers should be notified, false otherwise
- */
- public boolean isNotifyRetract()
- {
- return parseBoolean(getFieldValue(ConfigureNodeFields.notify_retract));
- }
-
- /**
- * Sets whether subscribers should be notified when items are deleted
- * from the node.
- *
- * @param notify true if subscribers should be notified, false otherwise
- */
- public void setNotifyRetract(boolean notify)
- {
- addField(ConfigureNodeFields.notify_retract, FormField.TYPE_BOOLEAN);
- setAnswer(ConfigureNodeFields.notify_retract.getFieldName(), notify);
- }
-
- /**
- * Determines whether items should be persisted in the node.
- *
- * @return true if items are persisted
- */
- public boolean isPersistItems()
- {
- return parseBoolean(getFieldValue(ConfigureNodeFields.persist_items));
- }
-
- /**
- * Sets whether items should be persisted in the node.
- *
- * @param persist true if items should be persisted, false otherwise
- */
- public void setPersistentItems(boolean persist)
- {
- addField(ConfigureNodeFields.persist_items, FormField.TYPE_BOOLEAN);
- setAnswer(ConfigureNodeFields.persist_items.getFieldName(), persist);
- }
-
- /**
- * Determines whether to deliver notifications to available users only.
- *
- * @return true if users must be available
- */
- public boolean isPresenceBasedDelivery()
- {
- return parseBoolean(getFieldValue(ConfigureNodeFields.presence_based_delivery));
- }
-
- /**
- * Sets whether to deliver notifications to available users only.
- *
- * @param presenceBased true if user must be available, false otherwise
- */
- public void setPresenceBasedDelivery(boolean presenceBased)
- {
- addField(ConfigureNodeFields.presence_based_delivery, FormField.TYPE_BOOLEAN);
- setAnswer(ConfigureNodeFields.presence_based_delivery.getFieldName(), presenceBased);
- }
-
- /**
- * Gets the publishing model for the node, which determines who may publish to it.
- *
- * @return The publishing model
- */
- public PublishModel getPublishModel()
- {
- String value = getFieldValue(ConfigureNodeFields.publish_model);
-
- if (value == null)
- return null;
- else
- return PublishModel.valueOf(value);
- }
-
- /**
- * Sets the publishing model for the node, which determines who may publish to it.
- *
- * @param publish The enum representing the possible options for the publishing model
- */
- public void setPublishModel(PublishModel publish)
- {
- addField(ConfigureNodeFields.publish_model, FormField.TYPE_LIST_SINGLE);
- setAnswer(ConfigureNodeFields.publish_model.getFieldName(), getListSingle(publish.toString()));
- }
-
- /**
- * Iterator over the multi user chat rooms that are specified as reply rooms.
- *
- * @return The reply room JID's
- */
- public Iterator<String> getReplyRoom()
- {
- return getFieldValues(ConfigureNodeFields.replyroom);
- }
-
- /**
- * Sets the multi user chat rooms that are specified as reply rooms.
- *
- * @param replyRooms The multi user chat room to use as reply rooms
- */
- public void setReplyRoom(List<String> replyRooms)
- {
- addField(ConfigureNodeFields.replyroom, FormField.TYPE_LIST_MULTI);
- setAnswer(ConfigureNodeFields.replyroom.getFieldName(), replyRooms);
- }
-
- /**
- * Gets the specific JID's for reply to.
- *
- * @return The JID's
- */
- public Iterator<String> getReplyTo()
- {
- return getFieldValues(ConfigureNodeFields.replyto);
- }
-
- /**
- * Sets the specific JID's for reply to.
- *
- * @param replyTos The JID's to reply to
- */
- public void setReplyTo(List<String> replyTos)
- {
- addField(ConfigureNodeFields.replyto, FormField.TYPE_LIST_MULTI);
- setAnswer(ConfigureNodeFields.replyto.getFieldName(), replyTos);
- }
-
- /**
- * Gets the roster groups that are allowed to subscribe and retrieve items.
- *
- * @return The roster groups
- */
- public Iterator<String> getRosterGroupsAllowed()
- {
- return getFieldValues(ConfigureNodeFields.roster_groups_allowed);
- }
-
- /**
- * Sets the roster groups that are allowed to subscribe and retrieve items.
- *
- * @param groups The roster groups
- */
- public void setRosterGroupsAllowed(List<String> groups)
- {
- addField(ConfigureNodeFields.roster_groups_allowed, FormField.TYPE_LIST_MULTI);
- setAnswer(ConfigureNodeFields.roster_groups_allowed.getFieldName(), groups);
- }
-
- /**
- * Determines if subscriptions are allowed.
- *
- * @return true if subscriptions are allowed, false otherwise
- */
- public boolean isSubscibe()
- {
- return parseBoolean(getFieldValue(ConfigureNodeFields.subscribe));
- }
-
- /**
- * Sets whether subscriptions are allowed.
- *
- * @param subscribe true if they are, false otherwise
- */
- public void setSubscribe(boolean subscribe)
- {
- addField(ConfigureNodeFields.subscribe, FormField.TYPE_BOOLEAN);
- setAnswer(ConfigureNodeFields.subscribe.getFieldName(), subscribe);
- }
-
- /**
- * Gets the human readable node title.
- *
- * @return The node title
- */
- public String getTitle()
- {
- return getFieldValue(ConfigureNodeFields.title);
- }
-
- /**
- * Sets a human readable title for the node.
- *
- * @param title The node title
- */
- public void setTitle(String title)
- {
- addField(ConfigureNodeFields.title, FormField.TYPE_TEXT_SINGLE);
- setAnswer(ConfigureNodeFields.title.getFieldName(), title);
- }
-
- /**
- * The type of node data, usually specified by the namespace of the payload (if any).
- *
- * @return The type of node data
- */
- public String getDataType()
- {
- return getFieldValue(ConfigureNodeFields.type);
- }
-
- /**
- * Sets the type of node data, usually specified by the namespace of the payload (if any).
- *
- * @param type The type of node data
- */
- public void setDataType(String type)
- {
- addField(ConfigureNodeFields.type, FormField.TYPE_TEXT_SINGLE);
- setAnswer(ConfigureNodeFields.type.getFieldName(), type);
- }
-
- @Override
- public String toString()
- {
- StringBuilder result = new StringBuilder(getClass().getName() + " Content [");
-
- Iterator<FormField> fields = getFields();
-
- while (fields.hasNext())
- {
- FormField formField = fields.next();
- result.append('(');
- result.append(formField.getVariable());
- result.append(':');
-
- Iterator<String> values = formField.getValues();
- StringBuilder valuesBuilder = new StringBuilder();
-
- while (values.hasNext())
- {
- if (valuesBuilder.length() > 0)
- result.append(',');
- String value = (String)values.next();
- valuesBuilder.append(value);
- }
-
- if (valuesBuilder.length() == 0)
- valuesBuilder.append("NOT SET");
- result.append(valuesBuilder);
- result.append(')');
- }
- result.append(']');
- return result.toString();
- }
-
- static private boolean parseBoolean(String fieldValue)
- {
- return ("1".equals(fieldValue) || "true".equals(fieldValue));
- }
-
- private String getFieldValue(ConfigureNodeFields field)
- {
- FormField formField = getField(field.getFieldName());
-
- return (formField.getValues().hasNext()) ? formField.getValues().next() : null;
- }
-
- private Iterator<String> getFieldValues(ConfigureNodeFields field)
- {
- FormField formField = getField(field.getFieldName());
-
- return formField.getValues();
- }
-
- private void addField(ConfigureNodeFields nodeField, String type)
- {
- String fieldName = nodeField.getFieldName();
-
- if (getField(fieldName) == null)
- {
- FormField field = new FormField(fieldName);
- field.setType(type);
- addField(field);
- }
- }
-
- private List<String> getListSingle(String value)
- {
- List<String> list = new ArrayList<String>(1);
- list.add(value);
- return list;
- }
-
-}
+/**
+ * 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.pubsub;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.FormField;
+import org.jivesoftware.smackx.packet.DataForm;
+
+/**
+ * A decorator for a {@link Form} to easily enable reading and updating
+ * of node configuration. All operations read or update the underlying {@link DataForm}.
+ *
+ * <p>Unlike the {@link Form}.setAnswer(XXX)} methods, which throw an exception if the field does not
+ * exist, all <b>ConfigureForm.setXXX</b> methods will create the field in the wrapped form
+ * if it does not already exist.
+ *
+ * @author Robin Collier
+ */
+public class ConfigureForm extends Form
+{
+ /**
+ * Create a decorator from an existing {@link DataForm} that has been
+ * retrieved from parsing a node configuration request.
+ *
+ * @param configDataForm
+ */
+ public ConfigureForm(DataForm configDataForm)
+ {
+ super(configDataForm);
+ }
+
+ /**
+ * Create a decorator from an existing {@link Form} for node configuration.
+ * Typically, this can be used to create a decorator for an answer form
+ * by using the result of {@link #createAnswerForm()} as the input parameter.
+ *
+ * @param nodeConfigForm
+ */
+ public ConfigureForm(Form nodeConfigForm)
+ {
+ super(nodeConfigForm.getDataFormToSend());
+ }
+
+ /**
+ * Create a new form for configuring a node. This would typically only be used
+ * when creating and configuring a node at the same time via {@link PubSubManager#createNode(String, Form)}, since
+ * configuration of an existing node is typically accomplished by calling {@link LeafNode#getNodeConfiguration()} and
+ * using the resulting form to create a answer form. See {@link #ConfigureForm(Form)}.
+ * @param formType
+ */
+ public ConfigureForm(FormType formType)
+ {
+ super(formType.toString());
+ }
+
+ /**
+ * Get the currently configured {@link AccessModel}, null if it is not set.
+ *
+ * @return The current {@link AccessModel}
+ */
+ public AccessModel getAccessModel()
+ {
+ String value = getFieldValue(ConfigureNodeFields.access_model);
+
+ if (value == null)
+ return null;
+ else
+ return AccessModel.valueOf(value);
+ }
+
+ /**
+ * Sets the value of access model.
+ *
+ * @param accessModel
+ */
+ public void setAccessModel(AccessModel accessModel)
+ {
+ addField(ConfigureNodeFields.access_model, FormField.TYPE_LIST_SINGLE);
+ setAnswer(ConfigureNodeFields.access_model.getFieldName(), getListSingle(accessModel.toString()));
+ }
+
+ /**
+ * Returns the URL of an XSL transformation which can be applied to payloads in order to
+ * generate an appropriate message body element.
+ *
+ * @return URL to an XSL
+ */
+ public String getBodyXSLT()
+ {
+ return getFieldValue(ConfigureNodeFields.body_xslt);
+ }
+
+ /**
+ * Set the URL of an XSL transformation which can be applied to payloads in order to
+ * generate an appropriate message body element.
+ *
+ * @param bodyXslt The URL of an XSL
+ */
+ public void setBodyXSLT(String bodyXslt)
+ {
+ addField(ConfigureNodeFields.body_xslt, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(ConfigureNodeFields.body_xslt.getFieldName(), bodyXslt);
+ }
+
+ /**
+ * The id's of the child nodes associated with a collection node (both leaf and collection).
+ *
+ * @return Iterator over the list of child nodes.
+ */
+ public Iterator<String> getChildren()
+ {
+ return getFieldValues(ConfigureNodeFields.children);
+ }
+
+ /**
+ * Set the list of child node ids that are associated with a collection node.
+ *
+ * @param children
+ */
+ public void setChildren(List<String> children)
+ {
+ addField(ConfigureNodeFields.children, FormField.TYPE_TEXT_MULTI);
+ setAnswer(ConfigureNodeFields.children.getFieldName(), children);
+ }
+
+ /**
+ * Returns the policy that determines who may associate children with the node.
+ *
+ * @return The current policy
+ */
+ public ChildrenAssociationPolicy getChildrenAssociationPolicy()
+ {
+ String value = getFieldValue(ConfigureNodeFields.children_association_policy);
+
+ if (value == null)
+ return null;
+ else
+ return ChildrenAssociationPolicy.valueOf(value);
+ }
+
+ /**
+ * Sets the policy that determines who may associate children with the node.
+ *
+ * @param policy The policy being set
+ */
+ public void setChildrenAssociationPolicy(ChildrenAssociationPolicy policy)
+ {
+ addField(ConfigureNodeFields.children_association_policy, FormField.TYPE_LIST_SINGLE);
+ List<String> values = new ArrayList<String>(1);
+ values.add(policy.toString());
+ setAnswer(ConfigureNodeFields.children_association_policy.getFieldName(), values);
+ }
+
+ /**
+ * Iterator of JID's that are on the whitelist that determines who can associate child nodes
+ * with the collection node. This is only relevant if {@link #getChildrenAssociationPolicy()} is set to
+ * {@link ChildrenAssociationPolicy#whitelist}.
+ *
+ * @return Iterator over whitelist
+ */
+ public Iterator<String> getChildrenAssociationWhitelist()
+ {
+ return getFieldValues(ConfigureNodeFields.children_association_whitelist);
+ }
+
+ /**
+ * Set the JID's in the whitelist of users that can associate child nodes with the collection
+ * node. This is only relevant if {@link #getChildrenAssociationPolicy()} is set to
+ * {@link ChildrenAssociationPolicy#whitelist}.
+ *
+ * @param whitelist The list of JID's
+ */
+ public void setChildrenAssociationWhitelist(List<String> whitelist)
+ {
+ addField(ConfigureNodeFields.children_association_whitelist, FormField.TYPE_JID_MULTI);
+ setAnswer(ConfigureNodeFields.children_association_whitelist.getFieldName(), whitelist);
+ }
+
+ /**
+ * Gets the maximum number of child nodes that can be associated with the collection node.
+ *
+ * @return The maximum number of child nodes
+ */
+ public int getChildrenMax()
+ {
+ return Integer.parseInt(getFieldValue(ConfigureNodeFields.children_max));
+ }
+
+ /**
+ * Set the maximum number of child nodes that can be associated with a collection node.
+ *
+ * @param max The maximum number of child nodes.
+ */
+ public void setChildrenMax(int max)
+ {
+ addField(ConfigureNodeFields.children_max, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(ConfigureNodeFields.children_max.getFieldName(), max);
+ }
+
+ /**
+ * Gets the collection node which the node is affiliated with.
+ *
+ * @return The collection node id
+ */
+ public String getCollection()
+ {
+ return getFieldValue(ConfigureNodeFields.collection);
+ }
+
+ /**
+ * Sets the collection node which the node is affiliated with.
+ *
+ * @param collection The node id of the collection node
+ */
+ public void setCollection(String collection)
+ {
+ addField(ConfigureNodeFields.collection, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(ConfigureNodeFields.collection.getFieldName(), collection);
+ }
+
+ /**
+ * Gets the URL of an XSL transformation which can be applied to the payload
+ * format in order to generate a valid Data Forms result that the client could
+ * display using a generic Data Forms rendering engine.
+ *
+ * @return The URL of an XSL transformation
+ */
+ public String getDataformXSLT()
+ {
+ return getFieldValue(ConfigureNodeFields.dataform_xslt);
+ }
+
+ /**
+ * Sets the URL of an XSL transformation which can be applied to the payload
+ * format in order to generate a valid Data Forms result that the client could
+ * display using a generic Data Forms rendering engine.
+ *
+ * @param url The URL of an XSL transformation
+ */
+ public void setDataformXSLT(String url)
+ {
+ addField(ConfigureNodeFields.dataform_xslt, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(ConfigureNodeFields.dataform_xslt.getFieldName(), url);
+ }
+
+ /**
+ * Does the node deliver payloads with event notifications.
+ *
+ * @return true if it does, false otherwise
+ */
+ public boolean isDeliverPayloads()
+ {
+ return parseBoolean(getFieldValue(ConfigureNodeFields.deliver_payloads));
+ }
+
+ /**
+ * Sets whether the node will deliver payloads with event notifications.
+ *
+ * @param deliver true if the payload will be delivered, false otherwise
+ */
+ public void setDeliverPayloads(boolean deliver)
+ {
+ addField(ConfigureNodeFields.deliver_payloads, FormField.TYPE_BOOLEAN);
+ setAnswer(ConfigureNodeFields.deliver_payloads.getFieldName(), deliver);
+ }
+
+ /**
+ * Determines who should get replies to items
+ *
+ * @return Who should get the reply
+ */
+ public ItemReply getItemReply()
+ {
+ String value = getFieldValue(ConfigureNodeFields.itemreply);
+
+ if (value == null)
+ return null;
+ else
+ return ItemReply.valueOf(value);
+ }
+
+ /**
+ * Sets who should get the replies to items
+ *
+ * @param reply Defines who should get the reply
+ */
+ public void setItemReply(ItemReply reply)
+ {
+ addField(ConfigureNodeFields.itemreply, FormField.TYPE_LIST_SINGLE);
+ setAnswer(ConfigureNodeFields.itemreply.getFieldName(), getListSingle(reply.toString()));
+ }
+
+ /**
+ * Gets the maximum number of items to persisted to this node if {@link #isPersistItems()} is
+ * true.
+ *
+ * @return The maximum number of items to persist
+ */
+ public int getMaxItems()
+ {
+ return Integer.parseInt(getFieldValue(ConfigureNodeFields.max_items));
+ }
+
+ /**
+ * Set the maximum number of items to persisted to this node if {@link #isPersistItems()} is
+ * true.
+ *
+ * @param max The maximum number of items to persist
+ */
+ public void setMaxItems(int max)
+ {
+ addField(ConfigureNodeFields.max_items, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(ConfigureNodeFields.max_items.getFieldName(), max);
+ }
+
+ /**
+ * Gets the maximum payload size in bytes.
+ *
+ * @return The maximum payload size
+ */
+ public int getMaxPayloadSize()
+ {
+ return Integer.parseInt(getFieldValue(ConfigureNodeFields.max_payload_size));
+ }
+
+ /**
+ * Sets the maximum payload size in bytes
+ *
+ * @param max The maximum payload size
+ */
+ public void setMaxPayloadSize(int max)
+ {
+ addField(ConfigureNodeFields.max_payload_size, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(ConfigureNodeFields.max_payload_size.getFieldName(), max);
+ }
+
+ /**
+ * Gets the node type
+ *
+ * @return The node type
+ */
+ public NodeType getNodeType()
+ {
+ String value = getFieldValue(ConfigureNodeFields.node_type);
+
+ if (value == null)
+ return null;
+ else
+ return NodeType.valueOf(value);
+ }
+
+ /**
+ * Sets the node type
+ *
+ * @param type The node type
+ */
+ public void setNodeType(NodeType type)
+ {
+ addField(ConfigureNodeFields.node_type, FormField.TYPE_LIST_SINGLE);
+ setAnswer(ConfigureNodeFields.node_type.getFieldName(), getListSingle(type.toString()));
+ }
+
+ /**
+ * Determines if subscribers should be notified when the configuration changes.
+ *
+ * @return true if they should be notified, false otherwise
+ */
+ public boolean isNotifyConfig()
+ {
+ return parseBoolean(getFieldValue(ConfigureNodeFields.notify_config));
+ }
+
+ /**
+ * Sets whether subscribers should be notified when the configuration changes.
+ *
+ * @param notify true if subscribers should be notified, false otherwise
+ */
+ public void setNotifyConfig(boolean notify)
+ {
+ addField(ConfigureNodeFields.notify_config, FormField.TYPE_BOOLEAN);
+ setAnswer(ConfigureNodeFields.notify_config.getFieldName(), notify);
+ }
+
+ /**
+ * Determines whether subscribers should be notified when the node is deleted.
+ *
+ * @return true if subscribers should be notified, false otherwise
+ */
+ public boolean isNotifyDelete()
+ {
+ return parseBoolean(getFieldValue(ConfigureNodeFields.notify_delete));
+ }
+
+ /**
+ * Sets whether subscribers should be notified when the node is deleted.
+ *
+ * @param notify true if subscribers should be notified, false otherwise
+ */
+ public void setNotifyDelete(boolean notify)
+ {
+ addField(ConfigureNodeFields.notify_delete, FormField.TYPE_BOOLEAN);
+ setAnswer(ConfigureNodeFields.notify_delete.getFieldName(), notify);
+ }
+
+ /**
+ * Determines whether subscribers should be notified when items are deleted
+ * from the node.
+ *
+ * @return true if subscribers should be notified, false otherwise
+ */
+ public boolean isNotifyRetract()
+ {
+ return parseBoolean(getFieldValue(ConfigureNodeFields.notify_retract));
+ }
+
+ /**
+ * Sets whether subscribers should be notified when items are deleted
+ * from the node.
+ *
+ * @param notify true if subscribers should be notified, false otherwise
+ */
+ public void setNotifyRetract(boolean notify)
+ {
+ addField(ConfigureNodeFields.notify_retract, FormField.TYPE_BOOLEAN);
+ setAnswer(ConfigureNodeFields.notify_retract.getFieldName(), notify);
+ }
+
+ /**
+ * Determines whether items should be persisted in the node.
+ *
+ * @return true if items are persisted
+ */
+ public boolean isPersistItems()
+ {
+ return parseBoolean(getFieldValue(ConfigureNodeFields.persist_items));
+ }
+
+ /**
+ * Sets whether items should be persisted in the node.
+ *
+ * @param persist true if items should be persisted, false otherwise
+ */
+ public void setPersistentItems(boolean persist)
+ {
+ addField(ConfigureNodeFields.persist_items, FormField.TYPE_BOOLEAN);
+ setAnswer(ConfigureNodeFields.persist_items.getFieldName(), persist);
+ }
+
+ /**
+ * Determines whether to deliver notifications to available users only.
+ *
+ * @return true if users must be available
+ */
+ public boolean isPresenceBasedDelivery()
+ {
+ return parseBoolean(getFieldValue(ConfigureNodeFields.presence_based_delivery));
+ }
+
+ /**
+ * Sets whether to deliver notifications to available users only.
+ *
+ * @param presenceBased true if user must be available, false otherwise
+ */
+ public void setPresenceBasedDelivery(boolean presenceBased)
+ {
+ addField(ConfigureNodeFields.presence_based_delivery, FormField.TYPE_BOOLEAN);
+ setAnswer(ConfigureNodeFields.presence_based_delivery.getFieldName(), presenceBased);
+ }
+
+ /**
+ * Gets the publishing model for the node, which determines who may publish to it.
+ *
+ * @return The publishing model
+ */
+ public PublishModel getPublishModel()
+ {
+ String value = getFieldValue(ConfigureNodeFields.publish_model);
+
+ if (value == null)
+ return null;
+ else
+ return PublishModel.valueOf(value);
+ }
+
+ /**
+ * Sets the publishing model for the node, which determines who may publish to it.
+ *
+ * @param publish The enum representing the possible options for the publishing model
+ */
+ public void setPublishModel(PublishModel publish)
+ {
+ addField(ConfigureNodeFields.publish_model, FormField.TYPE_LIST_SINGLE);
+ setAnswer(ConfigureNodeFields.publish_model.getFieldName(), getListSingle(publish.toString()));
+ }
+
+ /**
+ * Iterator over the multi user chat rooms that are specified as reply rooms.
+ *
+ * @return The reply room JID's
+ */
+ public Iterator<String> getReplyRoom()
+ {
+ return getFieldValues(ConfigureNodeFields.replyroom);
+ }
+
+ /**
+ * Sets the multi user chat rooms that are specified as reply rooms.
+ *
+ * @param replyRooms The multi user chat room to use as reply rooms
+ */
+ public void setReplyRoom(List<String> replyRooms)
+ {
+ addField(ConfigureNodeFields.replyroom, FormField.TYPE_LIST_MULTI);
+ setAnswer(ConfigureNodeFields.replyroom.getFieldName(), replyRooms);
+ }
+
+ /**
+ * Gets the specific JID's for reply to.
+ *
+ * @return The JID's
+ */
+ public Iterator<String> getReplyTo()
+ {
+ return getFieldValues(ConfigureNodeFields.replyto);
+ }
+
+ /**
+ * Sets the specific JID's for reply to.
+ *
+ * @param replyTos The JID's to reply to
+ */
+ public void setReplyTo(List<String> replyTos)
+ {
+ addField(ConfigureNodeFields.replyto, FormField.TYPE_LIST_MULTI);
+ setAnswer(ConfigureNodeFields.replyto.getFieldName(), replyTos);
+ }
+
+ /**
+ * Gets the roster groups that are allowed to subscribe and retrieve items.
+ *
+ * @return The roster groups
+ */
+ public Iterator<String> getRosterGroupsAllowed()
+ {
+ return getFieldValues(ConfigureNodeFields.roster_groups_allowed);
+ }
+
+ /**
+ * Sets the roster groups that are allowed to subscribe and retrieve items.
+ *
+ * @param groups The roster groups
+ */
+ public void setRosterGroupsAllowed(List<String> groups)
+ {
+ addField(ConfigureNodeFields.roster_groups_allowed, FormField.TYPE_LIST_MULTI);
+ setAnswer(ConfigureNodeFields.roster_groups_allowed.getFieldName(), groups);
+ }
+
+ /**
+ * Determines if subscriptions are allowed.
+ *
+ * @return true if subscriptions are allowed, false otherwise
+ */
+ public boolean isSubscibe()
+ {
+ return parseBoolean(getFieldValue(ConfigureNodeFields.subscribe));
+ }
+
+ /**
+ * Sets whether subscriptions are allowed.
+ *
+ * @param subscribe true if they are, false otherwise
+ */
+ public void setSubscribe(boolean subscribe)
+ {
+ addField(ConfigureNodeFields.subscribe, FormField.TYPE_BOOLEAN);
+ setAnswer(ConfigureNodeFields.subscribe.getFieldName(), subscribe);
+ }
+
+ /**
+ * Gets the human readable node title.
+ *
+ * @return The node title
+ */
+ public String getTitle()
+ {
+ return getFieldValue(ConfigureNodeFields.title);
+ }
+
+ /**
+ * Sets a human readable title for the node.
+ *
+ * @param title The node title
+ */
+ public void setTitle(String title)
+ {
+ addField(ConfigureNodeFields.title, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(ConfigureNodeFields.title.getFieldName(), title);
+ }
+
+ /**
+ * The type of node data, usually specified by the namespace of the payload (if any).
+ *
+ * @return The type of node data
+ */
+ public String getDataType()
+ {
+ return getFieldValue(ConfigureNodeFields.type);
+ }
+
+ /**
+ * Sets the type of node data, usually specified by the namespace of the payload (if any).
+ *
+ * @param type The type of node data
+ */
+ public void setDataType(String type)
+ {
+ addField(ConfigureNodeFields.type, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(ConfigureNodeFields.type.getFieldName(), type);
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder result = new StringBuilder(getClass().getName() + " Content [");
+
+ Iterator<FormField> fields = getFields();
+
+ while (fields.hasNext())
+ {
+ FormField formField = fields.next();
+ result.append('(');
+ result.append(formField.getVariable());
+ result.append(':');
+
+ Iterator<String> values = formField.getValues();
+ StringBuilder valuesBuilder = new StringBuilder();
+
+ while (values.hasNext())
+ {
+ if (valuesBuilder.length() > 0)
+ result.append(',');
+ String value = (String)values.next();
+ valuesBuilder.append(value);
+ }
+
+ if (valuesBuilder.length() == 0)
+ valuesBuilder.append("NOT SET");
+ result.append(valuesBuilder);
+ result.append(')');
+ }
+ result.append(']');
+ return result.toString();
+ }
+
+ static private boolean parseBoolean(String fieldValue)
+ {
+ return ("1".equals(fieldValue) || "true".equals(fieldValue));
+ }
+
+ private String getFieldValue(ConfigureNodeFields field)
+ {
+ FormField formField = getField(field.getFieldName());
+
+ return (formField.getValues().hasNext()) ? formField.getValues().next() : null;
+ }
+
+ private Iterator<String> getFieldValues(ConfigureNodeFields field)
+ {
+ FormField formField = getField(field.getFieldName());
+
+ return formField.getValues();
+ }
+
+ private void addField(ConfigureNodeFields nodeField, String type)
+ {
+ String fieldName = nodeField.getFieldName();
+
+ if (getField(fieldName) == null)
+ {
+ FormField field = new FormField(fieldName);
+ field.setType(type);
+ addField(field);
+ }
+ }
+
+ private List<String> getListSingle(String value)
+ {
+ List<String> list = new ArrayList<String>(1);
+ list.add(value);
+ return list;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureNodeFields.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureNodeFields.java
index 39124831d..5b9f66213 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureNodeFields.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ConfigureNodeFields.java
@@ -1,218 +1,218 @@
-/**
- * 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.pubsub;
-
-import java.net.URL;
-
-import org.jivesoftware.smackx.Form;
-
-/**
- * This enumeration represents all the fields of a node configuration form. This enumeration
- * is not required when using the {@link ConfigureForm} to configure nodes, but may be helpful
- * for generic UI's using only a {@link Form} for configuration.
- *
- * @author Robin Collier
- */
-public enum ConfigureNodeFields
-{
- /**
- * Determines who may subscribe and retrieve items
- *
- * <p><b>Value: {@link AccessModel}</b></p>
- */
- access_model,
-
- /**
- * The URL of an XSL transformation which can be applied to
- * payloads in order to generate an appropriate message
- * body element
- *
- * <p><b>Value: {@link URL}</b></p>
- */
- body_xslt,
-
- /**
- * The collection with which a node is affiliated
- *
- * <p><b>Value: String</b></p>
- */
- collection,
-
- /**
- * The URL of an XSL transformation which can be applied to
- * payload format in order to generate a valid Data Forms result
- * that the client could display using a generic Data Forms
- * rendering engine body element.
- *
- * <p><b>Value: {@link URL}</b></p>
- */
- dataform_xslt,
-
- /**
- * Whether to deliver payloads with event notifications
- *
- * <p><b>Value: boolean</b></p>
- */
- deliver_payloads,
-
- /**
- * Whether owners or publisher should receive replies to items
- *
- * <p><b>Value: {@link ItemReply}</b></p>
- */
- itemreply,
-
- /**
- * Who may associate leaf nodes with a collection
- *
- * <p><b>Value: {@link ChildrenAssociationPolicy}</b></p>
- */
- children_association_policy,
-
- /**
- * The list of JIDs that may associate leaf nodes with a
- * collection
- *
- * <p><b>Value: List of JIDs as Strings</b></p>
- */
- children_association_whitelist,
-
- /**
- * The child nodes (leaf or collection) associated with a collection
- *
- * <p><b>Value: List of Strings</b></p>
- */
- children,
-
- /**
- * The maximum number of child nodes that can be associated with a
- * collection
- *
- * <p><b>Value: int</b></p>
- */
- children_max,
-
- /**
- * The maximum number of items to persist
- *
- * <p><b>Value: int</b></p>
- */
- max_items,
-
- /**
- * The maximum payload size in bytes
- *
- * <p><b>Value: int</b></p>
- */
- max_payload_size,
-
- /**
- * Whether the node is a leaf (default) or collection
- *
- * <p><b>Value: {@link NodeType}</b></p>
- */
- node_type,
-
- /**
- * Whether to notify subscribers when the node configuration changes
- *
- * <p><b>Value: boolean</b></p>
- */
- notify_config,
-
- /**
- * Whether to notify subscribers when the node is deleted
- *
- * <p><b>Value: boolean</b></p>
- */
- notify_delete,
-
- /**
- * Whether to notify subscribers when items are removed from the node
- *
- * <p><b>Value: boolean</b></p>
- */
- notify_retract,
-
- /**
- * Whether to persist items to storage. This is required to have multiple
- * items in the node.
- *
- * <p><b>Value: boolean</b></p>
- */
- persist_items,
-
- /**
- * Whether to deliver notifications to available users only
- *
- * <p><b>Value: boolean</b></p>
- */
- presence_based_delivery,
-
- /**
- * Defines who can publish to the node
- *
- * <p><b>Value: {@link PublishModel}</b></p>
- */
- publish_model,
-
- /**
- * The specific multi-user chat rooms to specify for replyroom
- *
- * <p><b>Value: List of JIDs as Strings</b></p>
- */
- replyroom,
-
- /**
- * The specific JID(s) to specify for replyto
- *
- * <p><b>Value: List of JIDs as Strings</b></p>
- */
- replyto,
-
- /**
- * The roster group(s) allowed to subscribe and retrieve items
- *
- * <p><b>Value: List of strings</b></p>
- */
- roster_groups_allowed,
-
- /**
- * Whether to allow subscriptions
- *
- * <p><b>Value: boolean</b></p>
- */
- subscribe,
-
- /**
- * A friendly name for the node
- *
- * <p><b>Value: String</b></p>
- */
- title,
-
- /**
- * The type of node data, ussually specified by the namespace
- * of the payload(if any);MAY be a list-single rather than a
- * text single
- *
- * <p><b>Value: String</b></p>
- */
- type;
-
- public String getFieldName()
- {
- return "pubsub#" + toString();
- }
-}
+/**
+ * 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.pubsub;
+
+import java.net.URL;
+
+import org.jivesoftware.smackx.Form;
+
+/**
+ * This enumeration represents all the fields of a node configuration form. This enumeration
+ * is not required when using the {@link ConfigureForm} to configure nodes, but may be helpful
+ * for generic UI's using only a {@link Form} for configuration.
+ *
+ * @author Robin Collier
+ */
+public enum ConfigureNodeFields
+{
+ /**
+ * Determines who may subscribe and retrieve items
+ *
+ * <p><b>Value: {@link AccessModel}</b></p>
+ */
+ access_model,
+
+ /**
+ * The URL of an XSL transformation which can be applied to
+ * payloads in order to generate an appropriate message
+ * body element
+ *
+ * <p><b>Value: {@link URL}</b></p>
+ */
+ body_xslt,
+
+ /**
+ * The collection with which a node is affiliated
+ *
+ * <p><b>Value: String</b></p>
+ */
+ collection,
+
+ /**
+ * The URL of an XSL transformation which can be applied to
+ * payload format in order to generate a valid Data Forms result
+ * that the client could display using a generic Data Forms
+ * rendering engine body element.
+ *
+ * <p><b>Value: {@link URL}</b></p>
+ */
+ dataform_xslt,
+
+ /**
+ * Whether to deliver payloads with event notifications
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ deliver_payloads,
+
+ /**
+ * Whether owners or publisher should receive replies to items
+ *
+ * <p><b>Value: {@link ItemReply}</b></p>
+ */
+ itemreply,
+
+ /**
+ * Who may associate leaf nodes with a collection
+ *
+ * <p><b>Value: {@link ChildrenAssociationPolicy}</b></p>
+ */
+ children_association_policy,
+
+ /**
+ * The list of JIDs that may associate leaf nodes with a
+ * collection
+ *
+ * <p><b>Value: List of JIDs as Strings</b></p>
+ */
+ children_association_whitelist,
+
+ /**
+ * The child nodes (leaf or collection) associated with a collection
+ *
+ * <p><b>Value: List of Strings</b></p>
+ */
+ children,
+
+ /**
+ * The maximum number of child nodes that can be associated with a
+ * collection
+ *
+ * <p><b>Value: int</b></p>
+ */
+ children_max,
+
+ /**
+ * The maximum number of items to persist
+ *
+ * <p><b>Value: int</b></p>
+ */
+ max_items,
+
+ /**
+ * The maximum payload size in bytes
+ *
+ * <p><b>Value: int</b></p>
+ */
+ max_payload_size,
+
+ /**
+ * Whether the node is a leaf (default) or collection
+ *
+ * <p><b>Value: {@link NodeType}</b></p>
+ */
+ node_type,
+
+ /**
+ * Whether to notify subscribers when the node configuration changes
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ notify_config,
+
+ /**
+ * Whether to notify subscribers when the node is deleted
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ notify_delete,
+
+ /**
+ * Whether to notify subscribers when items are removed from the node
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ notify_retract,
+
+ /**
+ * Whether to persist items to storage. This is required to have multiple
+ * items in the node.
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ persist_items,
+
+ /**
+ * Whether to deliver notifications to available users only
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ presence_based_delivery,
+
+ /**
+ * Defines who can publish to the node
+ *
+ * <p><b>Value: {@link PublishModel}</b></p>
+ */
+ publish_model,
+
+ /**
+ * The specific multi-user chat rooms to specify for replyroom
+ *
+ * <p><b>Value: List of JIDs as Strings</b></p>
+ */
+ replyroom,
+
+ /**
+ * The specific JID(s) to specify for replyto
+ *
+ * <p><b>Value: List of JIDs as Strings</b></p>
+ */
+ replyto,
+
+ /**
+ * The roster group(s) allowed to subscribe and retrieve items
+ *
+ * <p><b>Value: List of strings</b></p>
+ */
+ roster_groups_allowed,
+
+ /**
+ * Whether to allow subscriptions
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ subscribe,
+
+ /**
+ * A friendly name for the node
+ *
+ * <p><b>Value: String</b></p>
+ */
+ title,
+
+ /**
+ * The type of node data, ussually specified by the namespace
+ * of the payload(if any);MAY be a list-single rather than a
+ * text single
+ *
+ * <p><b>Value: String</b></p>
+ */
+ type;
+
+ public String getFieldName()
+ {
+ return "pubsub#" + toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EmbeddedPacketExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EmbeddedPacketExtension.java
index b17a66a9d..a3b71e5a5 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EmbeddedPacketExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EmbeddedPacketExtension.java
@@ -1,45 +1,45 @@
-/**
- * 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.pubsub;
-
-import java.util.List;
-
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.util.PacketParserUtils;
-
-/**
- * This interface defines {@link PacketExtension} implementations that contain other
- * extensions. This effectively extends the idea of an extension within one of the
- * top level {@link Packet} types to consider any embedded element to be an extension
- * of its parent. This more easily enables the usage of some of Smacks parsing
- * utilities such as {@link PacketParserUtils#parsePacketExtension(String, String, org.xmlpull.v1.XmlPullParser)} to be used
- * to parse any element of the XML being parsed.
- *
- * <p>Top level extensions have only one element, but they can have multiple children, or
- * their children can have multiple children. This interface is a way of allowing extensions
- * to be embedded within one another as a partial or complete one to one mapping of extension
- * to element.
- *
- * @author Robin Collier
- */
-public interface EmbeddedPacketExtension extends PacketExtension
-{
- /**
- * Get the list of embedded {@link PacketExtension} objects.
- *
- * @return List of embedded {@link PacketExtension}
- */
- List<PacketExtension> getExtensions();
-}
+/**
+ * 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.pubsub;
+
+import java.util.List;
+
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.util.PacketParserUtils;
+
+/**
+ * This interface defines {@link PacketExtension} implementations that contain other
+ * extensions. This effectively extends the idea of an extension within one of the
+ * top level {@link Packet} types to consider any embedded element to be an extension
+ * of its parent. This more easily enables the usage of some of Smacks parsing
+ * utilities such as {@link PacketParserUtils#parsePacketExtension(String, String, org.xmlpull.v1.XmlPullParser)} to be used
+ * to parse any element of the XML being parsed.
+ *
+ * <p>Top level extensions have only one element, but they can have multiple children, or
+ * their children can have multiple children. This interface is a way of allowing extensions
+ * to be embedded within one another as a partial or complete one to one mapping of extension
+ * to element.
+ *
+ * @author Robin Collier
+ */
+public interface EmbeddedPacketExtension extends PacketExtension
+{
+ /**
+ * Get the list of embedded {@link PacketExtension} objects.
+ *
+ * @return List of embedded {@link PacketExtension}
+ */
+ List<PacketExtension> getExtensions();
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElement.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElement.java
index 165970f5d..e91b4374d 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElement.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElement.java
@@ -1,74 +1,74 @@
-/**
- * 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.pubsub;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
-
-/**
- * Represents the top level element of a pubsub event extension. All types of pubsub events are
- * represented by this class. The specific type can be found by {@link #getEventType()}. The
- * embedded event information, which is specific to the event type, can be retrieved by the {@link #getEvent()}
- * method.
- *
- * @author Robin Collier
- */
-public class EventElement implements EmbeddedPacketExtension
-{
- private EventElementType type;
- private NodeExtension ext;
-
- public EventElement(EventElementType eventType, NodeExtension eventExt)
- {
- type = eventType;
- ext = eventExt;
- }
-
- public EventElementType getEventType()
- {
- return type;
- }
-
- public List<PacketExtension> getExtensions()
- {
- return Arrays.asList(new PacketExtension[]{getEvent()});
- }
-
- public NodeExtension getEvent()
- {
- return ext;
- }
-
- public String getElementName()
- {
- return "event";
- }
-
- public String getNamespace()
- {
- return PubSubNamespace.EVENT.getXmlns();
- }
-
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<event xmlns='" + PubSubNamespace.EVENT.getXmlns() + "'>");
-
- builder.append(ext.toXML());
- builder.append("</event>");
- return builder.toString();
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+
+/**
+ * Represents the top level element of a pubsub event extension. All types of pubsub events are
+ * represented by this class. The specific type can be found by {@link #getEventType()}. The
+ * embedded event information, which is specific to the event type, can be retrieved by the {@link #getEvent()}
+ * method.
+ *
+ * @author Robin Collier
+ */
+public class EventElement implements EmbeddedPacketExtension
+{
+ private EventElementType type;
+ private NodeExtension ext;
+
+ public EventElement(EventElementType eventType, NodeExtension eventExt)
+ {
+ type = eventType;
+ ext = eventExt;
+ }
+
+ public EventElementType getEventType()
+ {
+ return type;
+ }
+
+ public List<PacketExtension> getExtensions()
+ {
+ return Arrays.asList(new PacketExtension[]{getEvent()});
+ }
+
+ public NodeExtension getEvent()
+ {
+ return ext;
+ }
+
+ public String getElementName()
+ {
+ return "event";
+ }
+
+ public String getNamespace()
+ {
+ return PubSubNamespace.EVENT.getXmlns();
+ }
+
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<event xmlns='" + PubSubNamespace.EVENT.getXmlns() + "'>");
+
+ builder.append(ext.toXML());
+ builder.append("</event>");
+ return builder.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElementType.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElementType.java
index 343edbe6f..038b97935 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElementType.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/EventElementType.java
@@ -1,41 +1,41 @@
-/**
- * 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.pubsub;
-
-/**
- * This enumeration defines the possible event types that are supported within pubsub
- * event messages.
- *
- * @author Robin Collier
- */
-public enum EventElementType
-{
- /** A node has been associated or dissassociated with a collection node */
- collection,
-
- /** A node has had its configuration changed */
- configuration,
-
- /** A node has been deleted */
- delete,
-
- /** Items have been published to a node */
- items,
-
- /** All items have been purged from a node */
- purge,
-
- /** A node has been subscribed to */
- subscription
-}
+/**
+ * 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.pubsub;
+
+/**
+ * This enumeration defines the possible event types that are supported within pubsub
+ * event messages.
+ *
+ * @author Robin Collier
+ */
+public enum EventElementType
+{
+ /** A node has been associated or dissassociated with a collection node */
+ collection,
+
+ /** A node has had its configuration changed */
+ configuration,
+
+ /** A node has been deleted */
+ delete,
+
+ /** Items have been published to a node */
+ items,
+
+ /** All items have been purged from a node */
+ purge,
+
+ /** A node has been subscribed to */
+ subscription
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNode.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNode.java
index e08bed259..992c26512 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNode.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNode.java
@@ -1,99 +1,99 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smackx.Form;
-
-/**
- * Generic packet extension which represents any pubsub form that is
- * parsed from the incoming stream or being sent out to the server.
- *
- * Form types are defined in {@link FormNodeType}.
- *
- * @author Robin Collier
- */
-public class FormNode extends NodeExtension
-{
- private Form configForm;
-
- /**
- * Create a {@link FormNode} which contains the specified form.
- *
- * @param formType The type of form being sent
- * @param submitForm The form
- */
- public FormNode(FormNodeType formType, Form submitForm)
- {
- super(formType.getNodeElement());
-
- if (submitForm == null)
- throw new IllegalArgumentException("Submit form cannot be null");
- configForm = submitForm;
- }
-
- /**
- * Create a {@link FormNode} which contains the specified form, which is
- * associated with the specified node.
- *
- * @param formType The type of form being sent
- * @param nodeId The node the form is associated with
- * @param submitForm The form
- */
- public FormNode(FormNodeType formType, String nodeId, Form submitForm)
- {
- super(formType.getNodeElement(), nodeId);
-
- if (submitForm == null)
- throw new IllegalArgumentException("Submit form cannot be null");
- configForm = submitForm;
- }
-
- /**
- * Get the Form that is to be sent, or was retrieved from the server.
- *
- * @return The form
- */
- public Form getForm()
- {
- return configForm;
- }
-
- @Override
- public String toXML()
- {
- if (configForm == null)
- {
- return super.toXML();
- }
- else
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
-
- if (getNode() != null)
- {
- builder.append(" node='");
- builder.append(getNode());
- builder.append("'>");
- }
- else
- builder.append('>');
- builder.append(configForm.getDataFormToSend().toXML());
- builder.append("</");
- builder.append(getElementName() + '>');
- return builder.toString();
- }
- }
-
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smackx.Form;
+
+/**
+ * Generic packet extension which represents any pubsub form that is
+ * parsed from the incoming stream or being sent out to the server.
+ *
+ * Form types are defined in {@link FormNodeType}.
+ *
+ * @author Robin Collier
+ */
+public class FormNode extends NodeExtension
+{
+ private Form configForm;
+
+ /**
+ * Create a {@link FormNode} which contains the specified form.
+ *
+ * @param formType The type of form being sent
+ * @param submitForm The form
+ */
+ public FormNode(FormNodeType formType, Form submitForm)
+ {
+ super(formType.getNodeElement());
+
+ if (submitForm == null)
+ throw new IllegalArgumentException("Submit form cannot be null");
+ configForm = submitForm;
+ }
+
+ /**
+ * Create a {@link FormNode} which contains the specified form, which is
+ * associated with the specified node.
+ *
+ * @param formType The type of form being sent
+ * @param nodeId The node the form is associated with
+ * @param submitForm The form
+ */
+ public FormNode(FormNodeType formType, String nodeId, Form submitForm)
+ {
+ super(formType.getNodeElement(), nodeId);
+
+ if (submitForm == null)
+ throw new IllegalArgumentException("Submit form cannot be null");
+ configForm = submitForm;
+ }
+
+ /**
+ * Get the Form that is to be sent, or was retrieved from the server.
+ *
+ * @return The form
+ */
+ public Form getForm()
+ {
+ return configForm;
+ }
+
+ @Override
+ public String toXML()
+ {
+ if (configForm == null)
+ {
+ return super.toXML();
+ }
+ else
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+
+ if (getNode() != null)
+ {
+ builder.append(" node='");
+ builder.append(getNode());
+ builder.append("'>");
+ }
+ else
+ builder.append('>');
+ builder.append(configForm.getDataFormToSend().toXML());
+ builder.append("</");
+ builder.append(getElementName() + '>');
+ return builder.toString();
+ }
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNodeType.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNodeType.java
index 6a163ee9f..48a600a76 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNodeType.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormNodeType.java
@@ -1,50 +1,50 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
-
-/**
- * The types of forms supported by the pubsub specification.
- *
- * @author Robin Collier
- */
-public enum FormNodeType
-{
- /** Form for configuring an existing node */
- CONFIGURE_OWNER,
-
- /** Form for configuring a node during creation */
- CONFIGURE,
-
- /** Form for configuring subscription options */
- OPTIONS,
-
- /** Form which represents the default node configuration options */
- DEFAULT;
-
- public PubSubElementType getNodeElement()
- {
- return PubSubElementType.valueOf(toString());
- }
-
- public static FormNodeType valueOfFromElementName(String elem, String configNamespace)
- {
- if ("configure".equals(elem) && PubSubNamespace.OWNER.getXmlns().equals(configNamespace))
- {
- return CONFIGURE_OWNER;
- }
- return valueOf(elem.toUpperCase());
- }
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+
+/**
+ * The types of forms supported by the pubsub specification.
+ *
+ * @author Robin Collier
+ */
+public enum FormNodeType
+{
+ /** Form for configuring an existing node */
+ CONFIGURE_OWNER,
+
+ /** Form for configuring a node during creation */
+ CONFIGURE,
+
+ /** Form for configuring subscription options */
+ OPTIONS,
+
+ /** Form which represents the default node configuration options */
+ DEFAULT;
+
+ public PubSubElementType getNodeElement()
+ {
+ return PubSubElementType.valueOf(toString());
+ }
+
+ public static FormNodeType valueOfFromElementName(String elem, String configNamespace)
+ {
+ if ("configure".equals(elem) && PubSubNamespace.OWNER.getXmlns().equals(configNamespace))
+ {
+ return CONFIGURE_OWNER;
+ }
+ return valueOf(elem.toUpperCase());
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormType.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormType.java
index e0fff519f..f4df2551e 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormType.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/FormType.java
@@ -1,26 +1,26 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smackx.Form;
-
-/**
- * Defines the allowable types for a {@link Form}
- *
- * @author Robin Collier
- */
-public enum FormType
-{
- form, submit, cancel, result;
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smackx.Form;
+
+/**
+ * Defines the allowable types for a {@link Form}
+ *
+ * @author Robin Collier
+ */
+public enum FormType
+{
+ form, submit, cancel, result;
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/GetItemsRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/GetItemsRequest.java
index 09355713c..341b7b5bc 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/GetItemsRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/GetItemsRequest.java
@@ -1,85 +1,85 @@
-/**
- * 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.pubsub;
-
-/**
- * Represents a request to subscribe to a node.
- *
- * @author Robin Collier
- */
-public class GetItemsRequest extends NodeExtension
-{
- protected String subId;
- protected int maxItems;
-
- public GetItemsRequest(String nodeId)
- {
- super(PubSubElementType.ITEMS, nodeId);
- }
-
- public GetItemsRequest(String nodeId, String subscriptionId)
- {
- super(PubSubElementType.ITEMS, nodeId);
- subId = subscriptionId;
- }
-
- public GetItemsRequest(String nodeId, int maxItemsToReturn)
- {
- super(PubSubElementType.ITEMS, nodeId);
- maxItems = maxItemsToReturn;
- }
-
- public GetItemsRequest(String nodeId, String subscriptionId, int maxItemsToReturn)
- {
- this(nodeId, maxItemsToReturn);
- subId = subscriptionId;
- }
-
- public String getSubscriptionId()
- {
- return subId;
- }
-
- public int getMaxItems()
- {
- return maxItems;
- }
-
- @Override
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
-
- builder.append(" node='");
- builder.append(getNode());
- builder.append("'");
-
- if (getSubscriptionId() != null)
- {
- builder.append(" subid='");
- builder.append(getSubscriptionId());
- builder.append("'");
- }
-
- if (getMaxItems() > 0)
- {
- builder.append(" max_items='");
- builder.append(getMaxItems());
- builder.append("'");
- }
- builder.append("/>");
- return builder.toString();
- }
-}
+/**
+ * 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.pubsub;
+
+/**
+ * Represents a request to subscribe to a node.
+ *
+ * @author Robin Collier
+ */
+public class GetItemsRequest extends NodeExtension
+{
+ protected String subId;
+ protected int maxItems;
+
+ public GetItemsRequest(String nodeId)
+ {
+ super(PubSubElementType.ITEMS, nodeId);
+ }
+
+ public GetItemsRequest(String nodeId, String subscriptionId)
+ {
+ super(PubSubElementType.ITEMS, nodeId);
+ subId = subscriptionId;
+ }
+
+ public GetItemsRequest(String nodeId, int maxItemsToReturn)
+ {
+ super(PubSubElementType.ITEMS, nodeId);
+ maxItems = maxItemsToReturn;
+ }
+
+ public GetItemsRequest(String nodeId, String subscriptionId, int maxItemsToReturn)
+ {
+ this(nodeId, maxItemsToReturn);
+ subId = subscriptionId;
+ }
+
+ public String getSubscriptionId()
+ {
+ return subId;
+ }
+
+ public int getMaxItems()
+ {
+ return maxItems;
+ }
+
+ @Override
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+
+ builder.append(" node='");
+ builder.append(getNode());
+ builder.append("'");
+
+ if (getSubscriptionId() != null)
+ {
+ builder.append(" subid='");
+ builder.append(getSubscriptionId());
+ builder.append("'");
+ }
+
+ if (getMaxItems() > 0)
+ {
+ builder.append(" max_items='");
+ builder.append(getMaxItems());
+ builder.append("'");
+ }
+ builder.append("/>");
+ return builder.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Item.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Item.java
index 2ce0baac5..8e897c765 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Item.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Item.java
@@ -1,132 +1,132 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smack.packet.Message;
-import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
-
-/**
- * This class represents an item that has been, or will be published to a
- * pubsub node. An <tt>Item</tt> has several properties that are dependent
- * on the configuration of the node to which it has been or will be published.
- *
- * <h1>An Item received from a node (via {@link LeafNode#getItems()} or {@link LeafNode#addItemEventListener(org.jivesoftware.smackx.pubsub.listener.ItemEventListener)}</b>
- * <li>Will always have an id (either user or server generated) unless node configuration has both
- * {@link ConfigureForm#isPersistItems()} and {@link ConfigureForm#isDeliverPayloads()}set to false.
- * <li>Will have a payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
- * to true, otherwise it will be null.
- *
- * <h1>An Item created to send to a node (via {@link LeafNode#send()} or {@link LeafNode#publish()}</b>
- * <li>The id is optional, since the server will generate one if necessary, but should be used if it is
- * meaningful in the context of the node. This value must be unique within the node that it is sent to, since
- * resending an item with the same id will overwrite the one that already exists if the items are persisted.
- * <li>Will require payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
- * to true.
- *
- * <p>To customise the payload object being returned from the {@link #getPayload()} method, you can
- * add a custom parser as explained in {@link ItemProvider}.
- *
- * @author Robin Collier
- */
-public class Item extends NodeExtension
-{
- private String id;
-
- /**
- * Create an empty <tt>Item</tt> with no id. This is a valid item for nodes which are configured
- * so that {@link ConfigureForm#isDeliverPayloads()} is false. In most cases an id will be generated by the server.
- * For nodes configured with {@link ConfigureForm#isDeliverPayloads()} and {@link ConfigureForm#isPersistItems()}
- * set to false, no <tt>Item</tt> is sent to the node, you have to use {@link LeafNode#send()} or {@link LeafNode#publish()}
- * methods in this case.
- */
- public Item()
- {
- super(PubSubElementType.ITEM);
- }
-
- /**
- * Create an <tt>Item</tt> with an id but no payload. This is a valid item for nodes which are configured
- * so that {@link ConfigureForm#isDeliverPayloads()} is false.
- *
- * @param itemId The id if the item. It must be unique within the node unless overwriting and existing item.
- * Passing null is the equivalent of calling {@link #Item()}.
- */
- public Item(String itemId)
- {
- // The element type is actually irrelevant since we override getNamespace() to return null
- super(PubSubElementType.ITEM);
- id = itemId;
- }
-
- /**
- * Create an <tt>Item</tt> with an id and a node id.
- * <p>
- * <b>Note:</b> This is not valid for publishing an item to a node, only receiving from
- * one as part of {@link Message}. If used to create an Item to publish
- * (via {@link LeafNode#publish(Item)}, the server <i>may</i> return an
- * error for an invalid packet.
- *
- * @param itemId The id of the item.
- * @param nodeId The id of the node which the item was published to.
- */
- public Item(String itemId, String nodeId)
- {
- super(PubSubElementType.ITEM_EVENT, nodeId);
- id = itemId;
- }
-
- /**
- * Get the item id. Unique to the node it is associated with.
- *
- * @return The id
- */
- public String getId()
- {
- return id;
- }
-
- @Override
- public String getNamespace()
- {
- return null;
- }
-
- @Override
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<item");
-
- if (id != null)
- {
- builder.append(" id='");
- builder.append(id);
- builder.append("'");
- }
-
- if (getNode() != null) {
- builder.append(" node='");
- builder.append(getNode());
- builder.append("'");
- }
- builder.append("/>");
-
- return builder.toString();
- }
-
- @Override
- public String toString()
- {
- return getClass().getName() + " | Content [" + toXML() + "]";
- }
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
+
+/**
+ * This class represents an item that has been, or will be published to a
+ * pubsub node. An <tt>Item</tt> has several properties that are dependent
+ * on the configuration of the node to which it has been or will be published.
+ *
+ * <h1>An Item received from a node (via {@link LeafNode#getItems()} or {@link LeafNode#addItemEventListener(org.jivesoftware.smackx.pubsub.listener.ItemEventListener)}</b>
+ * <li>Will always have an id (either user or server generated) unless node configuration has both
+ * {@link ConfigureForm#isPersistItems()} and {@link ConfigureForm#isDeliverPayloads()}set to false.
+ * <li>Will have a payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
+ * to true, otherwise it will be null.
+ *
+ * <h1>An Item created to send to a node (via {@link LeafNode#send()} or {@link LeafNode#publish()}</b>
+ * <li>The id is optional, since the server will generate one if necessary, but should be used if it is
+ * meaningful in the context of the node. This value must be unique within the node that it is sent to, since
+ * resending an item with the same id will overwrite the one that already exists if the items are persisted.
+ * <li>Will require payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
+ * to true.
+ *
+ * <p>To customise the payload object being returned from the {@link #getPayload()} method, you can
+ * add a custom parser as explained in {@link ItemProvider}.
+ *
+ * @author Robin Collier
+ */
+public class Item extends NodeExtension
+{
+ private String id;
+
+ /**
+ * Create an empty <tt>Item</tt> with no id. This is a valid item for nodes which are configured
+ * so that {@link ConfigureForm#isDeliverPayloads()} is false. In most cases an id will be generated by the server.
+ * For nodes configured with {@link ConfigureForm#isDeliverPayloads()} and {@link ConfigureForm#isPersistItems()}
+ * set to false, no <tt>Item</tt> is sent to the node, you have to use {@link LeafNode#send()} or {@link LeafNode#publish()}
+ * methods in this case.
+ */
+ public Item()
+ {
+ super(PubSubElementType.ITEM);
+ }
+
+ /**
+ * Create an <tt>Item</tt> with an id but no payload. This is a valid item for nodes which are configured
+ * so that {@link ConfigureForm#isDeliverPayloads()} is false.
+ *
+ * @param itemId The id if the item. It must be unique within the node unless overwriting and existing item.
+ * Passing null is the equivalent of calling {@link #Item()}.
+ */
+ public Item(String itemId)
+ {
+ // The element type is actually irrelevant since we override getNamespace() to return null
+ super(PubSubElementType.ITEM);
+ id = itemId;
+ }
+
+ /**
+ * Create an <tt>Item</tt> with an id and a node id.
+ * <p>
+ * <b>Note:</b> This is not valid for publishing an item to a node, only receiving from
+ * one as part of {@link Message}. If used to create an Item to publish
+ * (via {@link LeafNode#publish(Item)}, the server <i>may</i> return an
+ * error for an invalid packet.
+ *
+ * @param itemId The id of the item.
+ * @param nodeId The id of the node which the item was published to.
+ */
+ public Item(String itemId, String nodeId)
+ {
+ super(PubSubElementType.ITEM_EVENT, nodeId);
+ id = itemId;
+ }
+
+ /**
+ * Get the item id. Unique to the node it is associated with.
+ *
+ * @return The id
+ */
+ public String getId()
+ {
+ return id;
+ }
+
+ @Override
+ public String getNamespace()
+ {
+ return null;
+ }
+
+ @Override
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<item");
+
+ if (id != null)
+ {
+ builder.append(" id='");
+ builder.append(id);
+ builder.append("'");
+ }
+
+ if (getNode() != null) {
+ builder.append(" node='");
+ builder.append(getNode());
+ builder.append("'");
+ }
+ builder.append("/>");
+
+ return builder.toString();
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getName() + " | Content [" + toXML() + "]";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemDeleteEvent.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemDeleteEvent.java
index 82ab7dfe9..b26dd6f51 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemDeleteEvent.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemDeleteEvent.java
@@ -1,62 +1,62 @@
-/**
- * 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.pubsub;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Represents an event in which items have been deleted from the node.
- *
- * @author Robin Collier
- */
-public class ItemDeleteEvent extends SubscriptionEvent
-{
- private List<String> itemIds = Collections.EMPTY_LIST;
-
- /**
- * Constructs an <tt>ItemDeleteEvent</tt> that indicates the the supplied
- * items (by id) have been deleted, and that the event matches the listed
- * subscriptions. The subscriptions would have been created by calling
- * {@link LeafNode#subscribe(String)}.
- *
- * @param nodeId The id of the node the event came from
- * @param deletedItemIds The item ids of the items that were deleted.
- * @param subscriptionIds The subscriptions that match the event.
- */
- public ItemDeleteEvent(String nodeId, List<String> deletedItemIds, List<String> subscriptionIds)
- {
- super(nodeId, subscriptionIds);
-
- if (deletedItemIds == null)
- throw new IllegalArgumentException("deletedItemIds cannot be null");
- itemIds = deletedItemIds;
- }
-
- /**
- * Get the item id's of the items that have been deleted.
- *
- * @return List of item id's
- */
- public List<String> getItemIds()
- {
- return Collections.unmodifiableList(itemIds);
- }
-
- @Override
- public String toString()
- {
- return getClass().getName() + " [subscriptions: " + getSubscriptions() + "], [Deleted Items: " + itemIds + ']';
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents an event in which items have been deleted from the node.
+ *
+ * @author Robin Collier
+ */
+public class ItemDeleteEvent extends SubscriptionEvent
+{
+ private List<String> itemIds = Collections.EMPTY_LIST;
+
+ /**
+ * Constructs an <tt>ItemDeleteEvent</tt> that indicates the the supplied
+ * items (by id) have been deleted, and that the event matches the listed
+ * subscriptions. The subscriptions would have been created by calling
+ * {@link LeafNode#subscribe(String)}.
+ *
+ * @param nodeId The id of the node the event came from
+ * @param deletedItemIds The item ids of the items that were deleted.
+ * @param subscriptionIds The subscriptions that match the event.
+ */
+ public ItemDeleteEvent(String nodeId, List<String> deletedItemIds, List<String> subscriptionIds)
+ {
+ super(nodeId, subscriptionIds);
+
+ if (deletedItemIds == null)
+ throw new IllegalArgumentException("deletedItemIds cannot be null");
+ itemIds = deletedItemIds;
+ }
+
+ /**
+ * Get the item id's of the items that have been deleted.
+ *
+ * @return List of item id's
+ */
+ public List<String> getItemIds()
+ {
+ return Collections.unmodifiableList(itemIds);
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getName() + " [subscriptions: " + getSubscriptions() + "], [Deleted Items: " + itemIds + ']';
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java
index 1ef1f6776..7c0574c95 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemPublishEvent.java
@@ -1,123 +1,123 @@
-/**
- * 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.pubsub;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Represents an event generated by an item(s) being published to a node.
- *
- * @author Robin Collier
- */
-public class ItemPublishEvent <T extends Item> extends SubscriptionEvent
-{
- private List<T> items;
- private Date originalDate;
-
- /**
- * Constructs an <tt>ItemPublishEvent</tt> with the provided list
- * of {@link Item} that were published.
- *
- * @param nodeId The id of the node the event came from
- * @param eventItems The list of {@link Item} that were published
- */
- public ItemPublishEvent(String nodeId, List<T> eventItems)
- {
- super(nodeId);
- items = eventItems;
- }
-
- /**
- * Constructs an <tt>ItemPublishEvent</tt> with the provided list
- * of {@link Item} that were published. The list of subscription ids
- * represents the subscriptions that matched the event, in the case
- * of the user having multiple subscriptions.
- *
- * @param nodeId The id of the node the event came from
- * @param eventItems The list of {@link Item} that were published
- * @param subscriptionIds The list of subscriptionIds
- */
- public ItemPublishEvent(String nodeId, List<T> eventItems, List<String> subscriptionIds)
- {
- super(nodeId, subscriptionIds);
- items = eventItems;
- }
-
- /**
- * Constructs an <tt>ItemPublishEvent</tt> with the provided list
- * of {@link Item} that were published in the past. The published
- * date signifies that this is delayed event. The list of subscription ids
- * represents the subscriptions that matched the event, in the case
- * of the user having multiple subscriptions.
- *
- * @param nodeId The id of the node the event came from
- * @param eventItems The list of {@link Item} that were published
- * @param subscriptionIds The list of subscriptionIds
- * @param publishedDate The original publishing date of the events
- */
- public ItemPublishEvent(String nodeId, List<T> eventItems, List<String> subscriptionIds, Date publishedDate)
- {
- super(nodeId, subscriptionIds);
- items = eventItems;
-
- if (publishedDate != null)
- originalDate = publishedDate;
- }
-
- /**
- * Get the list of {@link Item} that were published.
- *
- * @return The list of published {@link Item}
- */
- public List<T> getItems()
- {
- return Collections.unmodifiableList(items);
- }
-
- /**
- * Indicates whether this event was delayed. That is, the items
- * were published to the node at some time in the past. This will
- * typically happen if there is an item already published to the node
- * before a user subscribes to it. In this case, when the user
- * subscribes, the server may send the last item published to the node
- * with a delay date showing its time of original publication.
- *
- * @return true if the items are delayed, false otherwise.
- */
- public boolean isDelayed()
- {
- return (originalDate != null);
- }
-
- /**
- * Gets the original date the items were published. This is only
- * valid if {@link #isDelayed()} is true.
- *
- * @return Date items were published if {@link #isDelayed()} is true, null otherwise.
- */
- public Date getPublishedDate()
- {
- return originalDate;
- }
-
- @Override
- public String toString()
- {
- return getClass().getName() + " [subscriptions: " + getSubscriptions() + "], [Delayed: " +
- (isDelayed() ? originalDate.toString() : "false") + ']';
- }
-
-}
+/**
+ * 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.pubsub;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Represents an event generated by an item(s) being published to a node.
+ *
+ * @author Robin Collier
+ */
+public class ItemPublishEvent <T extends Item> extends SubscriptionEvent
+{
+ private List<T> items;
+ private Date originalDate;
+
+ /**
+ * Constructs an <tt>ItemPublishEvent</tt> with the provided list
+ * of {@link Item} that were published.
+ *
+ * @param nodeId The id of the node the event came from
+ * @param eventItems The list of {@link Item} that were published
+ */
+ public ItemPublishEvent(String nodeId, List<T> eventItems)
+ {
+ super(nodeId);
+ items = eventItems;
+ }
+
+ /**
+ * Constructs an <tt>ItemPublishEvent</tt> with the provided list
+ * of {@link Item} that were published. The list of subscription ids
+ * represents the subscriptions that matched the event, in the case
+ * of the user having multiple subscriptions.
+ *
+ * @param nodeId The id of the node the event came from
+ * @param eventItems The list of {@link Item} that were published
+ * @param subscriptionIds The list of subscriptionIds
+ */
+ public ItemPublishEvent(String nodeId, List<T> eventItems, List<String> subscriptionIds)
+ {
+ super(nodeId, subscriptionIds);
+ items = eventItems;
+ }
+
+ /**
+ * Constructs an <tt>ItemPublishEvent</tt> with the provided list
+ * of {@link Item} that were published in the past. The published
+ * date signifies that this is delayed event. The list of subscription ids
+ * represents the subscriptions that matched the event, in the case
+ * of the user having multiple subscriptions.
+ *
+ * @param nodeId The id of the node the event came from
+ * @param eventItems The list of {@link Item} that were published
+ * @param subscriptionIds The list of subscriptionIds
+ * @param publishedDate The original publishing date of the events
+ */
+ public ItemPublishEvent(String nodeId, List<T> eventItems, List<String> subscriptionIds, Date publishedDate)
+ {
+ super(nodeId, subscriptionIds);
+ items = eventItems;
+
+ if (publishedDate != null)
+ originalDate = publishedDate;
+ }
+
+ /**
+ * Get the list of {@link Item} that were published.
+ *
+ * @return The list of published {@link Item}
+ */
+ public List<T> getItems()
+ {
+ return Collections.unmodifiableList(items);
+ }
+
+ /**
+ * Indicates whether this event was delayed. That is, the items
+ * were published to the node at some time in the past. This will
+ * typically happen if there is an item already published to the node
+ * before a user subscribes to it. In this case, when the user
+ * subscribes, the server may send the last item published to the node
+ * with a delay date showing its time of original publication.
+ *
+ * @return true if the items are delayed, false otherwise.
+ */
+ public boolean isDelayed()
+ {
+ return (originalDate != null);
+ }
+
+ /**
+ * Gets the original date the items were published. This is only
+ * valid if {@link #isDelayed()} is true.
+ *
+ * @return Date items were published if {@link #isDelayed()} is true, null otherwise.
+ */
+ public Date getPublishedDate()
+ {
+ return originalDate;
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getName() + " [subscriptions: " + getSubscriptions() + "], [Delayed: " +
+ (isDelayed() ? originalDate.toString() : "false") + ']';
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemReply.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemReply.java
index 3e090d98f..99a0827d5 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemReply.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemReply.java
@@ -1,29 +1,29 @@
-/**
- * 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.pubsub;
-
-/**
- * These are the options for the node configuration setting {@link ConfigureForm#setItemReply(ItemReply)},
- * which defines who should receive replies to items.
- *
- * @author Robin Collier
- */
-public enum ItemReply
-{
- /** The node owner */
- owner,
-
- /** The item publisher */
- publisher;
-}
+/**
+ * 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.pubsub;
+
+/**
+ * These are the options for the node configuration setting {@link ConfigureForm#setItemReply(ItemReply)},
+ * which defines who should receive replies to items.
+ *
+ * @author Robin Collier
+ */
+public enum ItemReply
+{
+ /** The node owner */
+ owner,
+
+ /** The item publisher */
+ publisher;
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemsExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemsExtension.java
index c98d93af0..855ed0684 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemsExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/ItemsExtension.java
@@ -1,196 +1,196 @@
-/**
- * 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.pubsub;
-
-import java.util.List;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * This class is used to for multiple purposes.
- * <li>It can represent an event containing a list of items that have been published
- * <li>It can represent an event containing a list of retracted (deleted) items.
- * <li>It can represent a request to delete a list of items.
- * <li>It can represent a request to get existing items.
- *
- * <p><b>Please note, this class is used for internal purposes, and is not required for usage of
- * pubsub functionality.</b>
- *
- * @author Robin Collier
- */
-public class ItemsExtension extends NodeExtension implements EmbeddedPacketExtension
-{
- protected ItemsElementType type;
- protected Boolean notify;
- protected List<? extends PacketExtension> items;
-
- public enum ItemsElementType
- {
- /** An items element, which has an optional <b>max_items</b> attribute when requesting items */
- items(PubSubElementType.ITEMS, "max_items"),
-
- /** A retract element, which has an optional <b>notify</b> attribute when publishing deletions */
- retract(PubSubElementType.RETRACT, "notify");
-
- private PubSubElementType elem;
- private String att;
-
- private ItemsElementType(PubSubElementType nodeElement, String attribute)
- {
- elem = nodeElement;
- att = attribute;
- }
-
- public PubSubElementType getNodeElement()
- {
- return elem;
- }
-
- public String getElementAttribute()
- {
- return att;
- }
- }
-
- /**
- * Construct an instance with a list representing items that have been published or deleted.
- *
- * <p>Valid scenarios are:
- * <li>Request items from node - itemsType = {@link ItemsElementType#items}, items = list of {@link Item} and an
- * optional value for the <b>max_items</b> attribute.
- * <li>Request to delete items - itemsType = {@link ItemsElementType#retract}, items = list of {@link Item} containing
- * only id's and an optional value for the <b>notify</b> attribute.
- * <li>Items published event - itemsType = {@link ItemsElementType#items}, items = list of {@link Item} and
- * attributeValue = <code>null</code>
- * <li>Items deleted event - itemsType = {@link ItemsElementType#items}, items = list of {@link RetractItem} and
- * attributeValue = <code>null</code>
- *
- * @param itemsType Type of representation
- * @param nodeId The node to which the items are being sent or deleted
- * @param items The list of {@link Item} or {@link RetractItem}
- * @param attributeValue The value of the <b>max_items</b>
- */
- public ItemsExtension(ItemsElementType itemsType, String nodeId, List<? extends PacketExtension> items)
- {
- super(itemsType.getNodeElement(), nodeId);
- type = itemsType;
- this.items = items;
- }
-
- /**
- * Construct an instance with a list representing items that have been published or deleted.
- *
- * <p>Valid scenarios are:
- * <li>Request items from node - itemsType = {@link ItemsElementType#items}, items = list of {@link Item} and an
- * optional value for the <b>max_items</b> attribute.
- * <li>Request to delete items - itemsType = {@link ItemsElementType#retract}, items = list of {@link Item} containing
- * only id's and an optional value for the <b>notify</b> attribute.
- * <li>Items published event - itemsType = {@link ItemsElementType#items}, items = list of {@link Item} and
- * attributeValue = <code>null</code>
- * <li>Items deleted event - itemsType = {@link ItemsElementType#items}, items = list of {@link RetractItem} and
- * attributeValue = <code>null</code>
- *
- * @param itemsType Type of representation
- * @param nodeId The node to which the items are being sent or deleted
- * @param items The list of {@link Item} or {@link RetractItem}
- * @param attributeValue The value of the <b>max_items</b>
- */
- public ItemsExtension(String nodeId, List<? extends PacketExtension> items, boolean notify)
- {
- super(ItemsElementType.retract.getNodeElement(), nodeId);
- type = ItemsElementType.retract;
- this.items = items;
- this.notify = notify;
- }
-
- /**
- * Get the type of element
- *
- * @return The element type
- */
- public ItemsElementType getItemsElementType()
- {
- return type;
- }
-
- public List<PacketExtension> getExtensions()
- {
- return (List<PacketExtension>)getItems();
- }
-
- /**
- * Gets the items related to the type of request or event.
- *
- * return List of {@link Item}, {@link RetractItem}, or null
- */
- public List<? extends PacketExtension> getItems()
- {
- return items;
- }
-
- /**
- * Gets the value of the optional attribute related to the {@link ItemsElementType}.
- *
- * @return The attribute value
- */
- public boolean getNotify()
- {
- return notify;
- }
-
- @Override
- public String toXML()
- {
- if ((items == null) || (items.size() == 0))
- {
- return super.toXML();
- }
- else
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
- builder.append(" node='");
- builder.append(getNode());
-
- if (notify != null)
- {
- builder.append("' ");
- builder.append(type.getElementAttribute());
- builder.append("='");
- builder.append(notify.equals(Boolean.TRUE) ? 1 : 0);
- builder.append("'>");
- }
- else
- {
- builder.append("'>");
- for (PacketExtension item : items)
- {
- builder.append(item.toXML());
- }
- }
-
- builder.append("</");
- builder.append(getElementName());
- builder.append(">");
- return builder.toString();
- }
- }
-
- @Override
- public String toString()
- {
- return getClass().getName() + "Content [" + toXML() + "]";
- }
-
-}
+/**
+ * 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.pubsub;
+
+import java.util.List;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * This class is used to for multiple purposes.
+ * <li>It can represent an event containing a list of items that have been published
+ * <li>It can represent an event containing a list of retracted (deleted) items.
+ * <li>It can represent a request to delete a list of items.
+ * <li>It can represent a request to get existing items.
+ *
+ * <p><b>Please note, this class is used for internal purposes, and is not required for usage of
+ * pubsub functionality.</b>
+ *
+ * @author Robin Collier
+ */
+public class ItemsExtension extends NodeExtension implements EmbeddedPacketExtension
+{
+ protected ItemsElementType type;
+ protected Boolean notify;
+ protected List<? extends PacketExtension> items;
+
+ public enum ItemsElementType
+ {
+ /** An items element, which has an optional <b>max_items</b> attribute when requesting items */
+ items(PubSubElementType.ITEMS, "max_items"),
+
+ /** A retract element, which has an optional <b>notify</b> attribute when publishing deletions */
+ retract(PubSubElementType.RETRACT, "notify");
+
+ private PubSubElementType elem;
+ private String att;
+
+ private ItemsElementType(PubSubElementType nodeElement, String attribute)
+ {
+ elem = nodeElement;
+ att = attribute;
+ }
+
+ public PubSubElementType getNodeElement()
+ {
+ return elem;
+ }
+
+ public String getElementAttribute()
+ {
+ return att;
+ }
+ }
+
+ /**
+ * Construct an instance with a list representing items that have been published or deleted.
+ *
+ * <p>Valid scenarios are:
+ * <li>Request items from node - itemsType = {@link ItemsElementType#items}, items = list of {@link Item} and an
+ * optional value for the <b>max_items</b> attribute.
+ * <li>Request to delete items - itemsType = {@link ItemsElementType#retract}, items = list of {@link Item} containing
+ * only id's and an optional value for the <b>notify</b> attribute.
+ * <li>Items published event - itemsType = {@link ItemsElementType#items}, items = list of {@link Item} and
+ * attributeValue = <code>null</code>
+ * <li>Items deleted event - itemsType = {@link ItemsElementType#items}, items = list of {@link RetractItem} and
+ * attributeValue = <code>null</code>
+ *
+ * @param itemsType Type of representation
+ * @param nodeId The node to which the items are being sent or deleted
+ * @param items The list of {@link Item} or {@link RetractItem}
+ * @param attributeValue The value of the <b>max_items</b>
+ */
+ public ItemsExtension(ItemsElementType itemsType, String nodeId, List<? extends PacketExtension> items)
+ {
+ super(itemsType.getNodeElement(), nodeId);
+ type = itemsType;
+ this.items = items;
+ }
+
+ /**
+ * Construct an instance with a list representing items that have been published or deleted.
+ *
+ * <p>Valid scenarios are:
+ * <li>Request items from node - itemsType = {@link ItemsElementType#items}, items = list of {@link Item} and an
+ * optional value for the <b>max_items</b> attribute.
+ * <li>Request to delete items - itemsType = {@link ItemsElementType#retract}, items = list of {@link Item} containing
+ * only id's and an optional value for the <b>notify</b> attribute.
+ * <li>Items published event - itemsType = {@link ItemsElementType#items}, items = list of {@link Item} and
+ * attributeValue = <code>null</code>
+ * <li>Items deleted event - itemsType = {@link ItemsElementType#items}, items = list of {@link RetractItem} and
+ * attributeValue = <code>null</code>
+ *
+ * @param itemsType Type of representation
+ * @param nodeId The node to which the items are being sent or deleted
+ * @param items The list of {@link Item} or {@link RetractItem}
+ * @param attributeValue The value of the <b>max_items</b>
+ */
+ public ItemsExtension(String nodeId, List<? extends PacketExtension> items, boolean notify)
+ {
+ super(ItemsElementType.retract.getNodeElement(), nodeId);
+ type = ItemsElementType.retract;
+ this.items = items;
+ this.notify = notify;
+ }
+
+ /**
+ * Get the type of element
+ *
+ * @return The element type
+ */
+ public ItemsElementType getItemsElementType()
+ {
+ return type;
+ }
+
+ public List<PacketExtension> getExtensions()
+ {
+ return (List<PacketExtension>)getItems();
+ }
+
+ /**
+ * Gets the items related to the type of request or event.
+ *
+ * return List of {@link Item}, {@link RetractItem}, or null
+ */
+ public List<? extends PacketExtension> getItems()
+ {
+ return items;
+ }
+
+ /**
+ * Gets the value of the optional attribute related to the {@link ItemsElementType}.
+ *
+ * @return The attribute value
+ */
+ public boolean getNotify()
+ {
+ return notify;
+ }
+
+ @Override
+ public String toXML()
+ {
+ if ((items == null) || (items.size() == 0))
+ {
+ return super.toXML();
+ }
+ else
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+ builder.append(" node='");
+ builder.append(getNode());
+
+ if (notify != null)
+ {
+ builder.append("' ");
+ builder.append(type.getElementAttribute());
+ builder.append("='");
+ builder.append(notify.equals(Boolean.TRUE) ? 1 : 0);
+ builder.append("'>");
+ }
+ else
+ {
+ builder.append("'>");
+ for (PacketExtension item : items)
+ {
+ builder.append(item.toXML());
+ }
+ }
+
+ builder.append("</");
+ builder.append(getElementName());
+ builder.append(">");
+ return builder.toString();
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getName() + "Content [" + toXML() + "]";
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/LeafNode.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/LeafNode.java
index eee629361..96ef51570 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/LeafNode.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/LeafNode.java
@@ -1,352 +1,352 @@
-/**
- * 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.pubsub;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ.Type;
-import org.jivesoftware.smackx.packet.DiscoverItems;
-import org.jivesoftware.smackx.pubsub.packet.PubSub;
-import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
-
-/**
- * The main class for the majority of pubsub functionality. In general
- * almost all pubsub capabilities are related to the concept of a node.
- * All items are published to a node, and typically subscribed to by other
- * users. These users then retrieve events based on this subscription.
- *
- * @author Robin Collier
- */
-public class LeafNode extends Node
-{
- LeafNode(Connection connection, String nodeName)
- {
- super(connection, nodeName);
- }
-
- /**
- * Get information on the items in the node in standard
- * {@link DiscoverItems} format.
- *
- * @return The item details in {@link DiscoverItems} format
- *
- * @throws XMPPException
- */
- public DiscoverItems discoverItems()
- throws XMPPException
- {
- DiscoverItems items = new DiscoverItems();
- items.setTo(to);
- items.setNode(getId());
- return (DiscoverItems)SyncPacketSend.getReply(con, items);
- }
-
- /**
- * Get the current items stored in the node.
- *
- * @return List of {@link Item} in the node
- *
- * @throws XMPPException
- */
- public <T extends Item> List<T> getItems()
- throws XMPPException
- {
- PubSub request = createPubsubPacket(Type.GET, new GetItemsRequest(getId()));
-
- PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
- ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
- return (List<T>)itemsElem.getItems();
- }
-
- /**
- * Get the current items stored in the node based
- * on the subscription associated with the provided
- * subscription id.
- *
- * @param subscriptionId - The subscription id for the
- * associated subscription.
- * @return List of {@link Item} in the node
- *
- * @throws XMPPException
- */
- public <T extends Item> List<T> getItems(String subscriptionId)
- throws XMPPException
- {
- PubSub request = createPubsubPacket(Type.GET, new GetItemsRequest(getId(), subscriptionId));
-
- PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
- ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
- return (List<T>)itemsElem.getItems();
- }
-
- /**
- * Get the items specified from the node. This would typically be
- * used when the server does not return the payload due to size
- * constraints. The user would be required to retrieve the payload
- * after the items have been retrieved via {@link #getItems()} or an
- * event, that did not include the payload.
- *
- * @param ids Item ids of the items to retrieve
- *
- * @return The list of {@link Item} with payload
- *
- * @throws XMPPException
- */
- public <T extends Item> List<T> getItems(Collection<String> ids)
- throws XMPPException
- {
- List<Item> itemList = new ArrayList<Item>(ids.size());
-
- for (String id : ids)
- {
- itemList.add(new Item(id));
- }
- PubSub request = createPubsubPacket(Type.GET, new ItemsExtension(ItemsExtension.ItemsElementType.items, getId(), itemList));
-
- PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
- ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
- return (List<T>)itemsElem.getItems();
- }
-
- /**
- * Get items persisted on the node, limited to the specified number.
- *
- * @param maxItems Maximum number of items to return
- *
- * @return List of {@link Item}
- *
- * @throws XMPPException
- */
- public <T extends Item> List<T> getItems(int maxItems)
- throws XMPPException
- {
- PubSub request = createPubsubPacket(Type.GET, new GetItemsRequest(getId(), maxItems));
-
- PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
- ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
- return (List<T>)itemsElem.getItems();
- }
-
- /**
- * Get items persisted on the node, limited to the specified number
- * based on the subscription associated with the provided subscriptionId.
- *
- * @param maxItems Maximum number of items to return
- * @param subscriptionId The subscription which the retrieval is based
- * on.
- *
- * @return List of {@link Item}
- *
- * @throws XMPPException
- */
- public <T extends Item> List<T> getItems(int maxItems, String subscriptionId)
- throws XMPPException
- {
- PubSub request = createPubsubPacket(Type.GET, new GetItemsRequest(getId(), subscriptionId, maxItems));
-
- PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
- ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
- return (List<T>)itemsElem.getItems();
- }
-
- /**
- * Publishes an event to the node. This is an empty event
- * with no item.
- *
- * This is only acceptable for nodes with {@link ConfigureForm#isPersistItems()}=false
- * and {@link ConfigureForm#isDeliverPayloads()}=false.
- *
- * This is an asynchronous call which returns as soon as the
- * packet has been sent.
- *
- * For synchronous calls use {@link #send() send()}.
- */
- public void publish()
- {
- PubSub packet = createPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.PUBLISH, getId()));
-
- con.sendPacket(packet);
- }
-
- /**
- * Publishes an event to the node. This is a simple item
- * with no payload.
- *
- * If the id is null, an empty item (one without an id) will be sent.
- * Please note that this is not the same as {@link #send()}, which
- * publishes an event with NO item.
- *
- * This is an asynchronous call which returns as soon as the
- * packet has been sent.
- *
- * For synchronous calls use {@link #send(Item) send(Item))}.
- *
- * @param item - The item being sent
- */
- public <T extends Item> void publish(T item)
- {
- Collection<T> items = new ArrayList<T>(1);
- items.add((T)(item == null ? new Item() : item));
- publish(items);
- }
-
- /**
- * Publishes multiple events to the node. Same rules apply as in {@link #publish(Item)}.
- *
- * In addition, if {@link ConfigureForm#isPersistItems()}=false, only the last item in the input
- * list will get stored on the node, assuming it stores the last sent item.
- *
- * This is an asynchronous call which returns as soon as the
- * packet has been sent.
- *
- * For synchronous calls use {@link #send(Collection) send(Collection))}.
- *
- * @param items - The collection of items being sent
- */
- public <T extends Item> void publish(Collection<T> items)
- {
- PubSub packet = createPubsubPacket(Type.SET, new PublishItem<T>(getId(), items));
-
- con.sendPacket(packet);
- }
-
- /**
- * Publishes an event to the node. This is an empty event
- * with no item.
- *
- * This is only acceptable for nodes with {@link ConfigureForm#isPersistItems()}=false
- * and {@link ConfigureForm#isDeliverPayloads()}=false.
- *
- * This is a synchronous call which will throw an exception
- * on failure.
- *
- * For asynchronous calls, use {@link #publish() publish()}.
- *
- * @throws XMPPException
- */
- public void send()
- throws XMPPException
- {
- PubSub packet = createPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.PUBLISH, getId()));
-
- SyncPacketSend.getReply(con, packet);
- }
-
- /**
- * Publishes an event to the node. This can be either a simple item
- * with no payload, or one with it. This is determined by the Node
- * configuration.
- *
- * If the node has <b>deliver_payload=false</b>, the Item must not
- * have a payload.
- *
- * If the id is null, an empty item (one without an id) will be sent.
- * Please note that this is not the same as {@link #send()}, which
- * publishes an event with NO item.
- *
- * This is a synchronous call which will throw an exception
- * on failure.
- *
- * For asynchronous calls, use {@link #publish(Item) publish(Item)}.
- *
- * @param item - The item being sent
- *
- * @throws XMPPException
- */
- public <T extends Item> void send(T item)
- throws XMPPException
- {
- Collection<T> items = new ArrayList<T>(1);
- items.add((item == null ? (T)new Item() : item));
- send(items);
- }
-
- /**
- * Publishes multiple events to the node. Same rules apply as in {@link #send(Item)}.
- *
- * In addition, if {@link ConfigureForm#isPersistItems()}=false, only the last item in the input
- * list will get stored on the node, assuming it stores the last sent item.
- *
- * This is a synchronous call which will throw an exception
- * on failure.
- *
- * For asynchronous calls, use {@link #publish(Collection) publish(Collection))}.
- *
- * @param items - The collection of {@link Item} objects being sent
- *
- * @throws XMPPException
- */
- public <T extends Item> void send(Collection<T> items)
- throws XMPPException
- {
- PubSub packet = createPubsubPacket(Type.SET, new PublishItem<T>(getId(), items));
-
- SyncPacketSend.getReply(con, packet);
- }
-
- /**
- * Purges the node of all items.
- *
- * <p>Note: Some implementations may keep the last item
- * sent.
- *
- * @throws XMPPException
- */
- public void deleteAllItems()
- throws XMPPException
- {
- PubSub request = createPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.PURGE_OWNER, getId()), PubSubElementType.PURGE_OWNER.getNamespace());
-
- SyncPacketSend.getReply(con, request);
- }
-
- /**
- * Delete the item with the specified id from the node.
- *
- * @param itemId The id of the item
- *
- * @throws XMPPException
- */
- public void deleteItem(String itemId)
- throws XMPPException
- {
- Collection<String> items = new ArrayList<String>(1);
- items.add(itemId);
- deleteItem(items);
- }
-
- /**
- * Delete the items with the specified id's from the node.
- *
- * @param itemIds The list of id's of items to delete
- *
- * @throws XMPPException
- */
- public void deleteItem(Collection<String> itemIds)
- throws XMPPException
- {
- List<Item> items = new ArrayList<Item>(itemIds.size());
-
- for (String id : itemIds)
- {
- items.add(new Item(id));
- }
- PubSub request = createPubsubPacket(Type.SET, new ItemsExtension(ItemsExtension.ItemsElementType.retract, getId(), items));
- SyncPacketSend.getReply(con, request);
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ.Type;
+import org.jivesoftware.smackx.packet.DiscoverItems;
+import org.jivesoftware.smackx.pubsub.packet.PubSub;
+import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
+
+/**
+ * The main class for the majority of pubsub functionality. In general
+ * almost all pubsub capabilities are related to the concept of a node.
+ * All items are published to a node, and typically subscribed to by other
+ * users. These users then retrieve events based on this subscription.
+ *
+ * @author Robin Collier
+ */
+public class LeafNode extends Node
+{
+ LeafNode(Connection connection, String nodeName)
+ {
+ super(connection, nodeName);
+ }
+
+ /**
+ * Get information on the items in the node in standard
+ * {@link DiscoverItems} format.
+ *
+ * @return The item details in {@link DiscoverItems} format
+ *
+ * @throws XMPPException
+ */
+ public DiscoverItems discoverItems()
+ throws XMPPException
+ {
+ DiscoverItems items = new DiscoverItems();
+ items.setTo(to);
+ items.setNode(getId());
+ return (DiscoverItems)SyncPacketSend.getReply(con, items);
+ }
+
+ /**
+ * Get the current items stored in the node.
+ *
+ * @return List of {@link Item} in the node
+ *
+ * @throws XMPPException
+ */
+ public <T extends Item> List<T> getItems()
+ throws XMPPException
+ {
+ PubSub request = createPubsubPacket(Type.GET, new GetItemsRequest(getId()));
+
+ PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
+ ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
+ return (List<T>)itemsElem.getItems();
+ }
+
+ /**
+ * Get the current items stored in the node based
+ * on the subscription associated with the provided
+ * subscription id.
+ *
+ * @param subscriptionId - The subscription id for the
+ * associated subscription.
+ * @return List of {@link Item} in the node
+ *
+ * @throws XMPPException
+ */
+ public <T extends Item> List<T> getItems(String subscriptionId)
+ throws XMPPException
+ {
+ PubSub request = createPubsubPacket(Type.GET, new GetItemsRequest(getId(), subscriptionId));
+
+ PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
+ ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
+ return (List<T>)itemsElem.getItems();
+ }
+
+ /**
+ * Get the items specified from the node. This would typically be
+ * used when the server does not return the payload due to size
+ * constraints. The user would be required to retrieve the payload
+ * after the items have been retrieved via {@link #getItems()} or an
+ * event, that did not include the payload.
+ *
+ * @param ids Item ids of the items to retrieve
+ *
+ * @return The list of {@link Item} with payload
+ *
+ * @throws XMPPException
+ */
+ public <T extends Item> List<T> getItems(Collection<String> ids)
+ throws XMPPException
+ {
+ List<Item> itemList = new ArrayList<Item>(ids.size());
+
+ for (String id : ids)
+ {
+ itemList.add(new Item(id));
+ }
+ PubSub request = createPubsubPacket(Type.GET, new ItemsExtension(ItemsExtension.ItemsElementType.items, getId(), itemList));
+
+ PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
+ ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
+ return (List<T>)itemsElem.getItems();
+ }
+
+ /**
+ * Get items persisted on the node, limited to the specified number.
+ *
+ * @param maxItems Maximum number of items to return
+ *
+ * @return List of {@link Item}
+ *
+ * @throws XMPPException
+ */
+ public <T extends Item> List<T> getItems(int maxItems)
+ throws XMPPException
+ {
+ PubSub request = createPubsubPacket(Type.GET, new GetItemsRequest(getId(), maxItems));
+
+ PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
+ ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
+ return (List<T>)itemsElem.getItems();
+ }
+
+ /**
+ * Get items persisted on the node, limited to the specified number
+ * based on the subscription associated with the provided subscriptionId.
+ *
+ * @param maxItems Maximum number of items to return
+ * @param subscriptionId The subscription which the retrieval is based
+ * on.
+ *
+ * @return List of {@link Item}
+ *
+ * @throws XMPPException
+ */
+ public <T extends Item> List<T> getItems(int maxItems, String subscriptionId)
+ throws XMPPException
+ {
+ PubSub request = createPubsubPacket(Type.GET, new GetItemsRequest(getId(), subscriptionId, maxItems));
+
+ PubSub result = (PubSub)SyncPacketSend.getReply(con, request);
+ ItemsExtension itemsElem = (ItemsExtension)result.getExtension(PubSubElementType.ITEMS);
+ return (List<T>)itemsElem.getItems();
+ }
+
+ /**
+ * Publishes an event to the node. This is an empty event
+ * with no item.
+ *
+ * This is only acceptable for nodes with {@link ConfigureForm#isPersistItems()}=false
+ * and {@link ConfigureForm#isDeliverPayloads()}=false.
+ *
+ * This is an asynchronous call which returns as soon as the
+ * packet has been sent.
+ *
+ * For synchronous calls use {@link #send() send()}.
+ */
+ public void publish()
+ {
+ PubSub packet = createPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.PUBLISH, getId()));
+
+ con.sendPacket(packet);
+ }
+
+ /**
+ * Publishes an event to the node. This is a simple item
+ * with no payload.
+ *
+ * If the id is null, an empty item (one without an id) will be sent.
+ * Please note that this is not the same as {@link #send()}, which
+ * publishes an event with NO item.
+ *
+ * This is an asynchronous call which returns as soon as the
+ * packet has been sent.
+ *
+ * For synchronous calls use {@link #send(Item) send(Item))}.
+ *
+ * @param item - The item being sent
+ */
+ public <T extends Item> void publish(T item)
+ {
+ Collection<T> items = new ArrayList<T>(1);
+ items.add((T)(item == null ? new Item() : item));
+ publish(items);
+ }
+
+ /**
+ * Publishes multiple events to the node. Same rules apply as in {@link #publish(Item)}.
+ *
+ * In addition, if {@link ConfigureForm#isPersistItems()}=false, only the last item in the input
+ * list will get stored on the node, assuming it stores the last sent item.
+ *
+ * This is an asynchronous call which returns as soon as the
+ * packet has been sent.
+ *
+ * For synchronous calls use {@link #send(Collection) send(Collection))}.
+ *
+ * @param items - The collection of items being sent
+ */
+ public <T extends Item> void publish(Collection<T> items)
+ {
+ PubSub packet = createPubsubPacket(Type.SET, new PublishItem<T>(getId(), items));
+
+ con.sendPacket(packet);
+ }
+
+ /**
+ * Publishes an event to the node. This is an empty event
+ * with no item.
+ *
+ * This is only acceptable for nodes with {@link ConfigureForm#isPersistItems()}=false
+ * and {@link ConfigureForm#isDeliverPayloads()}=false.
+ *
+ * This is a synchronous call which will throw an exception
+ * on failure.
+ *
+ * For asynchronous calls, use {@link #publish() publish()}.
+ *
+ * @throws XMPPException
+ */
+ public void send()
+ throws XMPPException
+ {
+ PubSub packet = createPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.PUBLISH, getId()));
+
+ SyncPacketSend.getReply(con, packet);
+ }
+
+ /**
+ * Publishes an event to the node. This can be either a simple item
+ * with no payload, or one with it. This is determined by the Node
+ * configuration.
+ *
+ * If the node has <b>deliver_payload=false</b>, the Item must not
+ * have a payload.
+ *
+ * If the id is null, an empty item (one without an id) will be sent.
+ * Please note that this is not the same as {@link #send()}, which
+ * publishes an event with NO item.
+ *
+ * This is a synchronous call which will throw an exception
+ * on failure.
+ *
+ * For asynchronous calls, use {@link #publish(Item) publish(Item)}.
+ *
+ * @param item - The item being sent
+ *
+ * @throws XMPPException
+ */
+ public <T extends Item> void send(T item)
+ throws XMPPException
+ {
+ Collection<T> items = new ArrayList<T>(1);
+ items.add((item == null ? (T)new Item() : item));
+ send(items);
+ }
+
+ /**
+ * Publishes multiple events to the node. Same rules apply as in {@link #send(Item)}.
+ *
+ * In addition, if {@link ConfigureForm#isPersistItems()}=false, only the last item in the input
+ * list will get stored on the node, assuming it stores the last sent item.
+ *
+ * This is a synchronous call which will throw an exception
+ * on failure.
+ *
+ * For asynchronous calls, use {@link #publish(Collection) publish(Collection))}.
+ *
+ * @param items - The collection of {@link Item} objects being sent
+ *
+ * @throws XMPPException
+ */
+ public <T extends Item> void send(Collection<T> items)
+ throws XMPPException
+ {
+ PubSub packet = createPubsubPacket(Type.SET, new PublishItem<T>(getId(), items));
+
+ SyncPacketSend.getReply(con, packet);
+ }
+
+ /**
+ * Purges the node of all items.
+ *
+ * <p>Note: Some implementations may keep the last item
+ * sent.
+ *
+ * @throws XMPPException
+ */
+ public void deleteAllItems()
+ throws XMPPException
+ {
+ PubSub request = createPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.PURGE_OWNER, getId()), PubSubElementType.PURGE_OWNER.getNamespace());
+
+ SyncPacketSend.getReply(con, request);
+ }
+
+ /**
+ * Delete the item with the specified id from the node.
+ *
+ * @param itemId The id of the item
+ *
+ * @throws XMPPException
+ */
+ public void deleteItem(String itemId)
+ throws XMPPException
+ {
+ Collection<String> items = new ArrayList<String>(1);
+ items.add(itemId);
+ deleteItem(items);
+ }
+
+ /**
+ * Delete the items with the specified id's from the node.
+ *
+ * @param itemIds The list of id's of items to delete
+ *
+ * @throws XMPPException
+ */
+ public void deleteItem(Collection<String> itemIds)
+ throws XMPPException
+ {
+ List<Item> items = new ArrayList<Item>(itemIds.size());
+
+ for (String id : itemIds)
+ {
+ items.add(new Item(id));
+ }
+ PubSub request = createPubsubPacket(Type.SET, new ItemsExtension(ItemsExtension.ItemsElementType.retract, getId(), items));
+ SyncPacketSend.getReply(con, request);
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Node.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Node.java
index 1b0ff5afd..3e745f3aa 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Node.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Node.java
@@ -17,525 +17,525 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smackx.pubsub;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.OrFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.packet.Message;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.packet.IQ.Type;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.packet.DelayInformation;
-import org.jivesoftware.smackx.packet.DiscoverInfo;
-import org.jivesoftware.smackx.packet.Header;
-import org.jivesoftware.smackx.packet.HeadersExtension;
-import org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener;
-import org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
-import org.jivesoftware.smackx.pubsub.listener.NodeConfigListener;
-import org.jivesoftware.smackx.pubsub.packet.PubSub;
-import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
-import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
-import org.jivesoftware.smackx.pubsub.util.NodeUtils;
-
-abstract public class Node
-{
- protected Connection con;
- protected String id;
- protected String to;
-
- protected ConcurrentHashMap<ItemEventListener<Item>, PacketListener> itemEventToListenerMap = new ConcurrentHashMap<ItemEventListener<Item>, PacketListener>();
- protected ConcurrentHashMap<ItemDeleteListener, PacketListener> itemDeleteToListenerMap = new ConcurrentHashMap<ItemDeleteListener, PacketListener>();
- protected ConcurrentHashMap<NodeConfigListener, PacketListener> configEventToListenerMap = new ConcurrentHashMap<NodeConfigListener, PacketListener>();
-
- /**
- * Construct a node associated to the supplied connection with the specified
- * node id.
- *
- * @param connection The connection the node is associated with
- * @param nodeName The node id
- */
- Node(Connection connection, String nodeName)
- {
- con = connection;
- id = nodeName;
- }
-
- /**
- * Some XMPP servers may require a specific service to be addressed on the
- * server.
- *
- * For example, OpenFire requires the server to be prefixed by <b>pubsub</b>
- */
- void setTo(String toAddress)
- {
- to = toAddress;
- }
-
- /**
- * Get the NodeId
- *
- * @return the node id
- */
- public String getId()
- {
- return id;
- }
- /**
- * Returns a configuration form, from which you can create an answer form to be submitted
- * via the {@link #sendConfigurationForm(Form)}.
- *
- * @return the configuration form
- */
- public ConfigureForm getNodeConfiguration()
- throws XMPPException
- {
- Packet reply = sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.CONFIGURE_OWNER, getId()), PubSubNamespace.OWNER);
- return NodeUtils.getFormFromPacket(reply, PubSubElementType.CONFIGURE_OWNER);
- }
-
- /**
- * Update the configuration with the contents of the new {@link Form}
- *
- * @param submitForm
- */
- public void sendConfigurationForm(Form submitForm)
- throws XMPPException
- {
- PubSub packet = createPubsubPacket(Type.SET, new FormNode(FormNodeType.CONFIGURE_OWNER, getId(), submitForm), PubSubNamespace.OWNER);
- SyncPacketSend.getReply(con, packet);
- }
-
- /**
- * Discover node information in standard {@link DiscoverInfo} format.
- *
- * @return The discovery information about the node.
- *
- * @throws XMPPException
- */
- public DiscoverInfo discoverInfo()
- throws XMPPException
- {
- DiscoverInfo info = new DiscoverInfo();
- info.setTo(to);
- info.setNode(getId());
- return (DiscoverInfo)SyncPacketSend.getReply(con, info);
- }
-
- /**
- * Get the subscriptions currently associated with this node.
- *
- * @return List of {@link Subscription}
- *
- * @throws XMPPException
- */
- public List<Subscription> getSubscriptions()
- throws XMPPException
- {
- PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.SUBSCRIPTIONS, getId()));
- SubscriptionsExtension subElem = (SubscriptionsExtension)reply.getExtension(PubSubElementType.SUBSCRIPTIONS);
- return subElem.getSubscriptions();
- }
-
- /**
- * The user subscribes to the node using the supplied jid. The
- * bare jid portion of this one must match the jid for the connection.
- *
- * Please note that the {@link Subscription.State} should be checked
- * on return since more actions may be required by the caller.
- * {@link Subscription.State#pending} - The owner must approve the subscription
- * request before messages will be received.
- * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
- * the caller must configure the subscription before messages will be received. If it is false
- * the caller can configure it but is not required to do so.
- * @param jid The jid to subscribe as.
- * @return The subscription
- * @exception XMPPException
- */
- public Subscription subscribe(String jid)
- throws XMPPException
- {
- PubSub reply = (PubSub)sendPubsubPacket(Type.SET, new SubscribeExtension(jid, getId()));
- return (Subscription)reply.getExtension(PubSubElementType.SUBSCRIPTION);
- }
-
- /**
- * The user subscribes to the node using the supplied jid and subscription
- * options. The bare jid portion of this one must match the jid for the
- * connection.
- *
- * Please note that the {@link Subscription.State} should be checked
- * on return since more actions may be required by the caller.
- * {@link Subscription.State#pending} - The owner must approve the subscription
- * request before messages will be received.
- * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
- * the caller must configure the subscription before messages will be received. If it is false
- * the caller can configure it but is not required to do so.
- * @param jid The jid to subscribe as.
- * @return The subscription
- * @exception XMPPException
- */
- public Subscription subscribe(String jid, SubscribeForm subForm)
- throws XMPPException
- {
- PubSub request = createPubsubPacket(Type.SET, new SubscribeExtension(jid, getId()));
- request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm));
- PubSub reply = (PubSub)PubSubManager.sendPubsubPacket(con, jid, Type.SET, request);
- return (Subscription)reply.getExtension(PubSubElementType.SUBSCRIPTION);
- }
-
- /**
- * Remove the subscription related to the specified JID. This will only
- * work if there is only 1 subscription. If there are multiple subscriptions,
- * use {@link #unsubscribe(String, String)}.
- *
- * @param jid The JID used to subscribe to the node
- *
- * @throws XMPPException
- */
- public void unsubscribe(String jid)
- throws XMPPException
- {
- unsubscribe(jid, null);
- }
-
- /**
- * Remove the specific subscription related to the specified JID.
- *
- * @param jid The JID used to subscribe to the node
- * @param subscriptionId The id of the subscription being removed
- *
- * @throws XMPPException
- */
- public void unsubscribe(String jid, String subscriptionId)
- throws XMPPException
- {
- sendPubsubPacket(Type.SET, new UnsubscribeExtension(jid, getId(), subscriptionId));
- }
-
- /**
- * Returns a SubscribeForm for subscriptions, from which you can create an answer form to be submitted
- * via the {@link #sendConfigurationForm(Form)}.
- *
- * @return A subscription options form
- *
- * @throws XMPPException
- */
- public SubscribeForm getSubscriptionOptions(String jid)
- throws XMPPException
- {
- return getSubscriptionOptions(jid, null);
- }
-
-
- /**
- * Get the options for configuring the specified subscription.
- *
- * @param jid JID the subscription is registered under
- * @param subscriptionId The subscription id
- *
- * @return The subscription option form
- *
- * @throws XMPPException
- */
- public SubscribeForm getSubscriptionOptions(String jid, String subscriptionId)
- throws XMPPException
- {
- PubSub packet = (PubSub)sendPubsubPacket(Type.GET, new OptionsExtension(jid, getId(), subscriptionId));
- FormNode ext = (FormNode)packet.getExtension(PubSubElementType.OPTIONS);
- return new SubscribeForm(ext.getForm());
- }
-
- /**
- * Register a listener for item publication events. This
- * listener will get called whenever an item is published to
- * this node.
- *
- * @param listener The handler for the event
- */
- public void addItemEventListener(ItemEventListener listener)
- {
- PacketListener conListener = new ItemEventTranslator(listener);
- itemEventToListenerMap.put(listener, conListener);
- con.addPacketListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item"));
- }
-
- /**
- * Unregister a listener for publication events.
- *
- * @param listener The handler to unregister
- */
- public void removeItemEventListener(ItemEventListener listener)
- {
- PacketListener conListener = itemEventToListenerMap.remove(listener);
-
- if (conListener != null)
- con.removePacketListener(conListener);
- }
-
- /**
- * Register a listener for configuration events. This listener
- * will get called whenever the node's configuration changes.
- *
- * @param listener The handler for the event
- */
- public void addConfigurationListener(NodeConfigListener listener)
- {
- PacketListener conListener = new NodeConfigTranslator(listener);
- configEventToListenerMap.put(listener, conListener);
- con.addPacketListener(conListener, new EventContentFilter(EventElementType.configuration.toString()));
- }
-
- /**
- * Unregister a listener for configuration events.
- *
- * @param listener The handler to unregister
- */
- public void removeConfigurationListener(NodeConfigListener listener)
- {
- PacketListener conListener = configEventToListenerMap .remove(listener);
-
- if (conListener != null)
- con.removePacketListener(conListener);
- }
-
- /**
- * Register an listener for item delete events. This listener
- * gets called whenever an item is deleted from the node.
- *
- * @param listener The handler for the event
- */
- public void addItemDeleteListener(ItemDeleteListener listener)
- {
- PacketListener delListener = new ItemDeleteTranslator(listener);
- itemDeleteToListenerMap.put(listener, delListener);
- EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract");
- EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString());
-
- con.addPacketListener(delListener, new OrFilter(deleteItem, purge));
- }
-
- /**
- * Unregister a listener for item delete events.
- *
- * @param listener The handler to unregister
- */
- public void removeItemDeleteListener(ItemDeleteListener listener)
- {
- PacketListener conListener = itemDeleteToListenerMap .remove(listener);
-
- if (conListener != null)
- con.removePacketListener(conListener);
- }
-
- @Override
- public String toString()
- {
- return super.toString() + " " + getClass().getName() + " id: " + id;
- }
-
- protected PubSub createPubsubPacket(Type type, PacketExtension ext)
- {
- return createPubsubPacket(type, ext, null);
- }
-
- protected PubSub createPubsubPacket(Type type, PacketExtension ext, PubSubNamespace ns)
- {
- return PubSubManager.createPubsubPacket(to, type, ext, ns);
- }
-
- protected Packet sendPubsubPacket(Type type, NodeExtension ext)
- throws XMPPException
- {
- return PubSubManager.sendPubsubPacket(con, to, type, ext);
- }
-
- protected Packet sendPubsubPacket(Type type, NodeExtension ext, PubSubNamespace ns)
- throws XMPPException
- {
- return PubSubManager.sendPubsubPacket(con, to, type, ext, ns);
- }
-
-
- private static List<String> getSubscriptionIds(Packet packet)
- {
- HeadersExtension headers = (HeadersExtension)packet.getExtension("headers", "http://jabber.org/protocol/shim");
- List<String> values = null;
-
- if (headers != null)
- {
- values = new ArrayList<String>(headers.getHeaders().size());
-
- for (Header header : headers.getHeaders())
- {
- values.add(header.getValue());
- }
- }
- return values;
- }
-
- /**
- * This class translates low level item publication events into api level objects for
- * user consumption.
- *
- * @author Robin Collier
- */
- public class ItemEventTranslator implements PacketListener
- {
- private ItemEventListener listener;
-
- public ItemEventTranslator(ItemEventListener eventListener)
- {
- listener = eventListener;
- }
-
- public void processPacket(Packet packet)
- {
- EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
- ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
- DelayInformation delay = (DelayInformation)packet.getExtension("delay", "urn:xmpp:delay");
-
- // If there was no delay based on XEP-0203, then try XEP-0091 for backward compatibility
- if (delay == null)
- {
- delay = (DelayInformation)packet.getExtension("x", "jabber:x:delay");
- }
- ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), (List<Item>)itemsElem.getItems(), getSubscriptionIds(packet), (delay == null ? null : delay.getStamp()));
- listener.handlePublishedItems(eventItems);
- }
- }
-
- /**
- * This class translates low level item deletion events into api level objects for
- * user consumption.
- *
- * @author Robin Collier
- */
- public class ItemDeleteTranslator implements PacketListener
- {
- private ItemDeleteListener listener;
-
- public ItemDeleteTranslator(ItemDeleteListener eventListener)
- {
- listener = eventListener;
- }
-
- public void processPacket(Packet packet)
- {
- EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
-
- List<PacketExtension> extList = event.getExtensions();
-
- if (extList.get(0).getElementName().equals(PubSubElementType.PURGE_EVENT.getElementName()))
- {
- listener.handlePurge();
- }
- else
- {
- ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
- Collection<? extends PacketExtension> pubItems = itemsElem.getItems();
- Iterator<RetractItem> it = (Iterator<RetractItem>)pubItems.iterator();
- List<String> items = new ArrayList<String>(pubItems.size());
-
- while (it.hasNext())
- {
- RetractItem item = it.next();
- items.add(item.getId());
- }
-
- ItemDeleteEvent eventItems = new ItemDeleteEvent(itemsElem.getNode(), items, getSubscriptionIds(packet));
- listener.handleDeletedItems(eventItems);
- }
- }
- }
-
- /**
- * This class translates low level node configuration events into api level objects for
- * user consumption.
- *
- * @author Robin Collier
- */
- public class NodeConfigTranslator implements PacketListener
- {
- private NodeConfigListener listener;
-
- public NodeConfigTranslator(NodeConfigListener eventListener)
- {
- listener = eventListener;
- }
-
- public void processPacket(Packet packet)
- {
- EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
- ConfigurationEvent config = (ConfigurationEvent)event.getEvent();
-
- listener.handleNodeConfiguration(config);
- }
- }
-
- /**
- * Filter for {@link PacketListener} to filter out events not specific to the
- * event type expected for this node.
- *
- * @author Robin Collier
- */
- class EventContentFilter implements PacketFilter
- {
- private String firstElement;
- private String secondElement;
-
- EventContentFilter(String elementName)
- {
- firstElement = elementName;
- }
-
- EventContentFilter(String firstLevelEelement, String secondLevelElement)
- {
- firstElement = firstLevelEelement;
- secondElement = secondLevelElement;
- }
-
- public boolean accept(Packet packet)
- {
- if (!(packet instanceof Message))
- return false;
-
- EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
-
- if (event == null)
- return false;
-
- NodeExtension embedEvent = event.getEvent();
-
- if (embedEvent == null)
- return false;
-
- if (embedEvent.getElementName().equals(firstElement))
- {
- if (!embedEvent.getNode().equals(getId()))
- return false;
-
- if (secondElement == null)
- return true;
-
- if (embedEvent instanceof EmbeddedPacketExtension)
- {
- List<PacketExtension> secondLevelList = ((EmbeddedPacketExtension)embedEvent).getExtensions();
-
- if (secondLevelList.size() > 0 && secondLevelList.get(0).getElementName().equals(secondElement))
- return true;
- }
- }
- return false;
- }
- }
-}
+package org.jivesoftware.smackx.pubsub;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.OrFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.packet.IQ.Type;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.packet.DelayInformation;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
+import org.jivesoftware.smackx.packet.Header;
+import org.jivesoftware.smackx.packet.HeadersExtension;
+import org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener;
+import org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
+import org.jivesoftware.smackx.pubsub.listener.NodeConfigListener;
+import org.jivesoftware.smackx.pubsub.packet.PubSub;
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
+import org.jivesoftware.smackx.pubsub.util.NodeUtils;
+
+abstract public class Node
+{
+ protected Connection con;
+ protected String id;
+ protected String to;
+
+ protected ConcurrentHashMap<ItemEventListener<Item>, PacketListener> itemEventToListenerMap = new ConcurrentHashMap<ItemEventListener<Item>, PacketListener>();
+ protected ConcurrentHashMap<ItemDeleteListener, PacketListener> itemDeleteToListenerMap = new ConcurrentHashMap<ItemDeleteListener, PacketListener>();
+ protected ConcurrentHashMap<NodeConfigListener, PacketListener> configEventToListenerMap = new ConcurrentHashMap<NodeConfigListener, PacketListener>();
+
+ /**
+ * Construct a node associated to the supplied connection with the specified
+ * node id.
+ *
+ * @param connection The connection the node is associated with
+ * @param nodeName The node id
+ */
+ Node(Connection connection, String nodeName)
+ {
+ con = connection;
+ id = nodeName;
+ }
+
+ /**
+ * Some XMPP servers may require a specific service to be addressed on the
+ * server.
+ *
+ * For example, OpenFire requires the server to be prefixed by <b>pubsub</b>
+ */
+ void setTo(String toAddress)
+ {
+ to = toAddress;
+ }
+
+ /**
+ * Get the NodeId
+ *
+ * @return the node id
+ */
+ public String getId()
+ {
+ return id;
+ }
+ /**
+ * Returns a configuration form, from which you can create an answer form to be submitted
+ * via the {@link #sendConfigurationForm(Form)}.
+ *
+ * @return the configuration form
+ */
+ public ConfigureForm getNodeConfiguration()
+ throws XMPPException
+ {
+ Packet reply = sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.CONFIGURE_OWNER, getId()), PubSubNamespace.OWNER);
+ return NodeUtils.getFormFromPacket(reply, PubSubElementType.CONFIGURE_OWNER);
+ }
+
+ /**
+ * Update the configuration with the contents of the new {@link Form}
+ *
+ * @param submitForm
+ */
+ public void sendConfigurationForm(Form submitForm)
+ throws XMPPException
+ {
+ PubSub packet = createPubsubPacket(Type.SET, new FormNode(FormNodeType.CONFIGURE_OWNER, getId(), submitForm), PubSubNamespace.OWNER);
+ SyncPacketSend.getReply(con, packet);
+ }
+
+ /**
+ * Discover node information in standard {@link DiscoverInfo} format.
+ *
+ * @return The discovery information about the node.
+ *
+ * @throws XMPPException
+ */
+ public DiscoverInfo discoverInfo()
+ throws XMPPException
+ {
+ DiscoverInfo info = new DiscoverInfo();
+ info.setTo(to);
+ info.setNode(getId());
+ return (DiscoverInfo)SyncPacketSend.getReply(con, info);
+ }
+
+ /**
+ * Get the subscriptions currently associated with this node.
+ *
+ * @return List of {@link Subscription}
+ *
+ * @throws XMPPException
+ */
+ public List<Subscription> getSubscriptions()
+ throws XMPPException
+ {
+ PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.SUBSCRIPTIONS, getId()));
+ SubscriptionsExtension subElem = (SubscriptionsExtension)reply.getExtension(PubSubElementType.SUBSCRIPTIONS);
+ return subElem.getSubscriptions();
+ }
+
+ /**
+ * The user subscribes to the node using the supplied jid. The
+ * bare jid portion of this one must match the jid for the connection.
+ *
+ * Please note that the {@link Subscription.State} should be checked
+ * on return since more actions may be required by the caller.
+ * {@link Subscription.State#pending} - The owner must approve the subscription
+ * request before messages will be received.
+ * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
+ * the caller must configure the subscription before messages will be received. If it is false
+ * the caller can configure it but is not required to do so.
+ * @param jid The jid to subscribe as.
+ * @return The subscription
+ * @exception XMPPException
+ */
+ public Subscription subscribe(String jid)
+ throws XMPPException
+ {
+ PubSub reply = (PubSub)sendPubsubPacket(Type.SET, new SubscribeExtension(jid, getId()));
+ return (Subscription)reply.getExtension(PubSubElementType.SUBSCRIPTION);
+ }
+
+ /**
+ * The user subscribes to the node using the supplied jid and subscription
+ * options. The bare jid portion of this one must match the jid for the
+ * connection.
+ *
+ * Please note that the {@link Subscription.State} should be checked
+ * on return since more actions may be required by the caller.
+ * {@link Subscription.State#pending} - The owner must approve the subscription
+ * request before messages will be received.
+ * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
+ * the caller must configure the subscription before messages will be received. If it is false
+ * the caller can configure it but is not required to do so.
+ * @param jid The jid to subscribe as.
+ * @return The subscription
+ * @exception XMPPException
+ */
+ public Subscription subscribe(String jid, SubscribeForm subForm)
+ throws XMPPException
+ {
+ PubSub request = createPubsubPacket(Type.SET, new SubscribeExtension(jid, getId()));
+ request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm));
+ PubSub reply = (PubSub)PubSubManager.sendPubsubPacket(con, jid, Type.SET, request);
+ return (Subscription)reply.getExtension(PubSubElementType.SUBSCRIPTION);
+ }
+
+ /**
+ * Remove the subscription related to the specified JID. This will only
+ * work if there is only 1 subscription. If there are multiple subscriptions,
+ * use {@link #unsubscribe(String, String)}.
+ *
+ * @param jid The JID used to subscribe to the node
+ *
+ * @throws XMPPException
+ */
+ public void unsubscribe(String jid)
+ throws XMPPException
+ {
+ unsubscribe(jid, null);
+ }
+
+ /**
+ * Remove the specific subscription related to the specified JID.
+ *
+ * @param jid The JID used to subscribe to the node
+ * @param subscriptionId The id of the subscription being removed
+ *
+ * @throws XMPPException
+ */
+ public void unsubscribe(String jid, String subscriptionId)
+ throws XMPPException
+ {
+ sendPubsubPacket(Type.SET, new UnsubscribeExtension(jid, getId(), subscriptionId));
+ }
+
+ /**
+ * Returns a SubscribeForm for subscriptions, from which you can create an answer form to be submitted
+ * via the {@link #sendConfigurationForm(Form)}.
+ *
+ * @return A subscription options form
+ *
+ * @throws XMPPException
+ */
+ public SubscribeForm getSubscriptionOptions(String jid)
+ throws XMPPException
+ {
+ return getSubscriptionOptions(jid, null);
+ }
+
+
+ /**
+ * Get the options for configuring the specified subscription.
+ *
+ * @param jid JID the subscription is registered under
+ * @param subscriptionId The subscription id
+ *
+ * @return The subscription option form
+ *
+ * @throws XMPPException
+ */
+ public SubscribeForm getSubscriptionOptions(String jid, String subscriptionId)
+ throws XMPPException
+ {
+ PubSub packet = (PubSub)sendPubsubPacket(Type.GET, new OptionsExtension(jid, getId(), subscriptionId));
+ FormNode ext = (FormNode)packet.getExtension(PubSubElementType.OPTIONS);
+ return new SubscribeForm(ext.getForm());
+ }
+
+ /**
+ * Register a listener for item publication events. This
+ * listener will get called whenever an item is published to
+ * this node.
+ *
+ * @param listener The handler for the event
+ */
+ public void addItemEventListener(ItemEventListener listener)
+ {
+ PacketListener conListener = new ItemEventTranslator(listener);
+ itemEventToListenerMap.put(listener, conListener);
+ con.addPacketListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item"));
+ }
+
+ /**
+ * Unregister a listener for publication events.
+ *
+ * @param listener The handler to unregister
+ */
+ public void removeItemEventListener(ItemEventListener listener)
+ {
+ PacketListener conListener = itemEventToListenerMap.remove(listener);
+
+ if (conListener != null)
+ con.removePacketListener(conListener);
+ }
+
+ /**
+ * Register a listener for configuration events. This listener
+ * will get called whenever the node's configuration changes.
+ *
+ * @param listener The handler for the event
+ */
+ public void addConfigurationListener(NodeConfigListener listener)
+ {
+ PacketListener conListener = new NodeConfigTranslator(listener);
+ configEventToListenerMap.put(listener, conListener);
+ con.addPacketListener(conListener, new EventContentFilter(EventElementType.configuration.toString()));
+ }
+
+ /**
+ * Unregister a listener for configuration events.
+ *
+ * @param listener The handler to unregister
+ */
+ public void removeConfigurationListener(NodeConfigListener listener)
+ {
+ PacketListener conListener = configEventToListenerMap .remove(listener);
+
+ if (conListener != null)
+ con.removePacketListener(conListener);
+ }
+
+ /**
+ * Register an listener for item delete events. This listener
+ * gets called whenever an item is deleted from the node.
+ *
+ * @param listener The handler for the event
+ */
+ public void addItemDeleteListener(ItemDeleteListener listener)
+ {
+ PacketListener delListener = new ItemDeleteTranslator(listener);
+ itemDeleteToListenerMap.put(listener, delListener);
+ EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract");
+ EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString());
+
+ con.addPacketListener(delListener, new OrFilter(deleteItem, purge));
+ }
+
+ /**
+ * Unregister a listener for item delete events.
+ *
+ * @param listener The handler to unregister
+ */
+ public void removeItemDeleteListener(ItemDeleteListener listener)
+ {
+ PacketListener conListener = itemDeleteToListenerMap .remove(listener);
+
+ if (conListener != null)
+ con.removePacketListener(conListener);
+ }
+
+ @Override
+ public String toString()
+ {
+ return super.toString() + " " + getClass().getName() + " id: " + id;
+ }
+
+ protected PubSub createPubsubPacket(Type type, PacketExtension ext)
+ {
+ return createPubsubPacket(type, ext, null);
+ }
+
+ protected PubSub createPubsubPacket(Type type, PacketExtension ext, PubSubNamespace ns)
+ {
+ return PubSubManager.createPubsubPacket(to, type, ext, ns);
+ }
+
+ protected Packet sendPubsubPacket(Type type, NodeExtension ext)
+ throws XMPPException
+ {
+ return PubSubManager.sendPubsubPacket(con, to, type, ext);
+ }
+
+ protected Packet sendPubsubPacket(Type type, NodeExtension ext, PubSubNamespace ns)
+ throws XMPPException
+ {
+ return PubSubManager.sendPubsubPacket(con, to, type, ext, ns);
+ }
+
+
+ private static List<String> getSubscriptionIds(Packet packet)
+ {
+ HeadersExtension headers = (HeadersExtension)packet.getExtension("headers", "http://jabber.org/protocol/shim");
+ List<String> values = null;
+
+ if (headers != null)
+ {
+ values = new ArrayList<String>(headers.getHeaders().size());
+
+ for (Header header : headers.getHeaders())
+ {
+ values.add(header.getValue());
+ }
+ }
+ return values;
+ }
+
+ /**
+ * This class translates low level item publication events into api level objects for
+ * user consumption.
+ *
+ * @author Robin Collier
+ */
+ public class ItemEventTranslator implements PacketListener
+ {
+ private ItemEventListener listener;
+
+ public ItemEventTranslator(ItemEventListener eventListener)
+ {
+ listener = eventListener;
+ }
+
+ public void processPacket(Packet packet)
+ {
+ EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
+ ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
+ DelayInformation delay = (DelayInformation)packet.getExtension("delay", "urn:xmpp:delay");
+
+ // If there was no delay based on XEP-0203, then try XEP-0091 for backward compatibility
+ if (delay == null)
+ {
+ delay = (DelayInformation)packet.getExtension("x", "jabber:x:delay");
+ }
+ ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), (List<Item>)itemsElem.getItems(), getSubscriptionIds(packet), (delay == null ? null : delay.getStamp()));
+ listener.handlePublishedItems(eventItems);
+ }
+ }
+
+ /**
+ * This class translates low level item deletion events into api level objects for
+ * user consumption.
+ *
+ * @author Robin Collier
+ */
+ public class ItemDeleteTranslator implements PacketListener
+ {
+ private ItemDeleteListener listener;
+
+ public ItemDeleteTranslator(ItemDeleteListener eventListener)
+ {
+ listener = eventListener;
+ }
+
+ public void processPacket(Packet packet)
+ {
+ EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
+
+ List<PacketExtension> extList = event.getExtensions();
+
+ if (extList.get(0).getElementName().equals(PubSubElementType.PURGE_EVENT.getElementName()))
+ {
+ listener.handlePurge();
+ }
+ else
+ {
+ ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
+ Collection<? extends PacketExtension> pubItems = itemsElem.getItems();
+ Iterator<RetractItem> it = (Iterator<RetractItem>)pubItems.iterator();
+ List<String> items = new ArrayList<String>(pubItems.size());
+
+ while (it.hasNext())
+ {
+ RetractItem item = it.next();
+ items.add(item.getId());
+ }
+
+ ItemDeleteEvent eventItems = new ItemDeleteEvent(itemsElem.getNode(), items, getSubscriptionIds(packet));
+ listener.handleDeletedItems(eventItems);
+ }
+ }
+ }
+
+ /**
+ * This class translates low level node configuration events into api level objects for
+ * user consumption.
+ *
+ * @author Robin Collier
+ */
+ public class NodeConfigTranslator implements PacketListener
+ {
+ private NodeConfigListener listener;
+
+ public NodeConfigTranslator(NodeConfigListener eventListener)
+ {
+ listener = eventListener;
+ }
+
+ public void processPacket(Packet packet)
+ {
+ EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
+ ConfigurationEvent config = (ConfigurationEvent)event.getEvent();
+
+ listener.handleNodeConfiguration(config);
+ }
+ }
+
+ /**
+ * Filter for {@link PacketListener} to filter out events not specific to the
+ * event type expected for this node.
+ *
+ * @author Robin Collier
+ */
+ class EventContentFilter implements PacketFilter
+ {
+ private String firstElement;
+ private String secondElement;
+
+ EventContentFilter(String elementName)
+ {
+ firstElement = elementName;
+ }
+
+ EventContentFilter(String firstLevelEelement, String secondLevelElement)
+ {
+ firstElement = firstLevelEelement;
+ secondElement = secondLevelElement;
+ }
+
+ public boolean accept(Packet packet)
+ {
+ if (!(packet instanceof Message))
+ return false;
+
+ EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
+
+ if (event == null)
+ return false;
+
+ NodeExtension embedEvent = event.getEvent();
+
+ if (embedEvent == null)
+ return false;
+
+ if (embedEvent.getElementName().equals(firstElement))
+ {
+ if (!embedEvent.getNode().equals(getId()))
+ return false;
+
+ if (secondElement == null)
+ return true;
+
+ if (embedEvent instanceof EmbeddedPacketExtension)
+ {
+ List<PacketExtension> secondLevelList = ((EmbeddedPacketExtension)embedEvent).getExtensions();
+
+ if (secondLevelList.size() > 0 && secondLevelList.get(0).getElementName().equals(secondElement))
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeEvent.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeEvent.java
index 1392e851e..d55e21856 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeEvent.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeEvent.java
@@ -17,19 +17,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.jivesoftware.smackx.pubsub;
-
-abstract public class NodeEvent
-{
- private String nodeId;
-
- protected NodeEvent(String id)
- {
- nodeId = id;
- }
-
- public String getNodeId()
- {
- return nodeId;
- }
-}
+package org.jivesoftware.smackx.pubsub;
+
+abstract public class NodeEvent
+{
+ private String nodeId;
+
+ protected NodeEvent(String id)
+ {
+ nodeId = id;
+ }
+
+ public String getNodeId()
+ {
+ return nodeId;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeExtension.java
index 7e4cdecbb..9a3e4805f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeExtension.java
@@ -1,85 +1,85 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * A class which represents a common element within the pubsub defined
- * schemas. One which has a <b>node</b> as an attribute. This class is
- * used on its own as well as a base class for many others, since the
- * node is a central concept to most pubsub functionality.
- *
- * @author Robin Collier
- */
-public class NodeExtension implements PacketExtension
-{
- private PubSubElementType element;
- private String node;
-
- /**
- * Constructs a <tt>NodeExtension</tt> with an element name specified
- * by {@link PubSubElementType} and the specified node id.
- *
- * @param elem Defines the element name and namespace
- * @param nodeId Specifies the id of the node
- */
- public NodeExtension(PubSubElementType elem, String nodeId)
- {
- element = elem;
- this.node = nodeId;
- }
-
- /**
- * Constructs a <tt>NodeExtension</tt> with an element name specified
- * by {@link PubSubElementType}.
- *
- * @param elem Defines the element name and namespace
- */
- public NodeExtension(PubSubElementType elem)
- {
- this(elem, null);
- }
-
- /**
- * Gets the node id
- *
- * @return The node id
- */
- public String getNode()
- {
- return node;
- }
-
- public String getElementName()
- {
- return element.getElementName();
- }
-
- public String getNamespace()
- {
- return element.getNamespace().getXmlns();
- }
-
- public String toXML()
- {
- return '<' + getElementName() + (node == null ? "" : " node='" + node + '\'') + "/>";
- }
-
- @Override
- public String toString()
- {
- return getClass().getName() + " - content [" + toXML() + "]";
- }
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * A class which represents a common element within the pubsub defined
+ * schemas. One which has a <b>node</b> as an attribute. This class is
+ * used on its own as well as a base class for many others, since the
+ * node is a central concept to most pubsub functionality.
+ *
+ * @author Robin Collier
+ */
+public class NodeExtension implements PacketExtension
+{
+ private PubSubElementType element;
+ private String node;
+
+ /**
+ * Constructs a <tt>NodeExtension</tt> with an element name specified
+ * by {@link PubSubElementType} and the specified node id.
+ *
+ * @param elem Defines the element name and namespace
+ * @param nodeId Specifies the id of the node
+ */
+ public NodeExtension(PubSubElementType elem, String nodeId)
+ {
+ element = elem;
+ this.node = nodeId;
+ }
+
+ /**
+ * Constructs a <tt>NodeExtension</tt> with an element name specified
+ * by {@link PubSubElementType}.
+ *
+ * @param elem Defines the element name and namespace
+ */
+ public NodeExtension(PubSubElementType elem)
+ {
+ this(elem, null);
+ }
+
+ /**
+ * Gets the node id
+ *
+ * @return The node id
+ */
+ public String getNode()
+ {
+ return node;
+ }
+
+ public String getElementName()
+ {
+ return element.getElementName();
+ }
+
+ public String getNamespace()
+ {
+ return element.getNamespace().getXmlns();
+ }
+
+ public String toXML()
+ {
+ return '<' + getElementName() + (node == null ? "" : " node='" + node + '\'') + "/>";
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getName() + " - content [" + toXML() + "]";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeType.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeType.java
index 5ee5a0520..5d0eb696b 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeType.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/NodeType.java
@@ -1,25 +1,25 @@
-/**
- * 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.pubsub;
-
-/**
- * Defines the available types of nodes
- *
- * @author Robin Collier
- */
-public enum NodeType
-{
- leaf,
- collection;
-}
+/**
+ * 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.pubsub;
+
+/**
+ * Defines the available types of nodes
+ *
+ * @author Robin Collier
+ */
+public enum NodeType
+{
+ leaf,
+ collection;
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/OptionsExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/OptionsExtension.java
index 32c033180..f8775d82c 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/OptionsExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/OptionsExtension.java
@@ -1,72 +1,72 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smackx.pubsub.util.XmlUtils;
-
-/**
- * A packet extension representing the <b>options</b> element.
- *
- * @author Robin Collier
- */
-public class OptionsExtension extends NodeExtension
-{
- protected String jid;
- protected String id;
-
- public OptionsExtension(String subscriptionJid)
- {
- this(subscriptionJid, null, null);
- }
-
- public OptionsExtension(String subscriptionJid, String nodeId)
- {
- this(subscriptionJid, nodeId, null);
- }
-
- public OptionsExtension(String jid, String nodeId, String subscriptionId)
- {
- super(PubSubElementType.OPTIONS, nodeId);
- this.jid = jid;
- id = subscriptionId;
- }
-
- public String getJid()
- {
- return jid;
- }
-
- public String getId()
- {
- return id;
- }
-
- @Override
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
- XmlUtils.appendAttribute(builder, "jid", jid);
-
- if (getNode() != null)
- XmlUtils.appendAttribute(builder, "node", getNode());
-
- if (id != null)
- XmlUtils.appendAttribute(builder, "subid", id);
-
- builder.append("/>");
- return builder.toString();
- }
-
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smackx.pubsub.util.XmlUtils;
+
+/**
+ * A packet extension representing the <b>options</b> element.
+ *
+ * @author Robin Collier
+ */
+public class OptionsExtension extends NodeExtension
+{
+ protected String jid;
+ protected String id;
+
+ public OptionsExtension(String subscriptionJid)
+ {
+ this(subscriptionJid, null, null);
+ }
+
+ public OptionsExtension(String subscriptionJid, String nodeId)
+ {
+ this(subscriptionJid, nodeId, null);
+ }
+
+ public OptionsExtension(String jid, String nodeId, String subscriptionId)
+ {
+ super(PubSubElementType.OPTIONS, nodeId);
+ this.jid = jid;
+ id = subscriptionId;
+ }
+
+ public String getJid()
+ {
+ return jid;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ @Override
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+ XmlUtils.appendAttribute(builder, "jid", jid);
+
+ if (getNode() != null)
+ XmlUtils.appendAttribute(builder, "node", getNode());
+
+ if (id != null)
+ XmlUtils.appendAttribute(builder, "subid", id);
+
+ builder.append("/>");
+ return builder.toString();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PayloadItem.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PayloadItem.java
index e9497c55e..a6e636567 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PayloadItem.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PayloadItem.java
@@ -1,138 +1,138 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smack.packet.Message;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
-
-/**
- * This class represents an item that has been, or will be published to a
- * pubsub node. An <tt>Item</tt> has several properties that are dependent
- * on the configuration of the node to which it has been or will be published.
- *
- * <h1>An Item received from a node (via {@link LeafNode#getItems()} or {@link LeafNode#addItemEventListener(org.jivesoftware.smackx.pubsub.listener.ItemEventListener)}</b>
- * <li>Will always have an id (either user or server generated) unless node configuration has both
- * {@link ConfigureForm#isPersistItems()} and {@link ConfigureForm#isDeliverPayloads()}set to false.
- * <li>Will have a payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
- * to true, otherwise it will be null.
- *
- * <h1>An Item created to send to a node (via {@link LeafNode#send()} or {@link LeafNode#publish()}</b>
- * <li>The id is optional, since the server will generate one if necessary, but should be used if it is
- * meaningful in the context of the node. This value must be unique within the node that it is sent to, since
- * resending an item with the same id will overwrite the one that already exists if the items are persisted.
- * <li>Will require payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
- * to true.
- *
- * <p>To customise the payload object being returned from the {@link #getPayload()} method, you can
- * add a custom parser as explained in {@link ItemProvider}.
- *
- * @author Robin Collier
- */
-public class PayloadItem<E extends PacketExtension> extends Item
-{
- private E payload;
-
- /**
- * Create an <tt>Item</tt> with no id and a payload The id will be set by the server.
- *
- * @param payloadExt A {@link PacketExtension} which represents the payload data.
- */
- public PayloadItem(E payloadExt)
- {
- super();
-
- if (payloadExt == null)
- throw new IllegalArgumentException("payload cannot be 'null'");
- payload = payloadExt;
- }
-
- /**
- * Create an <tt>Item</tt> with an id and payload.
- *
- * @param itemId The id of this item. It can be null if we want the server to set the id.
- * @param payloadExt A {@link PacketExtension} which represents the payload data.
- */
- public PayloadItem(String itemId, E payloadExt)
- {
- super(itemId);
-
- if (payloadExt == null)
- throw new IllegalArgumentException("payload cannot be 'null'");
- payload = payloadExt;
- }
-
- /**
- * Create an <tt>Item</tt> with an id, node id and payload.
- *
- * <p>
- * <b>Note:</b> This is not valid for publishing an item to a node, only receiving from
- * one as part of {@link Message}. If used to create an Item to publish
- * (via {@link LeafNode#publish(Item)}, the server <i>may</i> return an
- * error for an invalid packet.
- *
- * @param itemId The id of this item.
- * @param nodeId The id of the node the item was published to.
- * @param payloadExt A {@link PacketExtension} which represents the payload data.
- */
- public PayloadItem(String itemId, String nodeId, E payloadExt)
- {
- super(itemId, nodeId);
-
- if (payloadExt == null)
- throw new IllegalArgumentException("payload cannot be 'null'");
- payload = payloadExt;
- }
-
- /**
- * Get the payload associated with this <tt>Item</tt>. Customising the payload
- * parsing from the server can be accomplished as described in {@link ItemProvider}.
- *
- * @return The payload as a {@link PacketExtension}.
- */
- public E getPayload()
- {
- return payload;
- }
-
- @Override
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<item");
-
- if (getId() != null)
- {
- builder.append(" id='");
- builder.append(getId());
- builder.append("'");
- }
-
- if (getNode() != null) {
- builder.append(" node='");
- builder.append(getNode());
- builder.append("'");
- }
- builder.append(">");
- builder.append(payload.toXML());
- builder.append("</item>");
-
- return builder.toString();
- }
-
- @Override
- public String toString()
- {
- return getClass().getName() + " | Content [" + toXML() + "]";
- }
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
+
+/**
+ * This class represents an item that has been, or will be published to a
+ * pubsub node. An <tt>Item</tt> has several properties that are dependent
+ * on the configuration of the node to which it has been or will be published.
+ *
+ * <h1>An Item received from a node (via {@link LeafNode#getItems()} or {@link LeafNode#addItemEventListener(org.jivesoftware.smackx.pubsub.listener.ItemEventListener)}</b>
+ * <li>Will always have an id (either user or server generated) unless node configuration has both
+ * {@link ConfigureForm#isPersistItems()} and {@link ConfigureForm#isDeliverPayloads()}set to false.
+ * <li>Will have a payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
+ * to true, otherwise it will be null.
+ *
+ * <h1>An Item created to send to a node (via {@link LeafNode#send()} or {@link LeafNode#publish()}</b>
+ * <li>The id is optional, since the server will generate one if necessary, but should be used if it is
+ * meaningful in the context of the node. This value must be unique within the node that it is sent to, since
+ * resending an item with the same id will overwrite the one that already exists if the items are persisted.
+ * <li>Will require payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set
+ * to true.
+ *
+ * <p>To customise the payload object being returned from the {@link #getPayload()} method, you can
+ * add a custom parser as explained in {@link ItemProvider}.
+ *
+ * @author Robin Collier
+ */
+public class PayloadItem<E extends PacketExtension> extends Item
+{
+ private E payload;
+
+ /**
+ * Create an <tt>Item</tt> with no id and a payload The id will be set by the server.
+ *
+ * @param payloadExt A {@link PacketExtension} which represents the payload data.
+ */
+ public PayloadItem(E payloadExt)
+ {
+ super();
+
+ if (payloadExt == null)
+ throw new IllegalArgumentException("payload cannot be 'null'");
+ payload = payloadExt;
+ }
+
+ /**
+ * Create an <tt>Item</tt> with an id and payload.
+ *
+ * @param itemId The id of this item. It can be null if we want the server to set the id.
+ * @param payloadExt A {@link PacketExtension} which represents the payload data.
+ */
+ public PayloadItem(String itemId, E payloadExt)
+ {
+ super(itemId);
+
+ if (payloadExt == null)
+ throw new IllegalArgumentException("payload cannot be 'null'");
+ payload = payloadExt;
+ }
+
+ /**
+ * Create an <tt>Item</tt> with an id, node id and payload.
+ *
+ * <p>
+ * <b>Note:</b> This is not valid for publishing an item to a node, only receiving from
+ * one as part of {@link Message}. If used to create an Item to publish
+ * (via {@link LeafNode#publish(Item)}, the server <i>may</i> return an
+ * error for an invalid packet.
+ *
+ * @param itemId The id of this item.
+ * @param nodeId The id of the node the item was published to.
+ * @param payloadExt A {@link PacketExtension} which represents the payload data.
+ */
+ public PayloadItem(String itemId, String nodeId, E payloadExt)
+ {
+ super(itemId, nodeId);
+
+ if (payloadExt == null)
+ throw new IllegalArgumentException("payload cannot be 'null'");
+ payload = payloadExt;
+ }
+
+ /**
+ * Get the payload associated with this <tt>Item</tt>. Customising the payload
+ * parsing from the server can be accomplished as described in {@link ItemProvider}.
+ *
+ * @return The payload as a {@link PacketExtension}.
+ */
+ public E getPayload()
+ {
+ return payload;
+ }
+
+ @Override
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<item");
+
+ if (getId() != null)
+ {
+ builder.append(" id='");
+ builder.append(getId());
+ builder.append("'");
+ }
+
+ if (getNode() != null) {
+ builder.append(" node='");
+ builder.append(getNode());
+ builder.append("'");
+ }
+ builder.append(">");
+ builder.append(payload.toXML());
+ builder.append("</item>");
+
+ return builder.toString();
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getName() + " | Content [" + toXML() + "]";
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PresenceState.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PresenceState.java
index 0612fc25e..07342e225 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PresenceState.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PresenceState.java
@@ -1,25 +1,25 @@
-/**
- * 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.pubsub;
-
-/**
- * Defines the possible valid presence states for node subscription via
- * {@link SubscribeForm#getShowValues()}.
- *
- * @author Robin Collier
- */
-public enum PresenceState
-{
- chat, online, away, xa, dnd
-}
+/**
+ * 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.pubsub;
+
+/**
+ * Defines the possible valid presence states for node subscription via
+ * {@link SubscribeForm#getShowValues()}.
+ *
+ * @author Robin Collier
+ */
+public enum PresenceState
+{
+ chat, online, away, xa, dnd
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubElementType.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubElementType.java
index a887ca2ba..ff762e971 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubElementType.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubElementType.java
@@ -1,80 +1,80 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
-
-/**
- * Defines all the possible element types as defined for all the pubsub
- * schemas in all 3 namespaces.
- *
- * @author Robin Collier
- */
-public enum PubSubElementType
-{
- CREATE("create", PubSubNamespace.BASIC),
- DELETE("delete", PubSubNamespace.OWNER),
- DELETE_EVENT("delete", PubSubNamespace.EVENT),
- CONFIGURE("configure", PubSubNamespace.BASIC),
- CONFIGURE_OWNER("configure", PubSubNamespace.OWNER),
- CONFIGURATION("configuration", PubSubNamespace.EVENT),
- OPTIONS("options", PubSubNamespace.BASIC),
- DEFAULT("default", PubSubNamespace.OWNER),
- ITEMS("items", PubSubNamespace.BASIC),
- ITEMS_EVENT("items", PubSubNamespace.EVENT),
- ITEM("item", PubSubNamespace.BASIC),
- ITEM_EVENT("item", PubSubNamespace.EVENT),
- PUBLISH("publish", PubSubNamespace.BASIC),
- PUBLISH_OPTIONS("publish-options", PubSubNamespace.BASIC),
- PURGE_OWNER("purge", PubSubNamespace.OWNER),
- PURGE_EVENT("purge", PubSubNamespace.EVENT),
- RETRACT("retract", PubSubNamespace.BASIC),
- AFFILIATIONS("affiliations", PubSubNamespace.BASIC),
- SUBSCRIBE("subscribe", PubSubNamespace.BASIC),
- SUBSCRIPTION("subscription", PubSubNamespace.BASIC),
- SUBSCRIPTIONS("subscriptions", PubSubNamespace.BASIC),
- UNSUBSCRIBE("unsubscribe", PubSubNamespace.BASIC);
-
- private String eName;
- private PubSubNamespace nSpace;
-
- private PubSubElementType(String elemName, PubSubNamespace ns)
- {
- eName = elemName;
- nSpace = ns;
- }
-
- public PubSubNamespace getNamespace()
- {
- return nSpace;
- }
-
- public String getElementName()
- {
- return eName;
- }
-
- public static PubSubElementType valueOfFromElemName(String elemName, String namespace)
- {
- int index = namespace.lastIndexOf('#');
- String fragment = (index == -1 ? null : namespace.substring(index+1));
-
- if (fragment != null)
- {
- return valueOf((elemName + '_' + fragment).toUpperCase());
- }
- return valueOf(elemName.toUpperCase().replace('-', '_'));
- }
-
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+
+/**
+ * Defines all the possible element types as defined for all the pubsub
+ * schemas in all 3 namespaces.
+ *
+ * @author Robin Collier
+ */
+public enum PubSubElementType
+{
+ CREATE("create", PubSubNamespace.BASIC),
+ DELETE("delete", PubSubNamespace.OWNER),
+ DELETE_EVENT("delete", PubSubNamespace.EVENT),
+ CONFIGURE("configure", PubSubNamespace.BASIC),
+ CONFIGURE_OWNER("configure", PubSubNamespace.OWNER),
+ CONFIGURATION("configuration", PubSubNamespace.EVENT),
+ OPTIONS("options", PubSubNamespace.BASIC),
+ DEFAULT("default", PubSubNamespace.OWNER),
+ ITEMS("items", PubSubNamespace.BASIC),
+ ITEMS_EVENT("items", PubSubNamespace.EVENT),
+ ITEM("item", PubSubNamespace.BASIC),
+ ITEM_EVENT("item", PubSubNamespace.EVENT),
+ PUBLISH("publish", PubSubNamespace.BASIC),
+ PUBLISH_OPTIONS("publish-options", PubSubNamespace.BASIC),
+ PURGE_OWNER("purge", PubSubNamespace.OWNER),
+ PURGE_EVENT("purge", PubSubNamespace.EVENT),
+ RETRACT("retract", PubSubNamespace.BASIC),
+ AFFILIATIONS("affiliations", PubSubNamespace.BASIC),
+ SUBSCRIBE("subscribe", PubSubNamespace.BASIC),
+ SUBSCRIPTION("subscription", PubSubNamespace.BASIC),
+ SUBSCRIPTIONS("subscriptions", PubSubNamespace.BASIC),
+ UNSUBSCRIBE("unsubscribe", PubSubNamespace.BASIC);
+
+ private String eName;
+ private PubSubNamespace nSpace;
+
+ private PubSubElementType(String elemName, PubSubNamespace ns)
+ {
+ eName = elemName;
+ nSpace = ns;
+ }
+
+ public PubSubNamespace getNamespace()
+ {
+ return nSpace;
+ }
+
+ public String getElementName()
+ {
+ return eName;
+ }
+
+ public static PubSubElementType valueOfFromElemName(String elemName, String namespace)
+ {
+ int index = namespace.lastIndexOf('#');
+ String fragment = (index == -1 ? null : namespace.substring(index+1));
+
+ if (fragment != null)
+ {
+ return valueOf((elemName + '_' + fragment).toUpperCase());
+ }
+ return valueOf(elemName.toUpperCase().replace('-', '_'));
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubManager.java
index 4fb01589c..483f6f255 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PubSubManager.java
@@ -1,329 +1,329 @@
-/**
- * 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.pubsub;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ.Type;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.FormField;
-import org.jivesoftware.smackx.ServiceDiscoveryManager;
-import org.jivesoftware.smackx.packet.DiscoverInfo;
-import org.jivesoftware.smackx.packet.DiscoverItems;
-import org.jivesoftware.smackx.pubsub.packet.PubSub;
-import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
-import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
-import org.jivesoftware.smackx.pubsub.util.NodeUtils;
-
-/**
- * This is the starting point for access to the pubsub service. It
- * will provide access to general information about the service, as
- * well as create or retrieve pubsub {@link LeafNode} instances. These
- * instances provide the bulk of the functionality as defined in the
- * pubsub specification <a href="http://xmpp.org/extensions/xep-0060.html">XEP-0060</a>.
- *
- * @author Robin Collier
- */
-final public class PubSubManager
-{
- private Connection con;
- private String to;
- private Map<String, Node> nodeMap = new ConcurrentHashMap<String, Node>();
-
- /**
- * Create a pubsub manager associated to the specified connection. Defaults the service
- * name to <i>pubsub</i>
- *
- * @param connection The XMPP connection
- */
- public PubSubManager(Connection connection)
- {
- con = connection;
- to = "pubsub." + connection.getServiceName();
- }
-
- /**
- * Create a pubsub manager associated to the specified connection where
- * the pubsub requests require a specific to address for packets.
- *
- * @param connection The XMPP connection
- * @param toAddress The pubsub specific to address (required for some servers)
- */
- public PubSubManager(Connection connection, String toAddress)
- {
- con = connection;
- to = toAddress;
- }
-
- /**
- * Creates an instant node, if supported.
- *
- * @return The node that was created
- * @exception XMPPException
- */
- public LeafNode createNode()
- throws XMPPException
- {
- PubSub reply = (PubSub)sendPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.CREATE));
- NodeExtension elem = (NodeExtension)reply.getExtension("create", PubSubNamespace.BASIC.getXmlns());
-
- LeafNode newNode = new LeafNode(con, elem.getNode());
- newNode.setTo(to);
- nodeMap.put(newNode.getId(), newNode);
-
- return newNode;
- }
-
- /**
- * Creates a node with default configuration.
- *
- * @param id The id of the node, which must be unique within the
- * pubsub service
- * @return The node that was created
- * @exception XMPPException
- */
- public LeafNode createNode(String id)
- throws XMPPException
- {
- return (LeafNode)createNode(id, null);
- }
-
- /**
- * Creates a node with specified configuration.
- *
- * Note: This is the only way to create a collection node.
- *
- * @param name The name of the node, which must be unique within the
- * pubsub service
- * @param config The configuration for the node
- * @return The node that was created
- * @exception XMPPException
- */
- public Node createNode(String name, Form config)
- throws XMPPException
- {
- PubSub request = createPubsubPacket(to, Type.SET, new NodeExtension(PubSubElementType.CREATE, name));
- boolean isLeafNode = true;
-
- if (config != null)
- {
- request.addExtension(new FormNode(FormNodeType.CONFIGURE, config));
- FormField nodeTypeField = config.getField(ConfigureNodeFields.node_type.getFieldName());
-
- if (nodeTypeField != null)
- isLeafNode = nodeTypeField.getValues().next().equals(NodeType.leaf.toString());
- }
-
- // Errors will cause exceptions in getReply, so it only returns
- // on success.
- sendPubsubPacket(con, to, Type.SET, request);
- Node newNode = isLeafNode ? new LeafNode(con, name) : new CollectionNode(con, name);
- newNode.setTo(to);
- nodeMap.put(newNode.getId(), newNode);
-
- return newNode;
- }
-
- /**
- * Retrieves the requested node, if it exists. It will throw an
- * exception if it does not.
- *
- * @param id - The unique id of the node
- * @return the node
- * @throws XMPPException The node does not exist
- */
- public <T extends Node> T getNode(String id)
- throws XMPPException
- {
- Node node = nodeMap.get(id);
-
- if (node == null)
- {
- DiscoverInfo info = new DiscoverInfo();
- info.setTo(to);
- info.setNode(id);
-
- DiscoverInfo infoReply = (DiscoverInfo)SyncPacketSend.getReply(con, info);
-
- if (infoReply.getIdentities().next().getType().equals(NodeType.leaf.toString()))
- node = new LeafNode(con, id);
- else
- node = new CollectionNode(con, id);
- node.setTo(to);
- nodeMap.put(id, node);
- }
- return (T) node;
- }
-
- /**
- * Get all the nodes that currently exist as a child of the specified
- * collection node. If the service does not support collection nodes
- * then all nodes will be returned.
- *
- * To retrieve contents of the root collection node (if it exists),
- * or there is no root collection node, pass null as the nodeId.
- *
- * @param nodeId - The id of the collection node for which the child
- * nodes will be returned.
- * @return {@link DiscoverItems} representing the existing nodes
- *
- * @throws XMPPException
- */
- public DiscoverItems discoverNodes(String nodeId)
- throws XMPPException
- {
- DiscoverItems items = new DiscoverItems();
-
- if (nodeId != null)
- items.setNode(nodeId);
- items.setTo(to);
- DiscoverItems nodeItems = (DiscoverItems)SyncPacketSend.getReply(con, items);
- return nodeItems;
- }
-
- /**
- * Gets the subscriptions on the root node.
- *
- * @return List of exceptions
- *
- * @throws XMPPException
- */
- public List<Subscription> getSubscriptions()
- throws XMPPException
- {
- Packet reply = sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.SUBSCRIPTIONS));
- SubscriptionsExtension subElem = (SubscriptionsExtension)reply.getExtension(PubSubElementType.SUBSCRIPTIONS.getElementName(), PubSubElementType.SUBSCRIPTIONS.getNamespace().getXmlns());
- return subElem.getSubscriptions();
- }
-
- /**
- * Gets the affiliations on the root node.
- *
- * @return List of affiliations
- *
- * @throws XMPPException
- */
- public List<Affiliation> getAffiliations()
- throws XMPPException
- {
- PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.AFFILIATIONS));
- AffiliationsExtension listElem = (AffiliationsExtension)reply.getExtension(PubSubElementType.AFFILIATIONS);
- return listElem.getAffiliations();
- }
-
- /**
- * Delete the specified node
- *
- * @param nodeId
- * @throws XMPPException
- */
- public void deleteNode(String nodeId)
- throws XMPPException
- {
- sendPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.DELETE, nodeId), PubSubElementType.DELETE.getNamespace());
- nodeMap.remove(nodeId);
- }
-
- /**
- * Returns the default settings for Node configuration.
- *
- * @return configuration form containing the default settings.
- */
- public ConfigureForm getDefaultConfiguration()
- throws XMPPException
- {
- // Errors will cause exceptions in getReply, so it only returns
- // on success.
- PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.DEFAULT), PubSubElementType.DEFAULT.getNamespace());
- return NodeUtils.getFormFromPacket(reply, PubSubElementType.DEFAULT);
- }
-
- /**
- * Gets the supported features of the servers pubsub implementation
- * as a standard {@link DiscoverInfo} instance.
- *
- * @return The supported features
- *
- * @throws XMPPException
- */
- public DiscoverInfo getSupportedFeatures()
- throws XMPPException
- {
- ServiceDiscoveryManager mgr = ServiceDiscoveryManager.getInstanceFor(con);
- return mgr.discoverInfo(to);
- }
-
- private Packet sendPubsubPacket(Type type, PacketExtension ext, PubSubNamespace ns)
- throws XMPPException
- {
- return sendPubsubPacket(con, to, type, ext, ns);
- }
-
- private Packet sendPubsubPacket(Type type, PacketExtension ext)
- throws XMPPException
- {
- return sendPubsubPacket(type, ext, null);
- }
-
- static PubSub createPubsubPacket(String to, Type type, PacketExtension ext)
- {
- return createPubsubPacket(to, type, ext, null);
- }
-
- static PubSub createPubsubPacket(String to, Type type, PacketExtension ext, PubSubNamespace ns)
- {
- PubSub request = new PubSub();
- request.setTo(to);
- request.setType(type);
-
- if (ns != null)
- {
- request.setPubSubNamespace(ns);
- }
- request.addExtension(ext);
-
- return request;
- }
-
- static Packet sendPubsubPacket(Connection con, String to, Type type, PacketExtension ext)
- throws XMPPException
- {
- return sendPubsubPacket(con, to, type, ext, null);
- }
-
- static Packet sendPubsubPacket(Connection con, String to, Type type, PacketExtension ext, PubSubNamespace ns)
- throws XMPPException
- {
- return SyncPacketSend.getReply(con, createPubsubPacket(to, type, ext, ns));
- }
-
- static Packet sendPubsubPacket(Connection con, String to, Type type, PubSub packet)
- throws XMPPException
- {
- return sendPubsubPacket(con, to, type, packet, null);
- }
-
- static Packet sendPubsubPacket(Connection con, String to, Type type, PubSub packet, PubSubNamespace ns)
- throws XMPPException
- {
- return SyncPacketSend.getReply(con, packet);
- }
-
-}
+/**
+ * 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.pubsub;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ.Type;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.FormField;
+import org.jivesoftware.smackx.ServiceDiscoveryManager;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
+import org.jivesoftware.smackx.packet.DiscoverItems;
+import org.jivesoftware.smackx.pubsub.packet.PubSub;
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
+import org.jivesoftware.smackx.pubsub.util.NodeUtils;
+
+/**
+ * This is the starting point for access to the pubsub service. It
+ * will provide access to general information about the service, as
+ * well as create or retrieve pubsub {@link LeafNode} instances. These
+ * instances provide the bulk of the functionality as defined in the
+ * pubsub specification <a href="http://xmpp.org/extensions/xep-0060.html">XEP-0060</a>.
+ *
+ * @author Robin Collier
+ */
+final public class PubSubManager
+{
+ private Connection con;
+ private String to;
+ private Map<String, Node> nodeMap = new ConcurrentHashMap<String, Node>();
+
+ /**
+ * Create a pubsub manager associated to the specified connection. Defaults the service
+ * name to <i>pubsub</i>
+ *
+ * @param connection The XMPP connection
+ */
+ public PubSubManager(Connection connection)
+ {
+ con = connection;
+ to = "pubsub." + connection.getServiceName();
+ }
+
+ /**
+ * Create a pubsub manager associated to the specified connection where
+ * the pubsub requests require a specific to address for packets.
+ *
+ * @param connection The XMPP connection
+ * @param toAddress The pubsub specific to address (required for some servers)
+ */
+ public PubSubManager(Connection connection, String toAddress)
+ {
+ con = connection;
+ to = toAddress;
+ }
+
+ /**
+ * Creates an instant node, if supported.
+ *
+ * @return The node that was created
+ * @exception XMPPException
+ */
+ public LeafNode createNode()
+ throws XMPPException
+ {
+ PubSub reply = (PubSub)sendPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.CREATE));
+ NodeExtension elem = (NodeExtension)reply.getExtension("create", PubSubNamespace.BASIC.getXmlns());
+
+ LeafNode newNode = new LeafNode(con, elem.getNode());
+ newNode.setTo(to);
+ nodeMap.put(newNode.getId(), newNode);
+
+ return newNode;
+ }
+
+ /**
+ * Creates a node with default configuration.
+ *
+ * @param id The id of the node, which must be unique within the
+ * pubsub service
+ * @return The node that was created
+ * @exception XMPPException
+ */
+ public LeafNode createNode(String id)
+ throws XMPPException
+ {
+ return (LeafNode)createNode(id, null);
+ }
+
+ /**
+ * Creates a node with specified configuration.
+ *
+ * Note: This is the only way to create a collection node.
+ *
+ * @param name The name of the node, which must be unique within the
+ * pubsub service
+ * @param config The configuration for the node
+ * @return The node that was created
+ * @exception XMPPException
+ */
+ public Node createNode(String name, Form config)
+ throws XMPPException
+ {
+ PubSub request = createPubsubPacket(to, Type.SET, new NodeExtension(PubSubElementType.CREATE, name));
+ boolean isLeafNode = true;
+
+ if (config != null)
+ {
+ request.addExtension(new FormNode(FormNodeType.CONFIGURE, config));
+ FormField nodeTypeField = config.getField(ConfigureNodeFields.node_type.getFieldName());
+
+ if (nodeTypeField != null)
+ isLeafNode = nodeTypeField.getValues().next().equals(NodeType.leaf.toString());
+ }
+
+ // Errors will cause exceptions in getReply, so it only returns
+ // on success.
+ sendPubsubPacket(con, to, Type.SET, request);
+ Node newNode = isLeafNode ? new LeafNode(con, name) : new CollectionNode(con, name);
+ newNode.setTo(to);
+ nodeMap.put(newNode.getId(), newNode);
+
+ return newNode;
+ }
+
+ /**
+ * Retrieves the requested node, if it exists. It will throw an
+ * exception if it does not.
+ *
+ * @param id - The unique id of the node
+ * @return the node
+ * @throws XMPPException The node does not exist
+ */
+ public <T extends Node> T getNode(String id)
+ throws XMPPException
+ {
+ Node node = nodeMap.get(id);
+
+ if (node == null)
+ {
+ DiscoverInfo info = new DiscoverInfo();
+ info.setTo(to);
+ info.setNode(id);
+
+ DiscoverInfo infoReply = (DiscoverInfo)SyncPacketSend.getReply(con, info);
+
+ if (infoReply.getIdentities().next().getType().equals(NodeType.leaf.toString()))
+ node = new LeafNode(con, id);
+ else
+ node = new CollectionNode(con, id);
+ node.setTo(to);
+ nodeMap.put(id, node);
+ }
+ return (T) node;
+ }
+
+ /**
+ * Get all the nodes that currently exist as a child of the specified
+ * collection node. If the service does not support collection nodes
+ * then all nodes will be returned.
+ *
+ * To retrieve contents of the root collection node (if it exists),
+ * or there is no root collection node, pass null as the nodeId.
+ *
+ * @param nodeId - The id of the collection node for which the child
+ * nodes will be returned.
+ * @return {@link DiscoverItems} representing the existing nodes
+ *
+ * @throws XMPPException
+ */
+ public DiscoverItems discoverNodes(String nodeId)
+ throws XMPPException
+ {
+ DiscoverItems items = new DiscoverItems();
+
+ if (nodeId != null)
+ items.setNode(nodeId);
+ items.setTo(to);
+ DiscoverItems nodeItems = (DiscoverItems)SyncPacketSend.getReply(con, items);
+ return nodeItems;
+ }
+
+ /**
+ * Gets the subscriptions on the root node.
+ *
+ * @return List of exceptions
+ *
+ * @throws XMPPException
+ */
+ public List<Subscription> getSubscriptions()
+ throws XMPPException
+ {
+ Packet reply = sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.SUBSCRIPTIONS));
+ SubscriptionsExtension subElem = (SubscriptionsExtension)reply.getExtension(PubSubElementType.SUBSCRIPTIONS.getElementName(), PubSubElementType.SUBSCRIPTIONS.getNamespace().getXmlns());
+ return subElem.getSubscriptions();
+ }
+
+ /**
+ * Gets the affiliations on the root node.
+ *
+ * @return List of affiliations
+ *
+ * @throws XMPPException
+ */
+ public List<Affiliation> getAffiliations()
+ throws XMPPException
+ {
+ PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.AFFILIATIONS));
+ AffiliationsExtension listElem = (AffiliationsExtension)reply.getExtension(PubSubElementType.AFFILIATIONS);
+ return listElem.getAffiliations();
+ }
+
+ /**
+ * Delete the specified node
+ *
+ * @param nodeId
+ * @throws XMPPException
+ */
+ public void deleteNode(String nodeId)
+ throws XMPPException
+ {
+ sendPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.DELETE, nodeId), PubSubElementType.DELETE.getNamespace());
+ nodeMap.remove(nodeId);
+ }
+
+ /**
+ * Returns the default settings for Node configuration.
+ *
+ * @return configuration form containing the default settings.
+ */
+ public ConfigureForm getDefaultConfiguration()
+ throws XMPPException
+ {
+ // Errors will cause exceptions in getReply, so it only returns
+ // on success.
+ PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.DEFAULT), PubSubElementType.DEFAULT.getNamespace());
+ return NodeUtils.getFormFromPacket(reply, PubSubElementType.DEFAULT);
+ }
+
+ /**
+ * Gets the supported features of the servers pubsub implementation
+ * as a standard {@link DiscoverInfo} instance.
+ *
+ * @return The supported features
+ *
+ * @throws XMPPException
+ */
+ public DiscoverInfo getSupportedFeatures()
+ throws XMPPException
+ {
+ ServiceDiscoveryManager mgr = ServiceDiscoveryManager.getInstanceFor(con);
+ return mgr.discoverInfo(to);
+ }
+
+ private Packet sendPubsubPacket(Type type, PacketExtension ext, PubSubNamespace ns)
+ throws XMPPException
+ {
+ return sendPubsubPacket(con, to, type, ext, ns);
+ }
+
+ private Packet sendPubsubPacket(Type type, PacketExtension ext)
+ throws XMPPException
+ {
+ return sendPubsubPacket(type, ext, null);
+ }
+
+ static PubSub createPubsubPacket(String to, Type type, PacketExtension ext)
+ {
+ return createPubsubPacket(to, type, ext, null);
+ }
+
+ static PubSub createPubsubPacket(String to, Type type, PacketExtension ext, PubSubNamespace ns)
+ {
+ PubSub request = new PubSub();
+ request.setTo(to);
+ request.setType(type);
+
+ if (ns != null)
+ {
+ request.setPubSubNamespace(ns);
+ }
+ request.addExtension(ext);
+
+ return request;
+ }
+
+ static Packet sendPubsubPacket(Connection con, String to, Type type, PacketExtension ext)
+ throws XMPPException
+ {
+ return sendPubsubPacket(con, to, type, ext, null);
+ }
+
+ static Packet sendPubsubPacket(Connection con, String to, Type type, PacketExtension ext, PubSubNamespace ns)
+ throws XMPPException
+ {
+ return SyncPacketSend.getReply(con, createPubsubPacket(to, type, ext, ns));
+ }
+
+ static Packet sendPubsubPacket(Connection con, String to, Type type, PubSub packet)
+ throws XMPPException
+ {
+ return sendPubsubPacket(con, to, type, packet, null);
+ }
+
+ static Packet sendPubsubPacket(Connection con, String to, Type type, PubSub packet, PubSubNamespace ns)
+ throws XMPPException
+ {
+ return SyncPacketSend.getReply(con, packet);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishItem.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishItem.java
index ffbd70503..15282eaba 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishItem.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishItem.java
@@ -1,70 +1,70 @@
-/**
- * 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.pubsub;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Represents a request to publish an item(s) to a specific node.
- *
- * @author Robin Collier
- */
-public class PublishItem <T extends Item> extends NodeExtension
-{
- protected Collection<T> items;
-
- /**
- * Construct a request to publish an item to a node.
- *
- * @param nodeId The node to publish to
- * @param toPublish The {@link Item} to publish
- */
- public PublishItem(String nodeId, T toPublish)
- {
- super(PubSubElementType.PUBLISH, nodeId);
- items = new ArrayList<T>(1);
- items.add(toPublish);
- }
-
- /**
- * Construct a request to publish multiple items to a node.
- *
- * @param nodeId The node to publish to
- * @param toPublish The list of {@link Item} to publish
- */
- public PublishItem(String nodeId, Collection<T> toPublish)
- {
- super(PubSubElementType.PUBLISH, nodeId);
- items = toPublish;
- }
-
- @Override
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
- builder.append(" node='");
- builder.append(getNode());
- builder.append("'>");
-
- for (Item item : items)
- {
- builder.append(item.toXML());
- }
- builder.append("</publish>");
-
- return builder.toString();
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Represents a request to publish an item(s) to a specific node.
+ *
+ * @author Robin Collier
+ */
+public class PublishItem <T extends Item> extends NodeExtension
+{
+ protected Collection<T> items;
+
+ /**
+ * Construct a request to publish an item to a node.
+ *
+ * @param nodeId The node to publish to
+ * @param toPublish The {@link Item} to publish
+ */
+ public PublishItem(String nodeId, T toPublish)
+ {
+ super(PubSubElementType.PUBLISH, nodeId);
+ items = new ArrayList<T>(1);
+ items.add(toPublish);
+ }
+
+ /**
+ * Construct a request to publish multiple items to a node.
+ *
+ * @param nodeId The node to publish to
+ * @param toPublish The list of {@link Item} to publish
+ */
+ public PublishItem(String nodeId, Collection<T> toPublish)
+ {
+ super(PubSubElementType.PUBLISH, nodeId);
+ items = toPublish;
+ }
+
+ @Override
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+ builder.append(" node='");
+ builder.append(getNode());
+ builder.append("'>");
+
+ for (Item item : items)
+ {
+ builder.append(item.toXML());
+ }
+ builder.append("</publish>");
+
+ return builder.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishModel.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishModel.java
index 4b5a851a4..b94d50f87 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishModel.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/PublishModel.java
@@ -1,32 +1,32 @@
-/**
- * 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.pubsub;
-
-/**
- * Determines who may publish to a node. Denotes possible values
- * for {@link ConfigureForm#setPublishModel(PublishModel)}.
- *
- * @author Robin Collier
- */
-public enum PublishModel
-{
- /** Only publishers may publish */
- publishers,
-
- /** Only subscribers may publish */
- subscribers,
-
- /** Anyone may publish */
- open;
-}
+/**
+ * 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.pubsub;
+
+/**
+ * Determines who may publish to a node. Denotes possible values
+ * for {@link ConfigureForm#setPublishModel(PublishModel)}.
+ *
+ * @author Robin Collier
+ */
+public enum PublishModel
+{
+ /** Only publishers may publish */
+ publishers,
+
+ /** Only subscribers may publish */
+ subscribers,
+
+ /** Anyone may publish */
+ open;
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/RetractItem.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/RetractItem.java
index 97db5ccd2..1e6cc4983 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/RetractItem.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/RetractItem.java
@@ -1,59 +1,59 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
-
-/**
- * Represents and item that has been deleted from a node.
- *
- * @author Robin Collier
- */
-public class RetractItem implements PacketExtension
-{
- private String id;
-
- /**
- * Construct a <tt>RetractItem</tt> with the specified id.
- *
- * @param itemId The id if the item deleted
- */
- public RetractItem(String itemId)
- {
- if (itemId == null)
- throw new IllegalArgumentException("itemId must not be 'null'");
- id = itemId;
- }
-
- public String getId()
- {
- return id;
- }
-
- public String getElementName()
- {
- return "retract";
- }
-
- public String getNamespace()
- {
- return PubSubNamespace.EVENT.getXmlns();
- }
-
- public String toXML()
- {
- return "<retract id='" + id + "'/>";
- }
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+
+/**
+ * Represents and item that has been deleted from a node.
+ *
+ * @author Robin Collier
+ */
+public class RetractItem implements PacketExtension
+{
+ private String id;
+
+ /**
+ * Construct a <tt>RetractItem</tt> with the specified id.
+ *
+ * @param itemId The id if the item deleted
+ */
+ public RetractItem(String itemId)
+ {
+ if (itemId == null)
+ throw new IllegalArgumentException("itemId must not be 'null'");
+ id = itemId;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public String getElementName()
+ {
+ return "retract";
+ }
+
+ public String getNamespace()
+ {
+ return PubSubNamespace.EVENT.getXmlns();
+ }
+
+ public String toXML()
+ {
+ return "<retract id='" + id + "'/>";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SimplePayload.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SimplePayload.java
index 9d114b090..644c1f3b7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SimplePayload.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SimplePayload.java
@@ -1,65 +1,65 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * The default payload representation for {@link Item#getPayload()}. It simply
- * stores the XML payload as a string.
- *
- * @author Robin Collier
- */
-public class SimplePayload implements PacketExtension
-{
- private String elemName;
- private String ns;
- private String payload;
-
- /**
- * Construct a <tt>SimplePayload</tt> object with the specified element name,
- * namespace and content. The content must be well formed XML.
- *
- * @param elementName The root element name (of the payload)
- * @param namespace The namespace of the payload, null if there is none
- * @param xmlPayload The payload data
- */
- public SimplePayload(String elementName, String namespace, String xmlPayload)
- {
- elemName = elementName;
- payload = xmlPayload;
- ns = namespace;
- }
-
- public String getElementName()
- {
- return elemName;
- }
-
- public String getNamespace()
- {
- return ns;
- }
-
- public String toXML()
- {
- return payload;
- }
-
- @Override
- public String toString()
- {
- return getClass().getName() + "payload [" + toXML() + "]";
- }
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * The default payload representation for {@link Item#getPayload()}. It simply
+ * stores the XML payload as a string.
+ *
+ * @author Robin Collier
+ */
+public class SimplePayload implements PacketExtension
+{
+ private String elemName;
+ private String ns;
+ private String payload;
+
+ /**
+ * Construct a <tt>SimplePayload</tt> object with the specified element name,
+ * namespace and content. The content must be well formed XML.
+ *
+ * @param elementName The root element name (of the payload)
+ * @param namespace The namespace of the payload, null if there is none
+ * @param xmlPayload The payload data
+ */
+ public SimplePayload(String elementName, String namespace, String xmlPayload)
+ {
+ elemName = elementName;
+ payload = xmlPayload;
+ ns = namespace;
+ }
+
+ public String getElementName()
+ {
+ return elemName;
+ }
+
+ public String getNamespace()
+ {
+ return ns;
+ }
+
+ public String toXML()
+ {
+ return payload;
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getName() + "payload [" + toXML() + "]";
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeExtension.java
index daf8db7fb..5245ece4e 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeExtension.java
@@ -1,60 +1,60 @@
-/**
- * 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.pubsub;
-
-/**
- * Represents a request to subscribe to a node.
- *
- * @author Robin Collier
- */
-public class SubscribeExtension extends NodeExtension
-{
- protected String jid;
-
- public SubscribeExtension(String subscribeJid)
- {
- super(PubSubElementType.SUBSCRIBE);
- jid = subscribeJid;
- }
-
- public SubscribeExtension(String subscribeJid, String nodeId)
- {
- super(PubSubElementType.SUBSCRIBE, nodeId);
- jid = subscribeJid;
- }
-
- public String getJid()
- {
- return jid;
- }
-
- @Override
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
-
- if (getNode() != null)
- {
- builder.append(" node='");
- builder.append(getNode());
- builder.append("'");
- }
- builder.append(" jid='");
- builder.append(getJid());
- builder.append("'/>");
-
- return builder.toString();
- }
-}
+/**
+ * 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.pubsub;
+
+/**
+ * Represents a request to subscribe to a node.
+ *
+ * @author Robin Collier
+ */
+public class SubscribeExtension extends NodeExtension
+{
+ protected String jid;
+
+ public SubscribeExtension(String subscribeJid)
+ {
+ super(PubSubElementType.SUBSCRIBE);
+ jid = subscribeJid;
+ }
+
+ public SubscribeExtension(String subscribeJid, String nodeId)
+ {
+ super(PubSubElementType.SUBSCRIBE, nodeId);
+ jid = subscribeJid;
+ }
+
+ public String getJid()
+ {
+ return jid;
+ }
+
+ @Override
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+
+ if (getNode() != null)
+ {
+ builder.append(" node='");
+ builder.append(getNode());
+ builder.append("'");
+ }
+ builder.append(" jid='");
+ builder.append(getJid());
+ builder.append("'/>");
+
+ return builder.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeForm.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeForm.java
index 53f26068f..71cad1410 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeForm.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeForm.java
@@ -1,241 +1,241 @@
-/**
- * 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.pubsub;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.UnknownFormatConversionException;
-
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.FormField;
-import org.jivesoftware.smackx.packet.DataForm;
-
-/**
- * A decorator for a {@link Form} to easily enable reading and updating
- * of subscription options. All operations read or update the underlying {@link DataForm}.
- *
- * <p>Unlike the {@link Form}.setAnswer(XXX)} methods, which throw an exception if the field does not
- * exist, all <b>SubscribeForm.setXXX</b> methods will create the field in the wrapped form
- * if it does not already exist.
- *
- * @author Robin Collier
- */
-public class SubscribeForm extends Form
-{
- public SubscribeForm(DataForm configDataForm)
- {
- super(configDataForm);
- }
-
- public SubscribeForm(Form subscribeOptionsForm)
- {
- super(subscribeOptionsForm.getDataFormToSend());
- }
-
- public SubscribeForm(FormType formType)
- {
- super(formType.toString());
- }
-
- /**
- * Determines if an entity wants to receive notifications.
- *
- * @return true if want to receive, false otherwise
- */
- public boolean isDeliverOn()
- {
- return parseBoolean(getFieldValue(SubscribeOptionFields.deliver));
- }
-
- /**
- * Sets whether an entity wants to receive notifications.
- *
- * @param deliverNotifications
- */
- public void setDeliverOn(boolean deliverNotifications)
- {
- addField(SubscribeOptionFields.deliver, FormField.TYPE_BOOLEAN);
- setAnswer(SubscribeOptionFields.deliver.getFieldName(), deliverNotifications);
- }
-
- /**
- * Determines if notifications should be delivered as aggregations or not.
- *
- * @return true to aggregate, false otherwise
- */
- public boolean isDigestOn()
- {
- return parseBoolean(getFieldValue(SubscribeOptionFields.digest));
- }
-
- /**
- * Sets whether notifications should be delivered as aggregations or not.
- *
- * @param digestOn true to aggregate, false otherwise
- */
- public void setDigestOn(boolean digestOn)
- {
- addField(SubscribeOptionFields.deliver, FormField.TYPE_BOOLEAN);
- setAnswer(SubscribeOptionFields.deliver.getFieldName(), digestOn);
- }
-
- /**
- * Gets the minimum number of milliseconds between sending notification digests
- *
- * @return The frequency in milliseconds
- */
- public int getDigestFrequency()
- {
- return Integer.parseInt(getFieldValue(SubscribeOptionFields.digest_frequency));
- }
-
- /**
- * Sets the minimum number of milliseconds between sending notification digests
- *
- * @param frequency The frequency in milliseconds
- */
- public void setDigestFrequency(int frequency)
- {
- addField(SubscribeOptionFields.digest_frequency, FormField.TYPE_TEXT_SINGLE);
- setAnswer(SubscribeOptionFields.digest_frequency.getFieldName(), frequency);
- }
-
- /**
- * Get the time at which the leased subscription will expire, or has expired.
- *
- * @return The expiry date
- */
- public Date getExpiry()
- {
- String dateTime = getFieldValue(SubscribeOptionFields.expire);
- try
- {
- return StringUtils.parseDate(dateTime);
- }
- catch (ParseException e)
- {
- UnknownFormatConversionException exc = new UnknownFormatConversionException(dateTime);
- exc.initCause(e);
- throw exc;
- }
- }
-
- /**
- * Sets the time at which the leased subscription will expire, or has expired.
- *
- * @param expire The expiry date
- */
- public void setExpiry(Date expire)
- {
- addField(SubscribeOptionFields.expire, FormField.TYPE_TEXT_SINGLE);
- setAnswer(SubscribeOptionFields.expire.getFieldName(), StringUtils.formatXEP0082Date(expire));
- }
-
- /**
- * Determines whether the entity wants to receive an XMPP message body in
- * addition to the payload format.
- *
- * @return true to receive the message body, false otherwise
- */
- public boolean isIncludeBody()
- {
- return parseBoolean(getFieldValue(SubscribeOptionFields.include_body));
- }
-
- /**
- * Sets whether the entity wants to receive an XMPP message body in
- * addition to the payload format.
- *
- * @param include true to receive the message body, false otherwise
- */
- public void setIncludeBody(boolean include)
- {
- addField(SubscribeOptionFields.include_body, FormField.TYPE_BOOLEAN);
- setAnswer(SubscribeOptionFields.include_body.getFieldName(), include);
- }
-
- /**
- * Gets the {@link PresenceState} for which an entity wants to receive
- * notifications.
- *
- * @return iterator over the list of states
- */
- public Iterator<PresenceState> getShowValues()
- {
- ArrayList<PresenceState> result = new ArrayList<PresenceState>(5);
- Iterator<String > it = getFieldValues(SubscribeOptionFields.show_values);
-
- while (it.hasNext())
- {
- String state = it.next();
- result.add(PresenceState.valueOf(state));
- }
- return result.iterator();
- }
-
- /**
- * Sets the list of {@link PresenceState} for which an entity wants
- * to receive notifications.
- *
- * @param stateValues The list of states
- */
- public void setShowValues(Collection<PresenceState> stateValues)
- {
- ArrayList<String> values = new ArrayList<String>(stateValues.size());
-
- for (PresenceState state : stateValues)
- {
- values.add(state.toString());
- }
- addField(SubscribeOptionFields.show_values, FormField.TYPE_LIST_MULTI);
- setAnswer(SubscribeOptionFields.show_values.getFieldName(), values);
- }
-
-
- static private boolean parseBoolean(String fieldValue)
- {
- return ("1".equals(fieldValue) || "true".equals(fieldValue));
- }
-
- private String getFieldValue(SubscribeOptionFields field)
- {
- FormField formField = getField(field.getFieldName());
-
- return formField.getValues().next();
- }
-
- private Iterator<String> getFieldValues(SubscribeOptionFields field)
- {
- FormField formField = getField(field.getFieldName());
-
- return formField.getValues();
- }
-
- private void addField(SubscribeOptionFields nodeField, String type)
- {
- String fieldName = nodeField.getFieldName();
-
- if (getField(fieldName) == null)
- {
- FormField field = new FormField(fieldName);
- field.setType(type);
- addField(field);
- }
- }
-}
+/**
+ * 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.pubsub;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.UnknownFormatConversionException;
+
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.FormField;
+import org.jivesoftware.smackx.packet.DataForm;
+
+/**
+ * A decorator for a {@link Form} to easily enable reading and updating
+ * of subscription options. All operations read or update the underlying {@link DataForm}.
+ *
+ * <p>Unlike the {@link Form}.setAnswer(XXX)} methods, which throw an exception if the field does not
+ * exist, all <b>SubscribeForm.setXXX</b> methods will create the field in the wrapped form
+ * if it does not already exist.
+ *
+ * @author Robin Collier
+ */
+public class SubscribeForm extends Form
+{
+ public SubscribeForm(DataForm configDataForm)
+ {
+ super(configDataForm);
+ }
+
+ public SubscribeForm(Form subscribeOptionsForm)
+ {
+ super(subscribeOptionsForm.getDataFormToSend());
+ }
+
+ public SubscribeForm(FormType formType)
+ {
+ super(formType.toString());
+ }
+
+ /**
+ * Determines if an entity wants to receive notifications.
+ *
+ * @return true if want to receive, false otherwise
+ */
+ public boolean isDeliverOn()
+ {
+ return parseBoolean(getFieldValue(SubscribeOptionFields.deliver));
+ }
+
+ /**
+ * Sets whether an entity wants to receive notifications.
+ *
+ * @param deliverNotifications
+ */
+ public void setDeliverOn(boolean deliverNotifications)
+ {
+ addField(SubscribeOptionFields.deliver, FormField.TYPE_BOOLEAN);
+ setAnswer(SubscribeOptionFields.deliver.getFieldName(), deliverNotifications);
+ }
+
+ /**
+ * Determines if notifications should be delivered as aggregations or not.
+ *
+ * @return true to aggregate, false otherwise
+ */
+ public boolean isDigestOn()
+ {
+ return parseBoolean(getFieldValue(SubscribeOptionFields.digest));
+ }
+
+ /**
+ * Sets whether notifications should be delivered as aggregations or not.
+ *
+ * @param digestOn true to aggregate, false otherwise
+ */
+ public void setDigestOn(boolean digestOn)
+ {
+ addField(SubscribeOptionFields.deliver, FormField.TYPE_BOOLEAN);
+ setAnswer(SubscribeOptionFields.deliver.getFieldName(), digestOn);
+ }
+
+ /**
+ * Gets the minimum number of milliseconds between sending notification digests
+ *
+ * @return The frequency in milliseconds
+ */
+ public int getDigestFrequency()
+ {
+ return Integer.parseInt(getFieldValue(SubscribeOptionFields.digest_frequency));
+ }
+
+ /**
+ * Sets the minimum number of milliseconds between sending notification digests
+ *
+ * @param frequency The frequency in milliseconds
+ */
+ public void setDigestFrequency(int frequency)
+ {
+ addField(SubscribeOptionFields.digest_frequency, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(SubscribeOptionFields.digest_frequency.getFieldName(), frequency);
+ }
+
+ /**
+ * Get the time at which the leased subscription will expire, or has expired.
+ *
+ * @return The expiry date
+ */
+ public Date getExpiry()
+ {
+ String dateTime = getFieldValue(SubscribeOptionFields.expire);
+ try
+ {
+ return StringUtils.parseDate(dateTime);
+ }
+ catch (ParseException e)
+ {
+ UnknownFormatConversionException exc = new UnknownFormatConversionException(dateTime);
+ exc.initCause(e);
+ throw exc;
+ }
+ }
+
+ /**
+ * Sets the time at which the leased subscription will expire, or has expired.
+ *
+ * @param expire The expiry date
+ */
+ public void setExpiry(Date expire)
+ {
+ addField(SubscribeOptionFields.expire, FormField.TYPE_TEXT_SINGLE);
+ setAnswer(SubscribeOptionFields.expire.getFieldName(), StringUtils.formatXEP0082Date(expire));
+ }
+
+ /**
+ * Determines whether the entity wants to receive an XMPP message body in
+ * addition to the payload format.
+ *
+ * @return true to receive the message body, false otherwise
+ */
+ public boolean isIncludeBody()
+ {
+ return parseBoolean(getFieldValue(SubscribeOptionFields.include_body));
+ }
+
+ /**
+ * Sets whether the entity wants to receive an XMPP message body in
+ * addition to the payload format.
+ *
+ * @param include true to receive the message body, false otherwise
+ */
+ public void setIncludeBody(boolean include)
+ {
+ addField(SubscribeOptionFields.include_body, FormField.TYPE_BOOLEAN);
+ setAnswer(SubscribeOptionFields.include_body.getFieldName(), include);
+ }
+
+ /**
+ * Gets the {@link PresenceState} for which an entity wants to receive
+ * notifications.
+ *
+ * @return iterator over the list of states
+ */
+ public Iterator<PresenceState> getShowValues()
+ {
+ ArrayList<PresenceState> result = new ArrayList<PresenceState>(5);
+ Iterator<String > it = getFieldValues(SubscribeOptionFields.show_values);
+
+ while (it.hasNext())
+ {
+ String state = it.next();
+ result.add(PresenceState.valueOf(state));
+ }
+ return result.iterator();
+ }
+
+ /**
+ * Sets the list of {@link PresenceState} for which an entity wants
+ * to receive notifications.
+ *
+ * @param stateValues The list of states
+ */
+ public void setShowValues(Collection<PresenceState> stateValues)
+ {
+ ArrayList<String> values = new ArrayList<String>(stateValues.size());
+
+ for (PresenceState state : stateValues)
+ {
+ values.add(state.toString());
+ }
+ addField(SubscribeOptionFields.show_values, FormField.TYPE_LIST_MULTI);
+ setAnswer(SubscribeOptionFields.show_values.getFieldName(), values);
+ }
+
+
+ static private boolean parseBoolean(String fieldValue)
+ {
+ return ("1".equals(fieldValue) || "true".equals(fieldValue));
+ }
+
+ private String getFieldValue(SubscribeOptionFields field)
+ {
+ FormField formField = getField(field.getFieldName());
+
+ return formField.getValues().next();
+ }
+
+ private Iterator<String> getFieldValues(SubscribeOptionFields field)
+ {
+ FormField formField = getField(field.getFieldName());
+
+ return formField.getValues();
+ }
+
+ private void addField(SubscribeOptionFields nodeField, String type)
+ {
+ String fieldName = nodeField.getFieldName();
+
+ if (getField(fieldName) == null)
+ {
+ FormField field = new FormField(fieldName);
+ field.setType(type);
+ addField(field);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeOptionFields.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeOptionFields.java
index dfca6016f..463a40f43 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeOptionFields.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscribeOptionFields.java
@@ -1,99 +1,99 @@
-/**
- * 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.pubsub;
-
-import java.util.Calendar;
-
-/**
- * Defines the possible field options for a subscribe options form as defined
- * by <a href="http://xmpp.org/extensions/xep-0060.html#registrar-formtypes-subscribe">Section 16.4.2</a>.
- *
- * @author Robin Collier
- */
-public enum SubscribeOptionFields
-{
- /**
- * Whether an entity wants to receive or disable notifications
- *
- * <p><b>Value: boolean</b></p>
- */
- deliver,
-
- /**
- * Whether an entity wants to receive digests (aggregations) of
- * notifications or all notifications individually.
- *
- * <p><b>Value: boolean</b></p>
- */
- digest,
-
- /**
- * The minimum number of seconds between sending any two notifications digests
- *
- * <p><b>Value: int</b></p>
- */
- digest_frequency,
-
- /**
- * The DateTime at which a leased subsscription will end ro has ended.
- *
- * <p><b>Value: {@link Calendar}</b></p>
- */
- expire,
-
- /**
- * Whether an entity wants to receive an XMPP message body in addition to
- * the payload format.
- *
- * <p><b>Value: boolean</b></p>
- */
- include_body,
-
- /**
- * The presence states for which an entity wants to receive notifications.
- *
- * <p><b>Value: {@link PresenceState}</b></p>
- */
- show_values,
-
- /**
- *
- *
- * <p><b>Value: </b></p>
- */
- subscription_type,
-
- /**
- *
- * <p><b>Value: </b></p>
- */
- subscription_depth;
-
- public String getFieldName()
- {
- if (this == show_values)
- return "pubsub#" + toString().replace('_', '-');
- return "pubsub#" + toString();
- }
-
- static public SubscribeOptionFields valueOfFromElement(String elementName)
- {
- String portion = elementName.substring(elementName.lastIndexOf('#' + 1));
-
- if ("show-values".equals(portion))
- return show_values;
- else
- return valueOf(portion);
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.Calendar;
+
+/**
+ * Defines the possible field options for a subscribe options form as defined
+ * by <a href="http://xmpp.org/extensions/xep-0060.html#registrar-formtypes-subscribe">Section 16.4.2</a>.
+ *
+ * @author Robin Collier
+ */
+public enum SubscribeOptionFields
+{
+ /**
+ * Whether an entity wants to receive or disable notifications
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ deliver,
+
+ /**
+ * Whether an entity wants to receive digests (aggregations) of
+ * notifications or all notifications individually.
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ digest,
+
+ /**
+ * The minimum number of seconds between sending any two notifications digests
+ *
+ * <p><b>Value: int</b></p>
+ */
+ digest_frequency,
+
+ /**
+ * The DateTime at which a leased subsscription will end ro has ended.
+ *
+ * <p><b>Value: {@link Calendar}</b></p>
+ */
+ expire,
+
+ /**
+ * Whether an entity wants to receive an XMPP message body in addition to
+ * the payload format.
+ *
+ * <p><b>Value: boolean</b></p>
+ */
+ include_body,
+
+ /**
+ * The presence states for which an entity wants to receive notifications.
+ *
+ * <p><b>Value: {@link PresenceState}</b></p>
+ */
+ show_values,
+
+ /**
+ *
+ *
+ * <p><b>Value: </b></p>
+ */
+ subscription_type,
+
+ /**
+ *
+ * <p><b>Value: </b></p>
+ */
+ subscription_depth;
+
+ public String getFieldName()
+ {
+ if (this == show_values)
+ return "pubsub#" + toString().replace('_', '-');
+ return "pubsub#" + toString();
+ }
+
+ static public SubscribeOptionFields valueOfFromElement(String elementName)
+ {
+ String portion = elementName.substring(elementName.lastIndexOf('#' + 1));
+
+ if ("show-values".equals(portion))
+ return show_values;
+ else
+ return valueOf(portion);
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Subscription.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Subscription.java
index 19ad8a8f1..49d9a4a74 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Subscription.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/Subscription.java
@@ -1,160 +1,160 @@
-/**
- * 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.pubsub;
-
-/**
- * Represents a subscription to node for both requests and replies.
- *
- * @author Robin Collier
- */
-public class Subscription extends NodeExtension
-{
- protected String jid;
- protected String id;
- protected State state;
- protected boolean configRequired = false;
-
- public enum State
- {
- subscribed, unconfigured, pending, none
- }
-
- /**
- * Used to constructs a subscription request to the root node with the specified
- * JID.
- *
- * @param subscriptionJid The subscriber JID
- */
- public Subscription(String subscriptionJid)
- {
- this(subscriptionJid, null, null, null);
- }
-
- /**
- * Used to constructs a subscription request to the specified node with the specified
- * JID.
- *
- * @param subscriptionJid The subscriber JID
- * @param nodeId The node id
- */
- public Subscription(String subscriptionJid, String nodeId)
- {
- this(subscriptionJid, nodeId, null, null);
- }
-
- /**
- * Constructs a representation of a subscription reply to the specified node
- * and JID. The server will have supplied the subscription id and current state.
- *
- * @param jid The JID the request was made under
- * @param nodeId The node subscribed to
- * @param subscriptionId The id of this subscription
- * @param state The current state of the subscription
- */
- public Subscription(String jid, String nodeId, String subscriptionId, State state)
- {
- super(PubSubElementType.SUBSCRIPTION, nodeId);
- this.jid = jid;
- id = subscriptionId;
- this.state = state;
- }
-
- /**
- * Constructs a representation of a subscription reply to the specified node
- * and JID. The server will have supplied the subscription id and current state
- * and whether the subscription need to be configured.
- *
- * @param jid The JID the request was made under
- * @param nodeId The node subscribed to
- * @param subscriptionId The id of this subscription
- * @param state The current state of the subscription
- * @param configRequired Is configuration required to complete the subscription
- */
- public Subscription(String jid, String nodeId, String subscriptionId, State state, boolean configRequired)
- {
- super(PubSubElementType.SUBSCRIPTION, nodeId);
- this.jid = jid;
- id = subscriptionId;
- this.state = state;
- this.configRequired = configRequired;
- }
-
- /**
- * Gets the JID the subscription is created for
- *
- * @return The JID
- */
- public String getJid()
- {
- return jid;
- }
-
- /**
- * Gets the subscription id
- *
- * @return The subscription id
- */
- public String getId()
- {
- return id;
- }
-
- /**
- * Gets the current subscription state.
- *
- * @return Current subscription state
- */
- public State getState()
- {
- return state;
- }
-
- /**
- * This value is only relevant when the {@link #getState()} is {@link State#unconfigured}
- *
- * @return true if configuration is required, false otherwise
- */
- public boolean isConfigRequired()
- {
- return configRequired;
- }
-
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<subscription");
- appendAttribute(builder, "jid", jid);
-
- if (getNode() != null)
- appendAttribute(builder, "node", getNode());
-
- if (id != null)
- appendAttribute(builder, "subid", id);
-
- if (state != null)
- appendAttribute(builder, "subscription", state.toString());
-
- builder.append("/>");
- return builder.toString();
- }
-
- private void appendAttribute(StringBuilder builder, String att, String value)
- {
- builder.append(" ");
- builder.append(att);
- builder.append("='");
- builder.append(value);
- builder.append("'");
- }
-
-}
+/**
+ * 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.pubsub;
+
+/**
+ * Represents a subscription to node for both requests and replies.
+ *
+ * @author Robin Collier
+ */
+public class Subscription extends NodeExtension
+{
+ protected String jid;
+ protected String id;
+ protected State state;
+ protected boolean configRequired = false;
+
+ public enum State
+ {
+ subscribed, unconfigured, pending, none
+ }
+
+ /**
+ * Used to constructs a subscription request to the root node with the specified
+ * JID.
+ *
+ * @param subscriptionJid The subscriber JID
+ */
+ public Subscription(String subscriptionJid)
+ {
+ this(subscriptionJid, null, null, null);
+ }
+
+ /**
+ * Used to constructs a subscription request to the specified node with the specified
+ * JID.
+ *
+ * @param subscriptionJid The subscriber JID
+ * @param nodeId The node id
+ */
+ public Subscription(String subscriptionJid, String nodeId)
+ {
+ this(subscriptionJid, nodeId, null, null);
+ }
+
+ /**
+ * Constructs a representation of a subscription reply to the specified node
+ * and JID. The server will have supplied the subscription id and current state.
+ *
+ * @param jid The JID the request was made under
+ * @param nodeId The node subscribed to
+ * @param subscriptionId The id of this subscription
+ * @param state The current state of the subscription
+ */
+ public Subscription(String jid, String nodeId, String subscriptionId, State state)
+ {
+ super(PubSubElementType.SUBSCRIPTION, nodeId);
+ this.jid = jid;
+ id = subscriptionId;
+ this.state = state;
+ }
+
+ /**
+ * Constructs a representation of a subscription reply to the specified node
+ * and JID. The server will have supplied the subscription id and current state
+ * and whether the subscription need to be configured.
+ *
+ * @param jid The JID the request was made under
+ * @param nodeId The node subscribed to
+ * @param subscriptionId The id of this subscription
+ * @param state The current state of the subscription
+ * @param configRequired Is configuration required to complete the subscription
+ */
+ public Subscription(String jid, String nodeId, String subscriptionId, State state, boolean configRequired)
+ {
+ super(PubSubElementType.SUBSCRIPTION, nodeId);
+ this.jid = jid;
+ id = subscriptionId;
+ this.state = state;
+ this.configRequired = configRequired;
+ }
+
+ /**
+ * Gets the JID the subscription is created for
+ *
+ * @return The JID
+ */
+ public String getJid()
+ {
+ return jid;
+ }
+
+ /**
+ * Gets the subscription id
+ *
+ * @return The subscription id
+ */
+ public String getId()
+ {
+ return id;
+ }
+
+ /**
+ * Gets the current subscription state.
+ *
+ * @return Current subscription state
+ */
+ public State getState()
+ {
+ return state;
+ }
+
+ /**
+ * This value is only relevant when the {@link #getState()} is {@link State#unconfigured}
+ *
+ * @return true if configuration is required, false otherwise
+ */
+ public boolean isConfigRequired()
+ {
+ return configRequired;
+ }
+
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<subscription");
+ appendAttribute(builder, "jid", jid);
+
+ if (getNode() != null)
+ appendAttribute(builder, "node", getNode());
+
+ if (id != null)
+ appendAttribute(builder, "subid", id);
+
+ if (state != null)
+ appendAttribute(builder, "subscription", state.toString());
+
+ builder.append("/>");
+ return builder.toString();
+ }
+
+ private void appendAttribute(StringBuilder builder, String att, String value)
+ {
+ builder.append(" ");
+ builder.append(att);
+ builder.append("='");
+ builder.append(value);
+ builder.append("'");
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionEvent.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionEvent.java
index 99f18d5f1..a72145284 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionEvent.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionEvent.java
@@ -1,75 +1,75 @@
-/**
- * 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.pubsub;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Base class to represents events that are associated to subscriptions.
- *
- * @author Robin Collier
- */
-abstract public class SubscriptionEvent extends NodeEvent
-{
- private List<String> subIds = Collections.EMPTY_LIST;
-
- /**
- * Construct an event with no subscription id's. This can
- * occur when there is only one subscription to a node. The
- * event may or may not report the subscription id along
- * with the event.
- *
- * @param nodeId The id of the node the event came from
- */
- protected SubscriptionEvent(String nodeId)
- {
- super(nodeId);
- }
-
- /**
- * Construct an event with multiple subscriptions.
- *
- * @param nodeId The id of the node the event came from
- * @param subscriptionIds The list of subscription id's
- */
- protected SubscriptionEvent(String nodeId, List<String> subscriptionIds)
- {
- super(nodeId);
-
- if (subscriptionIds != null)
- subIds = subscriptionIds;
- }
-
- /**
- * Get the subscriptions this event is associated with.
- *
- * @return List of subscription id's
- */
- public List<String> getSubscriptions()
- {
- return Collections.unmodifiableList(subIds);
- }
-
- /**
- * Set the list of subscription id's for this event.
- *
- * @param subscriptionIds The list of subscription id's
- */
- protected void setSubscriptions(List<String> subscriptionIds)
- {
- if (subscriptionIds != null)
- subIds = subscriptionIds;
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Base class to represents events that are associated to subscriptions.
+ *
+ * @author Robin Collier
+ */
+abstract public class SubscriptionEvent extends NodeEvent
+{
+ private List<String> subIds = Collections.EMPTY_LIST;
+
+ /**
+ * Construct an event with no subscription id's. This can
+ * occur when there is only one subscription to a node. The
+ * event may or may not report the subscription id along
+ * with the event.
+ *
+ * @param nodeId The id of the node the event came from
+ */
+ protected SubscriptionEvent(String nodeId)
+ {
+ super(nodeId);
+ }
+
+ /**
+ * Construct an event with multiple subscriptions.
+ *
+ * @param nodeId The id of the node the event came from
+ * @param subscriptionIds The list of subscription id's
+ */
+ protected SubscriptionEvent(String nodeId, List<String> subscriptionIds)
+ {
+ super(nodeId);
+
+ if (subscriptionIds != null)
+ subIds = subscriptionIds;
+ }
+
+ /**
+ * Get the subscriptions this event is associated with.
+ *
+ * @return List of subscription id's
+ */
+ public List<String> getSubscriptions()
+ {
+ return Collections.unmodifiableList(subIds);
+ }
+
+ /**
+ * Set the list of subscription id's for this event.
+ *
+ * @param subscriptionIds The list of subscription id's
+ */
+ protected void setSubscriptions(List<String> subscriptionIds)
+ {
+ if (subscriptionIds != null)
+ subIds = subscriptionIds;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionsExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionsExtension.java
index a28cbe2c9..396b36db8 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionsExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/SubscriptionsExtension.java
@@ -1,96 +1,96 @@
-/**
- * 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.pubsub;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Represents the element holding the list of subscription elements.
- *
- * @author Robin Collier
- */
-public class SubscriptionsExtension extends NodeExtension
-{
- protected List<Subscription> items = Collections.EMPTY_LIST;
-
- /**
- * Subscriptions to the root node
- *
- * @param subList The list of subscriptions
- */
- public SubscriptionsExtension(List<Subscription> subList)
- {
- super(PubSubElementType.SUBSCRIPTIONS);
-
- if (subList != null)
- items = subList;
- }
-
- /**
- * Subscriptions to the specified node.
- *
- * @param nodeId The node subscribed to
- * @param subList The list of subscriptions
- */
- public SubscriptionsExtension(String nodeId, List<Subscription> subList)
- {
- super(PubSubElementType.SUBSCRIPTIONS, nodeId);
-
- if (subList != null)
- items = subList;
- }
-
- /**
- * Gets the list of subscriptions.
- *
- * @return List of subscriptions
- */
- public List<Subscription> getSubscriptions()
- {
- return items;
- }
-
- @Override
- public String toXML()
- {
- if ((items == null) || (items.size() == 0))
- {
- return super.toXML();
- }
- else
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
-
- if (getNode() != null)
- {
- builder.append(" node='");
- builder.append(getNode());
- builder.append("'");
- }
- builder.append(">");
-
- for (Subscription item : items)
- {
- builder.append(item.toXML());
- }
-
- builder.append("</");
- builder.append(getElementName());
- builder.append(">");
- return builder.toString();
- }
- }
-}
+/**
+ * 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.pubsub;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents the element holding the list of subscription elements.
+ *
+ * @author Robin Collier
+ */
+public class SubscriptionsExtension extends NodeExtension
+{
+ protected List<Subscription> items = Collections.EMPTY_LIST;
+
+ /**
+ * Subscriptions to the root node
+ *
+ * @param subList The list of subscriptions
+ */
+ public SubscriptionsExtension(List<Subscription> subList)
+ {
+ super(PubSubElementType.SUBSCRIPTIONS);
+
+ if (subList != null)
+ items = subList;
+ }
+
+ /**
+ * Subscriptions to the specified node.
+ *
+ * @param nodeId The node subscribed to
+ * @param subList The list of subscriptions
+ */
+ public SubscriptionsExtension(String nodeId, List<Subscription> subList)
+ {
+ super(PubSubElementType.SUBSCRIPTIONS, nodeId);
+
+ if (subList != null)
+ items = subList;
+ }
+
+ /**
+ * Gets the list of subscriptions.
+ *
+ * @return List of subscriptions
+ */
+ public List<Subscription> getSubscriptions()
+ {
+ return items;
+ }
+
+ @Override
+ public String toXML()
+ {
+ if ((items == null) || (items.size() == 0))
+ {
+ return super.toXML();
+ }
+ else
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+
+ if (getNode() != null)
+ {
+ builder.append(" node='");
+ builder.append(getNode());
+ builder.append("'");
+ }
+ builder.append(">");
+
+ for (Subscription item : items)
+ {
+ builder.append(item.toXML());
+ }
+
+ builder.append("</");
+ builder.append(getElementName());
+ builder.append(">");
+ return builder.toString();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/UnsubscribeExtension.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/UnsubscribeExtension.java
index ac14c603a..dc815caf4 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/UnsubscribeExtension.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/UnsubscribeExtension.java
@@ -1,73 +1,73 @@
-/**
- * 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.pubsub;
-
-import org.jivesoftware.smackx.pubsub.util.XmlUtils;
-
-
-/**
- * Represents an unsubscribe element.
- *
- * @author Robin Collier
- */
-public class UnsubscribeExtension extends NodeExtension
-{
- protected String jid;
- protected String id;
-
- public UnsubscribeExtension(String subscriptionJid)
- {
- this(subscriptionJid, null, null);
- }
-
- public UnsubscribeExtension(String subscriptionJid, String nodeId)
- {
- this(subscriptionJid, nodeId, null);
- }
-
- public UnsubscribeExtension(String jid, String nodeId, String subscriptionId)
- {
- super(PubSubElementType.UNSUBSCRIBE, nodeId);
- this.jid = jid;
- id = subscriptionId;
- }
-
- public String getJid()
- {
- return jid;
- }
-
- public String getId()
- {
- return id;
- }
-
- @Override
- public String toXML()
- {
- StringBuilder builder = new StringBuilder("<");
- builder.append(getElementName());
- XmlUtils.appendAttribute(builder, "jid", jid);
-
- if (getNode() != null)
- XmlUtils.appendAttribute(builder, "node", getNode());
-
- if (id != null)
- XmlUtils.appendAttribute(builder, "subid", id);
-
- builder.append("/>");
- return builder.toString();
- }
-
-}
+/**
+ * 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.pubsub;
+
+import org.jivesoftware.smackx.pubsub.util.XmlUtils;
+
+
+/**
+ * Represents an unsubscribe element.
+ *
+ * @author Robin Collier
+ */
+public class UnsubscribeExtension extends NodeExtension
+{
+ protected String jid;
+ protected String id;
+
+ public UnsubscribeExtension(String subscriptionJid)
+ {
+ this(subscriptionJid, null, null);
+ }
+
+ public UnsubscribeExtension(String subscriptionJid, String nodeId)
+ {
+ this(subscriptionJid, nodeId, null);
+ }
+
+ public UnsubscribeExtension(String jid, String nodeId, String subscriptionId)
+ {
+ super(PubSubElementType.UNSUBSCRIBE, nodeId);
+ this.jid = jid;
+ id = subscriptionId;
+ }
+
+ public String getJid()
+ {
+ return jid;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ @Override
+ public String toXML()
+ {
+ StringBuilder builder = new StringBuilder("<");
+ builder.append(getElementName());
+ XmlUtils.appendAttribute(builder, "jid", jid);
+
+ if (getNode() != null)
+ XmlUtils.appendAttribute(builder, "node", getNode());
+
+ if (id != null)
+ XmlUtils.appendAttribute(builder, "subid", id);
+
+ builder.append("/>");
+ return builder.toString();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemDeleteListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemDeleteListener.java
index d228e8f09..9b9c31066 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemDeleteListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemDeleteListener.java
@@ -1,41 +1,41 @@
-/**
- * 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.pubsub.listener;
-
-import org.jivesoftware.smackx.pubsub.ItemDeleteEvent;
-import org.jivesoftware.smackx.pubsub.LeafNode;
-
-/**
- * Defines the listener for item deletion events from a node.
- *
- * @see LeafNode#addItemDeleteListener(ItemDeleteListener)
- *
- * @author Robin Collier
- */
-public interface ItemDeleteListener
-{
- /**
- * Called when items are deleted from a node the listener is
- * registered with.
- *
- * @param items The event with item deletion details
- */
- void handleDeletedItems(ItemDeleteEvent items);
-
- /**
- * Called when <b>all</b> items are deleted from a node the listener is
- * registered with.
- */
- void handlePurge();
-}
+/**
+ * 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.pubsub.listener;
+
+import org.jivesoftware.smackx.pubsub.ItemDeleteEvent;
+import org.jivesoftware.smackx.pubsub.LeafNode;
+
+/**
+ * Defines the listener for item deletion events from a node.
+ *
+ * @see LeafNode#addItemDeleteListener(ItemDeleteListener)
+ *
+ * @author Robin Collier
+ */
+public interface ItemDeleteListener
+{
+ /**
+ * Called when items are deleted from a node the listener is
+ * registered with.
+ *
+ * @param items The event with item deletion details
+ */
+ void handleDeletedItems(ItemDeleteEvent items);
+
+ /**
+ * Called when <b>all</b> items are deleted from a node the listener is
+ * registered with.
+ */
+ void handlePurge();
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemEventListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemEventListener.java
index 714b2c088..0556eeabf 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemEventListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/ItemEventListener.java
@@ -1,36 +1,36 @@
-/**
- * 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.pubsub.listener;
-
-import org.jivesoftware.smackx.pubsub.Item;
-import org.jivesoftware.smackx.pubsub.ItemPublishEvent;
-import org.jivesoftware.smackx.pubsub.LeafNode;
-
-/**
- * Defines the listener for items being published to a node.
- *
- * @see LeafNode#addItemEventListener(ItemEventListener)
- *
- * @author Robin Collier
- */
-public interface ItemEventListener <T extends Item>
-{
- /**
- * Called whenever an item is published to the node the listener
- * is registered with.
- *
- * @param items The publishing details.
- */
- void handlePublishedItems(ItemPublishEvent<T> items);
-}
+/**
+ * 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.pubsub.listener;
+
+import org.jivesoftware.smackx.pubsub.Item;
+import org.jivesoftware.smackx.pubsub.ItemPublishEvent;
+import org.jivesoftware.smackx.pubsub.LeafNode;
+
+/**
+ * Defines the listener for items being published to a node.
+ *
+ * @see LeafNode#addItemEventListener(ItemEventListener)
+ *
+ * @author Robin Collier
+ */
+public interface ItemEventListener <T extends Item>
+{
+ /**
+ * Called whenever an item is published to the node the listener
+ * is registered with.
+ *
+ * @param items The publishing details.
+ */
+ void handlePublishedItems(ItemPublishEvent<T> items);
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/NodeConfigListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/NodeConfigListener.java
index 39db5a5db..096ed6860 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/NodeConfigListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/listener/NodeConfigListener.java
@@ -1,35 +1,35 @@
-/**
- * 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.pubsub.listener;
-
-import org.jivesoftware.smackx.pubsub.ConfigurationEvent;
-import org.jivesoftware.smackx.pubsub.LeafNode;
-
-/**
- * Defines the listener for a node being configured.
- *
- * @see LeafNode#addConfigurationListener(NodeConfigListener)
- *
- * @author Robin Collier
- */
-public interface NodeConfigListener
-{
- /**
- * Called whenever the node the listener
- * is registered with is configured.
- *
- * @param config The configuration details.
- */
- void handleNodeConfiguration(ConfigurationEvent config);
-}
+/**
+ * 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.pubsub.listener;
+
+import org.jivesoftware.smackx.pubsub.ConfigurationEvent;
+import org.jivesoftware.smackx.pubsub.LeafNode;
+
+/**
+ * Defines the listener for a node being configured.
+ *
+ * @see LeafNode#addConfigurationListener(NodeConfigListener)
+ *
+ * @author Robin Collier
+ */
+public interface NodeConfigListener
+{
+ /**
+ * Called whenever the node the listener
+ * is registered with is configured.
+ *
+ * @param config The configuration details.
+ */
+ void handleNodeConfiguration(ConfigurationEvent config);
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSub.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSub.java
index 5aa4865a4..fb7f64385 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSub.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSub.java
@@ -1,106 +1,106 @@
-/**
- * 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.pubsub.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.pubsub.PubSubElementType;
-
-/**
- * The standard PubSub extension of an {@link IQ} packet. This is the topmost
- * element of all pubsub requests and replies as defined in the <a href="http://xmpp.org/extensions/xep-0060">Publish-Subscribe</a>
- * specification.
- *
- * @author Robin Collier
- */
-public class PubSub extends IQ
-{
- private PubSubNamespace ns = PubSubNamespace.BASIC;
-
- /**
- * Returns the XML element name of the extension sub-packet root element.
- *
- * @return the XML element name of the packet extension.
- */
- public String getElementName() {
- return "pubsub";
- }
-
- /**
- * Returns the XML namespace of the extension sub-packet root element.
- * According the specification the namespace is
- * http://jabber.org/protocol/pubsub with a specific fragment depending
- * on the request. The namespace is defined at <a href="http://xmpp.org/registrar/namespaces.html">XMPP Registrar</a> at
- *
- * The default value has no fragment.
- *
- * @return the XML namespace of the packet extension.
- */
- public String getNamespace()
- {
- return ns.getXmlns();
- }
-
- /**
- * Set the namespace for the packet if it something other than the default
- * case of {@link PubSubNamespace#BASIC}. The {@link #getNamespace()} method will return
- * the result of calling {@link PubSubNamespace#getXmlns()} on the specified enum.
- *
- * @param ns - The new value for the namespace.
- */
- public void setPubSubNamespace(PubSubNamespace ns)
- {
- this.ns = ns;
- }
-
- public PacketExtension getExtension(PubSubElementType elem)
- {
- return getExtension(elem.getElementName(), elem.getNamespace().getXmlns());
- }
-
- /**
- * Returns the current value of the namespace. The {@link #getNamespace()} method will return
- * the result of calling {@link PubSubNamespace#getXmlns()} this value.
- *
- * @return The current value of the namespace.
- */
- public PubSubNamespace getPubSubNamespace()
- {
- return ns;
- }
- /**
- * Returns the XML representation of a pubsub element according the specification.
- *
- * The XML representation will be inside of an iq packet like
- * in the following example:
- * <pre>
- * &lt;iq type='set' id="MlIpV-4" to="pubsub.gato.home" from="gato3@gato.home/Smack"&gt;
- * &lt;pubsub xmlns="http://jabber.org/protocol/pubsub"&gt;
- * :
- * Specific request extension
- * :
- * &lt;/pubsub&gt;
- * &lt;/iq&gt;
- * </pre>
- *
- */
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append("\">");
- buf.append(getExtensionsXML());
- buf.append("</").append(getElementName()).append(">");
- return buf.toString();
- }
-
-}
+/**
+ * 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.pubsub.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.pubsub.PubSubElementType;
+
+/**
+ * The standard PubSub extension of an {@link IQ} packet. This is the topmost
+ * element of all pubsub requests and replies as defined in the <a href="http://xmpp.org/extensions/xep-0060">Publish-Subscribe</a>
+ * specification.
+ *
+ * @author Robin Collier
+ */
+public class PubSub extends IQ
+{
+ private PubSubNamespace ns = PubSubNamespace.BASIC;
+
+ /**
+ * Returns the XML element name of the extension sub-packet root element.
+ *
+ * @return the XML element name of the packet extension.
+ */
+ public String getElementName() {
+ return "pubsub";
+ }
+
+ /**
+ * Returns the XML namespace of the extension sub-packet root element.
+ * According the specification the namespace is
+ * http://jabber.org/protocol/pubsub with a specific fragment depending
+ * on the request. The namespace is defined at <a href="http://xmpp.org/registrar/namespaces.html">XMPP Registrar</a> at
+ *
+ * The default value has no fragment.
+ *
+ * @return the XML namespace of the packet extension.
+ */
+ public String getNamespace()
+ {
+ return ns.getXmlns();
+ }
+
+ /**
+ * Set the namespace for the packet if it something other than the default
+ * case of {@link PubSubNamespace#BASIC}. The {@link #getNamespace()} method will return
+ * the result of calling {@link PubSubNamespace#getXmlns()} on the specified enum.
+ *
+ * @param ns - The new value for the namespace.
+ */
+ public void setPubSubNamespace(PubSubNamespace ns)
+ {
+ this.ns = ns;
+ }
+
+ public PacketExtension getExtension(PubSubElementType elem)
+ {
+ return getExtension(elem.getElementName(), elem.getNamespace().getXmlns());
+ }
+
+ /**
+ * Returns the current value of the namespace. The {@link #getNamespace()} method will return
+ * the result of calling {@link PubSubNamespace#getXmlns()} this value.
+ *
+ * @return The current value of the namespace.
+ */
+ public PubSubNamespace getPubSubNamespace()
+ {
+ return ns;
+ }
+ /**
+ * Returns the XML representation of a pubsub element according the specification.
+ *
+ * The XML representation will be inside of an iq packet like
+ * in the following example:
+ * <pre>
+ * &lt;iq type='set' id="MlIpV-4" to="pubsub.gato.home" from="gato3@gato.home/Smack"&gt;
+ * &lt;pubsub xmlns="http://jabber.org/protocol/pubsub"&gt;
+ * :
+ * Specific request extension
+ * :
+ * &lt;/pubsub&gt;
+ * &lt;/iq&gt;
+ * </pre>
+ *
+ */
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append("\">");
+ buf.append(getExtensionsXML());
+ buf.append("</").append(getElementName()).append(">");
+ return buf.toString();
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSubNamespace.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSubNamespace.java
index eecf95950..4fa8ad2ce 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSubNamespace.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/PubSubNamespace.java
@@ -1,63 +1,63 @@
-/**
- * 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.pubsub.packet;
-
-/**
- * Defines all the valid namespaces that are used with the {@link PubSub} packet
- * as defined by the specification.
- *
- * @author Robin Collier
- */
-public enum PubSubNamespace
-{
- BASIC(null),
- ERROR("errors"),
- EVENT("event"),
- OWNER("owner");
-
- private String fragment;
-
- private PubSubNamespace(String fragment)
- {
- this.fragment = fragment;
- }
-
- public String getXmlns()
- {
- String ns = "http://jabber.org/protocol/pubsub";
-
- if (fragment != null)
- ns += '#' + fragment;
-
- return ns;
- }
-
- public String getFragment()
- {
- return fragment;
- }
-
- public static PubSubNamespace valueOfFromXmlns(String ns)
- {
- int index = ns.lastIndexOf('#');
-
- if (index != -1)
- {
- String suffix = ns.substring(ns.lastIndexOf('#')+1);
- return valueOf(suffix.toUpperCase());
- }
- else
- return BASIC;
- }
-}
+/**
+ * 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.pubsub.packet;
+
+/**
+ * Defines all the valid namespaces that are used with the {@link PubSub} packet
+ * as defined by the specification.
+ *
+ * @author Robin Collier
+ */
+public enum PubSubNamespace
+{
+ BASIC(null),
+ ERROR("errors"),
+ EVENT("event"),
+ OWNER("owner");
+
+ private String fragment;
+
+ private PubSubNamespace(String fragment)
+ {
+ this.fragment = fragment;
+ }
+
+ public String getXmlns()
+ {
+ String ns = "http://jabber.org/protocol/pubsub";
+
+ if (fragment != null)
+ ns += '#' + fragment;
+
+ return ns;
+ }
+
+ public String getFragment()
+ {
+ return fragment;
+ }
+
+ public static PubSubNamespace valueOfFromXmlns(String ns)
+ {
+ int index = ns.lastIndexOf('#');
+
+ if (index != -1)
+ {
+ String suffix = ns.substring(ns.lastIndexOf('#')+1);
+ return valueOf(suffix.toUpperCase());
+ }
+ else
+ return BASIC;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/SyncPacketSend.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/SyncPacketSend.java
index 080129bd0..ff730c491 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/SyncPacketSend.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/packet/SyncPacketSend.java
@@ -1,63 +1,63 @@
-/**
- * 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.pubsub.packet;
-
-import org.jivesoftware.smack.PacketCollector;
-import org.jivesoftware.smack.SmackConfiguration;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketIDFilter;
-import org.jivesoftware.smack.packet.Packet;
-
-/**
- * Utility class for doing synchronous calls to the server. Provides several
- * methods for sending a packet to the server and waiting for the reply.
- *
- * @author Robin Collier
- */
-final public class SyncPacketSend
-{
- private SyncPacketSend()
- { }
-
- static public Packet getReply(Connection connection, Packet packet, long timeout)
- throws XMPPException
- {
- PacketFilter responseFilter = new PacketIDFilter(packet.getPacketID());
- PacketCollector response = connection.createPacketCollector(responseFilter);
-
- connection.sendPacket(packet);
-
- // Wait up to a certain number of seconds for a reply.
- Packet result = response.nextResult(timeout);
-
- // Stop queuing results
- response.cancel();
-
- if (result == null) {
- throw new XMPPException("No response from server.");
- }
- else if (result.getError() != null) {
- throw new XMPPException(result.getError());
- }
- return result;
- }
-
- static public Packet getReply(Connection connection, Packet packet)
- throws XMPPException
- {
- return getReply(connection, packet, SmackConfiguration.getPacketReplyTimeout());
- }
-}
+/**
+ * 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.pubsub.packet;
+
+import org.jivesoftware.smack.PacketCollector;
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketIDFilter;
+import org.jivesoftware.smack.packet.Packet;
+
+/**
+ * Utility class for doing synchronous calls to the server. Provides several
+ * methods for sending a packet to the server and waiting for the reply.
+ *
+ * @author Robin Collier
+ */
+final public class SyncPacketSend
+{
+ private SyncPacketSend()
+ { }
+
+ static public Packet getReply(Connection connection, Packet packet, long timeout)
+ throws XMPPException
+ {
+ PacketFilter responseFilter = new PacketIDFilter(packet.getPacketID());
+ PacketCollector response = connection.createPacketCollector(responseFilter);
+
+ connection.sendPacket(packet);
+
+ // Wait up to a certain number of seconds for a reply.
+ Packet result = response.nextResult(timeout);
+
+ // Stop queuing results
+ response.cancel();
+
+ if (result == null) {
+ throw new XMPPException("No response from server.");
+ }
+ else if (result.getError() != null) {
+ throw new XMPPException(result.getError());
+ }
+ return result;
+ }
+
+ static public Packet getReply(Connection connection, Packet packet)
+ throws XMPPException
+ {
+ return getReply(connection, packet, SmackConfiguration.getPacketReplyTimeout());
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java
index 4e27c5075..771c5e97a 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java
@@ -1,37 +1,37 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.Affiliation;
-
-/**
- * Parses the affiliation element out of the reply stanza from the server
- * as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-pubsub">affiliation schema</a>.
- *
- * @author Robin Collier
- */
-public class AffiliationProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new Affiliation(attributeMap.get("node"), Affiliation.Type.valueOf(attributeMap.get("affiliation")));
- }
-
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.Affiliation;
+
+/**
+ * Parses the affiliation element out of the reply stanza from the server
+ * as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-pubsub">affiliation schema</a>.
+ *
+ * @author Robin Collier
+ */
+public class AffiliationProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new Affiliation(attributeMap.get("node"), Affiliation.Type.valueOf(attributeMap.get("affiliation")));
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java
index 9bfeb8110..0ccd596d7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java
@@ -1,38 +1,38 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.Affiliation;
-import org.jivesoftware.smackx.pubsub.AffiliationsExtension;
-
-/**
- * Parses the affiliations element out of the reply stanza from the server
- * as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-pubsub">affiliation schema</a>.
- *
- * @author Robin Collier
- */public class AffiliationsProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new AffiliationsExtension((List<Affiliation>)content);
- }
-
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.Affiliation;
+import org.jivesoftware.smackx.pubsub.AffiliationsExtension;
+
+/**
+ * Parses the affiliations element out of the reply stanza from the server
+ * as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-pubsub">affiliation schema</a>.
+ *
+ * @author Robin Collier
+ */public class AffiliationsProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new AffiliationsExtension((List<Affiliation>)content);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ConfigEventProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ConfigEventProvider.java
index 30e3017ce..5c1d88df2 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ConfigEventProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ConfigEventProvider.java
@@ -1,42 +1,42 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.packet.DataForm;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.ConfigurationEvent;
-import org.jivesoftware.smackx.pubsub.ConfigureForm;
-
-/**
- * Parses the node configuration element out of the message event stanza from
- * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-event">configuration schema</a>.
- *
- * @author Robin Collier
- */
-public class ConfigEventProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attMap, List<? extends PacketExtension> content)
- {
- if (content.size() == 0)
- return new ConfigurationEvent(attMap.get("node"));
- else
- return new ConfigurationEvent(attMap.get("node"), new ConfigureForm((DataForm)content.iterator().next()));
- }
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.packet.DataForm;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.ConfigurationEvent;
+import org.jivesoftware.smackx.pubsub.ConfigureForm;
+
+/**
+ * Parses the node configuration element out of the message event stanza from
+ * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-event">configuration schema</a>.
+ *
+ * @author Robin Collier
+ */
+public class ConfigEventProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attMap, List<? extends PacketExtension> content)
+ {
+ if (content.size() == 0)
+ return new ConfigurationEvent(attMap.get("node"));
+ else
+ return new ConfigurationEvent(attMap.get("node"), new ConfigureForm((DataForm)content.iterator().next()));
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/EventProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/EventProvider.java
index ef5671ec8..b216335b4 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/EventProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/EventProvider.java
@@ -1,38 +1,38 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.EventElement;
-import org.jivesoftware.smackx.pubsub.EventElementType;
-import org.jivesoftware.smackx.pubsub.NodeExtension;
-
-/**
- * Parses the event element out of the message stanza from
- * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-event">event schema</a>.
- *
- * @author Robin Collier
- */
-public class EventProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attMap, List<? extends PacketExtension> content)
- {
- return new EventElement(EventElementType.valueOf(content.get(0).getElementName()), (NodeExtension)content.get(0));
- }
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.EventElement;
+import org.jivesoftware.smackx.pubsub.EventElementType;
+import org.jivesoftware.smackx.pubsub.NodeExtension;
+
+/**
+ * Parses the event element out of the message stanza from
+ * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-event">event schema</a>.
+ *
+ * @author Robin Collier
+ */
+public class EventProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attMap, List<? extends PacketExtension> content)
+ {
+ return new EventElement(EventElementType.valueOf(content.get(0).getElementName()), (NodeExtension)content.get(0));
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java
index da75b2487..5a1152992 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java
@@ -1,39 +1,39 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.packet.DataForm;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.FormNode;
-import org.jivesoftware.smackx.pubsub.FormNodeType;
-
-/**
- * Parses one of several elements used in pubsub that contain a form of some kind as a child element. The
- * elements and namespaces supported is defined in {@link FormNodeType}.
- *
- * @author Robin Collier
- */
-public class FormNodeProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new FormNode(FormNodeType.valueOfFromElementName(currentElement, currentNamespace), attributeMap.get("node"), new Form((DataForm)content.iterator().next()));
- }
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.packet.DataForm;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.FormNode;
+import org.jivesoftware.smackx.pubsub.FormNodeType;
+
+/**
+ * Parses one of several elements used in pubsub that contain a form of some kind as a child element. The
+ * elements and namespaces supported is defined in {@link FormNodeType}.
+ *
+ * @author Robin Collier
+ */
+public class FormNodeProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new FormNode(FormNodeType.valueOfFromElementName(currentElement, currentNamespace), attributeMap.get("node"), new Form((DataForm)content.iterator().next()));
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java
index 7b06af301..b1cbd2b27 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java
@@ -1,109 +1,109 @@
-/**
- * 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.pubsub.provider;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smack.provider.ProviderManager;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.jivesoftware.smackx.pubsub.Item;
-import org.jivesoftware.smackx.pubsub.PayloadItem;
-import org.jivesoftware.smackx.pubsub.SimplePayload;
-import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Parses an <b>item</b> element as is defined in both the {@link PubSubNamespace#BASIC} and
- * {@link PubSubNamespace#EVENT} namespaces. To parse the item contents, it will use whatever
- * {@link PacketExtensionProvider} is registered in <b>smack.providers</b> for its element name and namespace. If no
- * provider is registered, it will return a {@link SimplePayload}.
- *
- * @author Robin Collier
- */
-public class ItemProvider implements PacketExtensionProvider
-{
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception
- {
- String id = parser.getAttributeValue(null, "id");
- String node = parser.getAttributeValue(null, "node");
- String elem = parser.getName();
-
- int tag = parser.next();
-
- if (tag == XmlPullParser.END_TAG)
- {
- return new Item(id, node);
- }
- else
- {
- String payloadElemName = parser.getName();
- String payloadNS = parser.getNamespace();
-
- if (ProviderManager.getInstance().getExtensionProvider(payloadElemName, payloadNS) == null)
- {
- boolean done = false;
- boolean isEmptyElement = false;
- StringBuilder payloadText = new StringBuilder();
-
- while (!done)
- {
- if (tag == XmlPullParser.END_TAG && parser.getName().equals(elem))
- {
- done = true;
- }
- else if (parser.getEventType() == XmlPullParser.START_TAG)
- {
- payloadText.append("<").append(parser.getName());
-
- if (parser.getName().equals(payloadElemName) && (payloadNS.length() > 0))
- payloadText.append(" xmlns=\"").append(payloadNS).append("\"");
- int n = parser.getAttributeCount();
-
- for (int i = 0; i < n; i++)
- payloadText.append(" ").append(parser.getAttributeName(i)).append("=\"")
- .append(parser.getAttributeValue(i)).append("\"");
-
- if (parser.isEmptyElementTag())
- {
- payloadText.append("/>");
- isEmptyElement = true;
- }
- else
- {
- payloadText.append(">");
- }
- }
- else if (parser.getEventType() == XmlPullParser.END_TAG)
- {
- if (isEmptyElement)
- isEmptyElement = false;
- else
- payloadText.append("</").append(parser.getName()).append(">");
- }
- else if (parser.getEventType() == XmlPullParser.TEXT)
- {
- payloadText.append(parser.getText());
- }
- tag = parser.next();
- }
- return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText.toString()));
- }
- else {
- return new PayloadItem<PacketExtension>(id, node, PacketParserUtils.parsePacketExtension(
- payloadElemName, payloadNS, parser));
- }
- }
- }
-
-}
+/**
+ * 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.pubsub.provider;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.provider.ProviderManager;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.pubsub.Item;
+import org.jivesoftware.smackx.pubsub.PayloadItem;
+import org.jivesoftware.smackx.pubsub.SimplePayload;
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses an <b>item</b> element as is defined in both the {@link PubSubNamespace#BASIC} and
+ * {@link PubSubNamespace#EVENT} namespaces. To parse the item contents, it will use whatever
+ * {@link PacketExtensionProvider} is registered in <b>smack.providers</b> for its element name and namespace. If no
+ * provider is registered, it will return a {@link SimplePayload}.
+ *
+ * @author Robin Collier
+ */
+public class ItemProvider implements PacketExtensionProvider
+{
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception
+ {
+ String id = parser.getAttributeValue(null, "id");
+ String node = parser.getAttributeValue(null, "node");
+ String elem = parser.getName();
+
+ int tag = parser.next();
+
+ if (tag == XmlPullParser.END_TAG)
+ {
+ return new Item(id, node);
+ }
+ else
+ {
+ String payloadElemName = parser.getName();
+ String payloadNS = parser.getNamespace();
+
+ if (ProviderManager.getInstance().getExtensionProvider(payloadElemName, payloadNS) == null)
+ {
+ boolean done = false;
+ boolean isEmptyElement = false;
+ StringBuilder payloadText = new StringBuilder();
+
+ while (!done)
+ {
+ if (tag == XmlPullParser.END_TAG && parser.getName().equals(elem))
+ {
+ done = true;
+ }
+ else if (parser.getEventType() == XmlPullParser.START_TAG)
+ {
+ payloadText.append("<").append(parser.getName());
+
+ if (parser.getName().equals(payloadElemName) && (payloadNS.length() > 0))
+ payloadText.append(" xmlns=\"").append(payloadNS).append("\"");
+ int n = parser.getAttributeCount();
+
+ for (int i = 0; i < n; i++)
+ payloadText.append(" ").append(parser.getAttributeName(i)).append("=\"")
+ .append(parser.getAttributeValue(i)).append("\"");
+
+ if (parser.isEmptyElementTag())
+ {
+ payloadText.append("/>");
+ isEmptyElement = true;
+ }
+ else
+ {
+ payloadText.append(">");
+ }
+ }
+ else if (parser.getEventType() == XmlPullParser.END_TAG)
+ {
+ if (isEmptyElement)
+ isEmptyElement = false;
+ else
+ payloadText.append("</").append(parser.getName()).append(">");
+ }
+ else if (parser.getEventType() == XmlPullParser.TEXT)
+ {
+ payloadText.append(parser.getText());
+ }
+ tag = parser.next();
+ }
+ return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText.toString()));
+ }
+ else {
+ return new PayloadItem<PacketExtension>(id, node, PacketParserUtils.parsePacketExtension(
+ payloadElemName, payloadNS, parser));
+ }
+ }
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemsProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemsProvider.java
index 01cb9d4b2..5657dd3b7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemsProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/ItemsProvider.java
@@ -1,38 +1,38 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.ItemsExtension;
-
-/**
- * Parses the <b>items</b> element out of the message event stanza from
- * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-event">items schema</a>.
- *
- * @author Robin Collier
- */
-public class ItemsProvider extends EmbeddedExtensionProvider
-{
-
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new ItemsExtension(ItemsExtension.ItemsElementType.items, attributeMap.get("node"), content);
- }
-
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.ItemsExtension;
+
+/**
+ * Parses the <b>items</b> element out of the message event stanza from
+ * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-event">items schema</a>.
+ *
+ * @author Robin Collier
+ */
+public class ItemsProvider extends EmbeddedExtensionProvider
+{
+
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new ItemsExtension(ItemsExtension.ItemsElementType.items, attributeMap.get("node"), content);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java
index 742f2198d..3fd34f549 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java
@@ -1,62 +1,62 @@
-/**
- * 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.pubsub.provider;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.jivesoftware.smackx.pubsub.packet.PubSub;
-import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Parses the root pubsub packet extensions of the {@link IQ} packet and returns
- * a {@link PubSub} instance.
- *
- * @author Robin Collier
- */
-public class PubSubProvider implements IQProvider
-{
- public IQ parseIQ(XmlPullParser parser) throws Exception
- {
- PubSub pubsub = new PubSub();
- String namespace = parser.getNamespace();
- pubsub.setPubSubNamespace(PubSubNamespace.valueOfFromXmlns(namespace));
- boolean done = false;
-
- while (!done)
- {
- int eventType = parser.next();
-
- if (eventType == XmlPullParser.START_TAG)
- {
- PacketExtension ext = PacketParserUtils.parsePacketExtension(parser.getName(), namespace, parser);
-
- if (ext != null)
- {
- pubsub.addExtension(ext);
- }
- }
- else if (eventType == XmlPullParser.END_TAG)
- {
- if (parser.getName().equals("pubsub"))
- {
- done = true;
- }
- }
- }
- return pubsub;
- }
-}
+/**
+ * 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.pubsub.provider;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.pubsub.packet.PubSub;
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses the root pubsub packet extensions of the {@link IQ} packet and returns
+ * a {@link PubSub} instance.
+ *
+ * @author Robin Collier
+ */
+public class PubSubProvider implements IQProvider
+{
+ public IQ parseIQ(XmlPullParser parser) throws Exception
+ {
+ PubSub pubsub = new PubSub();
+ String namespace = parser.getNamespace();
+ pubsub.setPubSubNamespace(PubSubNamespace.valueOfFromXmlns(namespace));
+ boolean done = false;
+
+ while (!done)
+ {
+ int eventType = parser.next();
+
+ if (eventType == XmlPullParser.START_TAG)
+ {
+ PacketExtension ext = PacketParserUtils.parsePacketExtension(parser.getName(), namespace, parser);
+
+ if (ext != null)
+ {
+ pubsub.addExtension(ext);
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG)
+ {
+ if (parser.getName().equals("pubsub"))
+ {
+ done = true;
+ }
+ }
+ }
+ return pubsub;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/RetractEventProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/RetractEventProvider.java
index 8fa333770..f182de8e5 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/RetractEventProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/RetractEventProvider.java
@@ -1,38 +1,38 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.RetractItem;
-
-/**
- * Parses the <b>retract</b> element out of the message event stanza from
- * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-event">retract schema</a>.
- * This element is a child of the <b>items</b> element.
- *
- * @author Robin Collier
- */
-public class RetractEventProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new RetractItem(attributeMap.get("id"));
- }
-
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.RetractItem;
+
+/**
+ * Parses the <b>retract</b> element out of the message event stanza from
+ * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-event">retract schema</a>.
+ * This element is a child of the <b>items</b> element.
+ *
+ * @author Robin Collier
+ */
+public class RetractEventProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new RetractItem(attributeMap.get("id"));
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SimpleNodeProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SimpleNodeProvider.java
index d2b7d30a4..b57f04ab3 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SimpleNodeProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SimpleNodeProvider.java
@@ -1,37 +1,37 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.NodeExtension;
-import org.jivesoftware.smackx.pubsub.PubSubElementType;
-
-/**
- * Parses simple elements that only contain a <b>node</b> attribute. This is common amongst many of the
- * elements defined in the pubsub specification. For this common case a {@link NodeExtension} is returned.
- *
- * @author Robin Collier
- */
-public class SimpleNodeProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new NodeExtension(PubSubElementType.valueOfFromElemName(currentElement, currentNamespace), attributeMap.get("node"));
- }
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.NodeExtension;
+import org.jivesoftware.smackx.pubsub.PubSubElementType;
+
+/**
+ * Parses simple elements that only contain a <b>node</b> attribute. This is common amongst many of the
+ * elements defined in the pubsub specification. For this common case a {@link NodeExtension} is returned.
+ *
+ * @author Robin Collier
+ */
+public class SimpleNodeProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new NodeExtension(PubSubElementType.valueOfFromElemName(currentElement, currentNamespace), attributeMap.get("node"));
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionProvider.java
index eccbe08f5..a35e6a190 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionProvider.java
@@ -1,52 +1,52 @@
-/**
- * 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.pubsub.provider;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smackx.pubsub.Subscription;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Parses the <b>subscription</b> element out of the pubsub IQ message from
- * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-pubsub">subscription schema</a>.
- *
- * @author Robin Collier
- */
-public class SubscriptionProvider implements PacketExtensionProvider
-{
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception
- {
- String jid = parser.getAttributeValue(null, "jid");
- String nodeId = parser.getAttributeValue(null, "node");
- String subId = parser.getAttributeValue(null, "subid");
- String state = parser.getAttributeValue(null, "subscription");
- boolean isRequired = false;
-
- int tag = parser.next();
-
- if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("subscribe-options"))
- {
- tag = parser.next();
-
- if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("required"))
- isRequired = true;
-
- while (parser.next() != XmlPullParser.END_TAG && parser.getName() != "subscribe-options");
- }
- while (parser.getEventType() != XmlPullParser.END_TAG) parser.next();
- return new Subscription(jid, nodeId, subId, (state == null ? null : Subscription.State.valueOf(state)), isRequired);
- }
-
-}
+/**
+ * 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.pubsub.provider;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smackx.pubsub.Subscription;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses the <b>subscription</b> element out of the pubsub IQ message from
+ * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-pubsub">subscription schema</a>.
+ *
+ * @author Robin Collier
+ */
+public class SubscriptionProvider implements PacketExtensionProvider
+{
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception
+ {
+ String jid = parser.getAttributeValue(null, "jid");
+ String nodeId = parser.getAttributeValue(null, "node");
+ String subId = parser.getAttributeValue(null, "subid");
+ String state = parser.getAttributeValue(null, "subscription");
+ boolean isRequired = false;
+
+ int tag = parser.next();
+
+ if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("subscribe-options"))
+ {
+ tag = parser.next();
+
+ if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("required"))
+ isRequired = true;
+
+ while (parser.next() != XmlPullParser.END_TAG && parser.getName() != "subscribe-options");
+ }
+ while (parser.getEventType() != XmlPullParser.END_TAG) parser.next();
+ return new Subscription(jid, nodeId, subId, (state == null ? null : Subscription.State.valueOf(state)), isRequired);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionsProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionsProvider.java
index 94dc61d1f..3b2aabbd3 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionsProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/provider/SubscriptionsProvider.java
@@ -1,38 +1,38 @@
-/**
- * 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.pubsub.provider;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
-import org.jivesoftware.smackx.pubsub.Subscription;
-import org.jivesoftware.smackx.pubsub.SubscriptionsExtension;
-
-/**
- * Parses the <b>subscriptions</b> element out of the pubsub IQ message from
- * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-pubsub">subscriptions schema</a>.
- *
- * @author Robin Collier
- */
-public class SubscriptionsProvider extends EmbeddedExtensionProvider
-{
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new SubscriptionsExtension(attributeMap.get("node"), (List<Subscription>)content);
- }
-
-}
+/**
+ * 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.pubsub.provider;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
+import org.jivesoftware.smackx.pubsub.Subscription;
+import org.jivesoftware.smackx.pubsub.SubscriptionsExtension;
+
+/**
+ * Parses the <b>subscriptions</b> element out of the pubsub IQ message from
+ * the server as specified in the <a href="http://xmpp.org/extensions/xep-0060.html#schemas-pubsub">subscriptions schema</a>.
+ *
+ * @author Robin Collier
+ */
+public class SubscriptionsProvider extends EmbeddedExtensionProvider
+{
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new SubscriptionsExtension(attributeMap.get("node"), (List<Subscription>)content);
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/NodeUtils.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/NodeUtils.java
index 414601f3e..48cafa7a6 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/NodeUtils.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/NodeUtils.java
@@ -1,43 +1,43 @@
-/**
- * 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.pubsub.util;
-
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.pubsub.ConfigureForm;
-import org.jivesoftware.smackx.pubsub.FormNode;
-import org.jivesoftware.smackx.pubsub.PubSubElementType;
-
-/**
- * Utility for extracting information from packets.
- *
- * @author Robin Collier
- */
-public class NodeUtils
-{
- /**
- * Get a {@link ConfigureForm} from a packet.
- *
- * @param packet
- * @param elem
- * @return The configuration form
- */
- public static ConfigureForm getFormFromPacket(Packet packet, PubSubElementType elem)
- {
- FormNode config = (FormNode)packet.getExtension(elem.getElementName(), elem.getNamespace().getXmlns());
- Form formReply = config.getForm();
- return new ConfigureForm(formReply);
-
- }
-}
+/**
+ * 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.pubsub.util;
+
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.pubsub.ConfigureForm;
+import org.jivesoftware.smackx.pubsub.FormNode;
+import org.jivesoftware.smackx.pubsub.PubSubElementType;
+
+/**
+ * Utility for extracting information from packets.
+ *
+ * @author Robin Collier
+ */
+public class NodeUtils
+{
+ /**
+ * Get a {@link ConfigureForm} from a packet.
+ *
+ * @param packet
+ * @param elem
+ * @return The configuration form
+ */
+ public static ConfigureForm getFormFromPacket(Packet packet, PubSubElementType elem)
+ {
+ FormNode config = (FormNode)packet.getExtension(elem.getElementName(), elem.getNamespace().getXmlns());
+ Form formReply = config.getForm();
+ return new ConfigureForm(formReply);
+
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/XmlUtils.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/XmlUtils.java
index f5948718d..c42e37349 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/XmlUtils.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/pubsub/util/XmlUtils.java
@@ -1,67 +1,67 @@
-/**
- * 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.pubsub.util;
-
-import java.io.StringReader;
-
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-
-/**
- * Simple utility for pretty printing xml.
- *
- * @author Robin Collier
- */
-public class XmlUtils
-{
- /**
- *
- * @param header Just a title for the stanza for readability. Single word no spaces since
- * it is inserted as the root element in the output.
- * @param xml The string to pretty print
- */
- static public void prettyPrint(String header, String xml)
- {
- try
- {
- Transformer transformer = TransformerFactory.newInstance().newTransformer();
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
-
- if (header != null)
- {
- xml = "\n<" + header + ">" + xml + "</" + header + '>';
- }
- transformer.transform(new StreamSource(new StringReader(xml)), new StreamResult(System.out));
- }
- catch (Exception e)
- {
- System.out.println("Something wrong with xml in \n---------------\n" + xml + "\n---------------");
- e.printStackTrace();
- }
- }
-
- static public void appendAttribute(StringBuilder builder, String att, String value)
- {
- builder.append(" ");
- builder.append(att);
- builder.append("='");
- builder.append(value);
- builder.append("'");
- }
-
-}
+/**
+ * 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.pubsub.util;
+
+import java.io.StringReader;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+/**
+ * Simple utility for pretty printing xml.
+ *
+ * @author Robin Collier
+ */
+public class XmlUtils
+{
+ /**
+ *
+ * @param header Just a title for the stanza for readability. Single word no spaces since
+ * it is inserted as the root element in the output.
+ * @param xml The string to pretty print
+ */
+ static public void prettyPrint(String header, String xml)
+ {
+ try
+ {
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
+
+ if (header != null)
+ {
+ xml = "\n<" + header + ">" + xml + "</" + header + '>';
+ }
+ transformer.transform(new StreamSource(new StringReader(xml)), new StreamResult(System.out));
+ }
+ catch (Exception e)
+ {
+ System.out.println("Something wrong with xml in \n---------------\n" + xml + "\n---------------");
+ e.printStackTrace();
+ }
+ }
+
+ static public void appendAttribute(StringBuilder builder, String att, String value)
+ {
+ builder.append(" ");
+ builder.append(att);
+ builder.append("='");
+ builder.append(value);
+ builder.append("'");
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceipt.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceipt.java
index 902055671..d58fab23c 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceipt.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceipt.java
@@ -1,77 +1,77 @@
-/**
- * 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.receipts;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
-
-/**
- * Represents a <b>message delivery receipt</b> entry as specified by
- * <a href="http://xmpp.org/extensions/xep-0184.html">Message Delivery Receipts</a>.
- *
- * @author Georg Lukas
- */
-public class DeliveryReceipt implements PacketExtension
-{
- public static final String NAMESPACE = "urn:xmpp:receipts";
- public static final String ELEMENT = "received";
-
- private String id; /// original ID of the delivered message
-
- public DeliveryReceipt(String id)
- {
- this.id = id;
- }
-
- public String getId()
- {
- return id;
- }
-
- @Override
- public String getElementName()
- {
- return ELEMENT;
- }
-
- @Override
- public String getNamespace()
- {
- return NAMESPACE;
- }
-
- @Override
- public String toXML()
- {
- return "<received xmlns='" + NAMESPACE + "' id='" + id + "'/>";
- }
-
- /**
- * This Provider parses and returns DeliveryReceipt packets.
- */
- public static class Provider extends EmbeddedExtensionProvider
- {
-
- @Override
- protected PacketExtension createReturnExtension(String currentElement, String currentNamespace,
- Map<String, String> attributeMap, List<? extends PacketExtension> content)
- {
- return new DeliveryReceipt(attributeMap.get("id"));
- }
-
- }
-}
+/**
+ * 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.receipts;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
+
+/**
+ * Represents a <b>message delivery receipt</b> entry as specified by
+ * <a href="http://xmpp.org/extensions/xep-0184.html">Message Delivery Receipts</a>.
+ *
+ * @author Georg Lukas
+ */
+public class DeliveryReceipt implements PacketExtension
+{
+ public static final String NAMESPACE = "urn:xmpp:receipts";
+ public static final String ELEMENT = "received";
+
+ private String id; /// original ID of the delivered message
+
+ public DeliveryReceipt(String id)
+ {
+ this.id = id;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ @Override
+ public String getElementName()
+ {
+ return ELEMENT;
+ }
+
+ @Override
+ public String getNamespace()
+ {
+ return NAMESPACE;
+ }
+
+ @Override
+ public String toXML()
+ {
+ return "<received xmlns='" + NAMESPACE + "' id='" + id + "'/>";
+ }
+
+ /**
+ * This Provider parses and returns DeliveryReceipt packets.
+ */
+ public static class Provider extends EmbeddedExtensionProvider
+ {
+
+ @Override
+ protected PacketExtension createReturnExtension(String currentElement, String currentNamespace,
+ Map<String, String> attributeMap, List<? extends PacketExtension> content)
+ {
+ return new DeliveryReceipt(attributeMap.get("id"));
+ }
+
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java
index 1b5ed3bc4..28bd0c8ec 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java
@@ -1,54 +1,54 @@
-/*
- * 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.receipts;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Represents a <b>message delivery receipt request</b> entry as specified by
- * <a href="http://xmpp.org/extensions/xep-0184.html">Message Delivery Receipts</a>.
- *
- * @author Georg Lukas
- */
-public class DeliveryReceiptRequest implements PacketExtension
-{
- public static final String ELEMENT = "request";
-
- public String getElementName()
- {
- return ELEMENT;
- }
-
- public String getNamespace()
- {
- return DeliveryReceipt.NAMESPACE;
- }
-
- public String toXML()
- {
- return "<request xmlns='" + DeliveryReceipt.NAMESPACE + "'/>";
- }
-
- /**
- * This Provider parses and returns DeliveryReceiptRequest packets.
- */
- public static class Provider implements PacketExtensionProvider {
- @Override
- public PacketExtension parseExtension(XmlPullParser parser) {
- return new DeliveryReceiptRequest();
- }
- }
-}
+/*
+ * 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.receipts;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Represents a <b>message delivery receipt request</b> entry as specified by
+ * <a href="http://xmpp.org/extensions/xep-0184.html">Message Delivery Receipts</a>.
+ *
+ * @author Georg Lukas
+ */
+public class DeliveryReceiptRequest implements PacketExtension
+{
+ public static final String ELEMENT = "request";
+
+ public String getElementName()
+ {
+ return ELEMENT;
+ }
+
+ public String getNamespace()
+ {
+ return DeliveryReceipt.NAMESPACE;
+ }
+
+ public String toXML()
+ {
+ return "<request xmlns='" + DeliveryReceipt.NAMESPACE + "'/>";
+ }
+
+ /**
+ * This Provider parses and returns DeliveryReceiptRequest packets.
+ */
+ public static class Provider implements PacketExtensionProvider {
+ @Override
+ public PacketExtension parseExtension(XmlPullParser parser) {
+ return new DeliveryReceiptRequest();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/ReceiptReceivedListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/ReceiptReceivedListener.java
index 318311371..4f613d3ec 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/ReceiptReceivedListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/receipts/ReceiptReceivedListener.java
@@ -1,26 +1,26 @@
-/**
- * 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.receipts;
-
-/**
- * Interface for received receipt notifications.
- *
- * Implement this and add a listener to get notified.
- */
-public interface ReceiptReceivedListener {
- void onReceiptReceived(String fromJid, String toJid, String receiptId);
+/**
+ * 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.receipts;
+
+/**
+ * Interface for received receipt notifications.
+ *
+ * Implement this and add a listener to get notified.
+ */
+public interface ReceiptReceivedListener {
+ void onReceiptReceived(String fromJid, String toJid, String receiptId);
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/MetaData.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/MetaData.java
index 115a79c95..707bcb5e9 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/MetaData.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/MetaData.java
@@ -1,68 +1,68 @@
-/**
- * $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
- *
- * 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.workgroup;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smackx.workgroup.util.MetaDataUtils;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * MetaData packet extension.
- */
-public class MetaData implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "metadata";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- private Map<String, List<String>> metaData;
-
- public MetaData(Map<String, List<String>> metaData) {
- this.metaData = metaData;
- }
-
- /**
- * @return the Map of metadata contained by this instance
- */
- public Map<String, List<String>> getMetaData() {
- return metaData;
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String toXML() {
- return MetaDataUtils.serializeMetaData(this.getMetaData());
- }
+/**
+ * $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
+ *
+ * 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.workgroup;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smackx.workgroup.util.MetaDataUtils;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * MetaData packet extension.
+ */
+public class MetaData implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "metadata";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ private Map<String, List<String>> metaData;
+
+ public MetaData(Map<String, List<String>> metaData) {
+ this.metaData = metaData;
+ }
+
+ /**
+ * @return the Map of metadata contained by this instance
+ */
+ public Map<String, List<String>> getMetaData() {
+ return metaData;
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String toXML() {
+ return MetaDataUtils.serializeMetaData(this.getMetaData());
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/QueueUser.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/QueueUser.java
index 89a18995f..da83061b8 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/QueueUser.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/QueueUser.java
@@ -1,85 +1,85 @@
-/**
- * $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
- *
- * 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.workgroup;
-
-import java.util.Date;
-
-/**
- * An immutable class which wraps up customer-in-queue data return from the server; depending on
- * the type of information dispatched from the server, not all information will be available in
- * any given instance.
- *
- * @author loki der quaeler
- */
-public class QueueUser {
-
- private String userID;
-
- private int queuePosition;
- private int estimatedTime;
- private Date joinDate;
-
- /**
- * @param uid the user jid of the customer in the queue
- * @param position the position customer sits in the queue
- * @param time the estimate of how much longer the customer will be in the queue in seconds
- * @param joinedAt the timestamp of when the customer entered the queue
- */
- public QueueUser (String uid, int position, int time, Date joinedAt) {
- super();
-
- this.userID = uid;
- this.queuePosition = position;
- this.estimatedTime = time;
- this.joinDate = joinedAt;
- }
-
- /**
- * @return the user jid of the customer in the queue
- */
- public String getUserID () {
- return this.userID;
- }
-
- /**
- * @return the position in the queue at which the customer sits, or -1 if the update which
- * this instance embodies is only a time update instead
- */
- public int getQueuePosition () {
- return this.queuePosition;
- }
-
- /**
- * @return the estimated time remaining of the customer in the queue in seconds, or -1 if
- * if the update which this instance embodies is only a position update instead
- */
- public int getEstimatedRemainingTime () {
- return this.estimatedTime;
- }
-
- /**
- * @return the timestamp of when this customer entered the queue, or null if the server did not
- * provide this information
- */
- public Date getQueueJoinTimestamp () {
- return this.joinDate;
- }
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup;
+
+import java.util.Date;
+
+/**
+ * An immutable class which wraps up customer-in-queue data return from the server; depending on
+ * the type of information dispatched from the server, not all information will be available in
+ * any given instance.
+ *
+ * @author loki der quaeler
+ */
+public class QueueUser {
+
+ private String userID;
+
+ private int queuePosition;
+ private int estimatedTime;
+ private Date joinDate;
+
+ /**
+ * @param uid the user jid of the customer in the queue
+ * @param position the position customer sits in the queue
+ * @param time the estimate of how much longer the customer will be in the queue in seconds
+ * @param joinedAt the timestamp of when the customer entered the queue
+ */
+ public QueueUser (String uid, int position, int time, Date joinedAt) {
+ super();
+
+ this.userID = uid;
+ this.queuePosition = position;
+ this.estimatedTime = time;
+ this.joinDate = joinedAt;
+ }
+
+ /**
+ * @return the user jid of the customer in the queue
+ */
+ public String getUserID () {
+ return this.userID;
+ }
+
+ /**
+ * @return the position in the queue at which the customer sits, or -1 if the update which
+ * this instance embodies is only a time update instead
+ */
+ public int getQueuePosition () {
+ return this.queuePosition;
+ }
+
+ /**
+ * @return the estimated time remaining of the customer in the queue in seconds, or -1 if
+ * if the update which this instance embodies is only a position update instead
+ */
+ public int getEstimatedRemainingTime () {
+ return this.estimatedTime;
+ }
+
+ /**
+ * @return the timestamp of when this customer entered the queue, or null if the server did not
+ * provide this information
+ */
+ public Date getQueueJoinTimestamp () {
+ return this.joinDate;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitation.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitation.java
index ac3b5b6d9..10a84d5c8 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitation.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitation.java
@@ -1,134 +1,134 @@
-/**
- * $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
- *
- * 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.workgroup;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * An immutable class wrapping up the basic information which comprises a group chat invitation.
- *
- * @author loki der quaeler
- */
-public class WorkgroupInvitation {
-
- protected String uniqueID;
-
- protected String sessionID;
-
- protected String groupChatName;
- protected String issuingWorkgroupName;
- protected String messageBody;
- protected String invitationSender;
- protected Map<String, List<String>> metaData;
-
- /**
- * This calls the 5-argument constructor with a null MetaData argument value
- *
- * @param jid the jid string with which the issuing AgentSession or Workgroup instance
- * was created
- * @param group the jid of the room to which the person is invited
- * @param workgroup the jid of the workgroup issuing the invitation
- * @param sessID the session id associated with the pending chat
- * @param msgBody the body of the message which contained the invitation
- * @param from the user jid who issued the invitation, if known, null otherwise
- */
- public WorkgroupInvitation (String jid, String group, String workgroup,
- String sessID, String msgBody, String from) {
- this(jid, group, workgroup, sessID, msgBody, from, null);
- }
-
- /**
- * @param jid the jid string with which the issuing AgentSession or Workgroup instance
- * was created
- * @param group the jid of the room to which the person is invited
- * @param workgroup the jid of the workgroup issuing the invitation
- * @param sessID the session id associated with the pending chat
- * @param msgBody the body of the message which contained the invitation
- * @param from the user jid who issued the invitation, if known, null otherwise
- * @param metaData the metadata sent with the invitation
- */
- public WorkgroupInvitation (String jid, String group, String workgroup, String sessID, String msgBody,
- String from, Map<String, List<String>> metaData) {
- super();
-
- this.uniqueID = jid;
- this.sessionID = sessID;
- this.groupChatName = group;
- this.issuingWorkgroupName = workgroup;
- this.messageBody = msgBody;
- this.invitationSender = from;
- this.metaData = metaData;
- }
-
- /**
- * @return the jid string with which the issuing AgentSession or Workgroup instance
- * was created.
- */
- public String getUniqueID () {
- return this.uniqueID;
- }
-
- /**
- * @return the session id associated with the pending chat; working backwards temporally,
- * this session id should match the session id to the corresponding offer request
- * which resulted in this invitation.
- */
- public String getSessionID () {
- return this.sessionID;
- }
-
- /**
- * @return the jid of the room to which the person is invited.
- */
- public String getGroupChatName () {
- return this.groupChatName;
- }
-
- /**
- * @return the name of the workgroup from which the invitation was issued.
- */
- public String getWorkgroupName () {
- return this.issuingWorkgroupName;
- }
-
- /**
- * @return the contents of the body-block of the message that housed this invitation.
- */
- public String getMessageBody () {
- return this.messageBody;
- }
-
- /**
- * @return the user who issued the invitation, or null if it wasn't known.
- */
- public String getInvitationSender () {
- return this.invitationSender;
- }
-
- /**
- * @return the meta data associated with the invitation, or null if this instance was
- * constructed with none
- */
- public Map<String, List<String>> getMetaData () {
- return this.metaData;
- }
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An immutable class wrapping up the basic information which comprises a group chat invitation.
+ *
+ * @author loki der quaeler
+ */
+public class WorkgroupInvitation {
+
+ protected String uniqueID;
+
+ protected String sessionID;
+
+ protected String groupChatName;
+ protected String issuingWorkgroupName;
+ protected String messageBody;
+ protected String invitationSender;
+ protected Map<String, List<String>> metaData;
+
+ /**
+ * This calls the 5-argument constructor with a null MetaData argument value
+ *
+ * @param jid the jid string with which the issuing AgentSession or Workgroup instance
+ * was created
+ * @param group the jid of the room to which the person is invited
+ * @param workgroup the jid of the workgroup issuing the invitation
+ * @param sessID the session id associated with the pending chat
+ * @param msgBody the body of the message which contained the invitation
+ * @param from the user jid who issued the invitation, if known, null otherwise
+ */
+ public WorkgroupInvitation (String jid, String group, String workgroup,
+ String sessID, String msgBody, String from) {
+ this(jid, group, workgroup, sessID, msgBody, from, null);
+ }
+
+ /**
+ * @param jid the jid string with which the issuing AgentSession or Workgroup instance
+ * was created
+ * @param group the jid of the room to which the person is invited
+ * @param workgroup the jid of the workgroup issuing the invitation
+ * @param sessID the session id associated with the pending chat
+ * @param msgBody the body of the message which contained the invitation
+ * @param from the user jid who issued the invitation, if known, null otherwise
+ * @param metaData the metadata sent with the invitation
+ */
+ public WorkgroupInvitation (String jid, String group, String workgroup, String sessID, String msgBody,
+ String from, Map<String, List<String>> metaData) {
+ super();
+
+ this.uniqueID = jid;
+ this.sessionID = sessID;
+ this.groupChatName = group;
+ this.issuingWorkgroupName = workgroup;
+ this.messageBody = msgBody;
+ this.invitationSender = from;
+ this.metaData = metaData;
+ }
+
+ /**
+ * @return the jid string with which the issuing AgentSession or Workgroup instance
+ * was created.
+ */
+ public String getUniqueID () {
+ return this.uniqueID;
+ }
+
+ /**
+ * @return the session id associated with the pending chat; working backwards temporally,
+ * this session id should match the session id to the corresponding offer request
+ * which resulted in this invitation.
+ */
+ public String getSessionID () {
+ return this.sessionID;
+ }
+
+ /**
+ * @return the jid of the room to which the person is invited.
+ */
+ public String getGroupChatName () {
+ return this.groupChatName;
+ }
+
+ /**
+ * @return the name of the workgroup from which the invitation was issued.
+ */
+ public String getWorkgroupName () {
+ return this.issuingWorkgroupName;
+ }
+
+ /**
+ * @return the contents of the body-block of the message that housed this invitation.
+ */
+ public String getMessageBody () {
+ return this.messageBody;
+ }
+
+ /**
+ * @return the user who issued the invitation, or null if it wasn't known.
+ */
+ public String getInvitationSender () {
+ return this.invitationSender;
+ }
+
+ /**
+ * @return the meta data associated with the invitation, or null if this instance was
+ * constructed with none
+ */
+ public Map<String, List<String>> getMetaData () {
+ return this.metaData;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitationListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitationListener.java
index bc7324252..06634d700 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitationListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/WorkgroupInvitationListener.java
@@ -1,39 +1,39 @@
-/**
- * $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
- *
- * 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.workgroup;
-
-/**
- * An interface which all classes interested in hearing about group chat invitations should
- * implement.
- *
- * @author loki der quaeler
- */
-public interface WorkgroupInvitationListener {
-
- /**
- * The implementing class instance will be notified via this method when an invitation
- * to join a group chat has been received from the server.
- *
- * @param invitation an Invitation instance embodying the information pertaining to the
- * invitation
- */
- public void invitationReceived(WorkgroupInvitation invitation);
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup;
+
+/**
+ * An interface which all classes interested in hearing about group chat invitations should
+ * implement.
+ *
+ * @author loki der quaeler
+ */
+public interface WorkgroupInvitationListener {
+
+ /**
+ * The implementing class instance will be notified via this method when an invitation
+ * to join a group chat has been received from the server.
+ *
+ * @param invitation an Invitation instance embodying the information pertaining to the
+ * invitation
+ */
+ public void invitationReceived(WorkgroupInvitation invitation);
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Agent.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Agent.java
index bebac3721..d7e4fa253 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Agent.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Agent.java
@@ -1,138 +1,138 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import org.jivesoftware.smackx.workgroup.packet.AgentInfo;
-import org.jivesoftware.smackx.workgroup.packet.AgentWorkgroups;
-import org.jivesoftware.smack.PacketCollector;
-import org.jivesoftware.smack.SmackConfiguration;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.PacketIDFilter;
-import org.jivesoftware.smack.packet.IQ;
-
-import java.util.Collection;
-
-/**
- * The <code>Agent</code> class is used to represent one agent in a Workgroup Queue.
- *
- * @author Derek DeMoro
- */
-public class Agent {
- private Connection connection;
- private String workgroupJID;
-
- public static Collection<String> getWorkgroups(String serviceJID, String agentJID, Connection connection) throws XMPPException {
- AgentWorkgroups request = new AgentWorkgroups(agentJID);
- request.setTo(serviceJID);
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- // Send the request
- connection.sendPacket(request);
-
- AgentWorkgroups response = (AgentWorkgroups)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response.getWorkgroups();
- }
-
- /**
- * Constructs an Agent.
- */
- Agent(Connection connection, String workgroupJID) {
- this.connection = connection;
- this.workgroupJID = workgroupJID;
- }
-
- /**
- * Return the agents JID
- *
- * @return - the agents JID.
- */
- public String getUser() {
- return connection.getUser();
- }
-
- /**
- * Return the agents name.
- *
- * @return - the agents name.
- */
- public String getName() throws XMPPException {
- AgentInfo agentInfo = new AgentInfo();
- agentInfo.setType(IQ.Type.GET);
- agentInfo.setTo(workgroupJID);
- agentInfo.setFrom(getUser());
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(agentInfo.getPacketID()));
- // Send the request
- connection.sendPacket(agentInfo);
-
- AgentInfo response = (AgentInfo)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response.getName();
- }
-
- /**
- * Changes the name of the agent in the server. The server may have this functionality
- * disabled for all the agents or for this agent in particular. If the agent is not
- * allowed to change his name then an exception will be thrown with a service_unavailable
- * error code.
- *
- * @param newName the new name of the agent.
- * @throws XMPPException if the agent is not allowed to change his name or no response was
- * obtained from the server.
- */
- public void setName(String newName) throws XMPPException {
- AgentInfo agentInfo = new AgentInfo();
- agentInfo.setType(IQ.Type.SET);
- agentInfo.setTo(workgroupJID);
- agentInfo.setFrom(getUser());
- agentInfo.setName(newName);
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(agentInfo.getPacketID()));
- // Send the request
- connection.sendPacket(agentInfo);
-
- IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return;
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import org.jivesoftware.smackx.workgroup.packet.AgentInfo;
+import org.jivesoftware.smackx.workgroup.packet.AgentWorkgroups;
+import org.jivesoftware.smack.PacketCollector;
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketIDFilter;
+import org.jivesoftware.smack.packet.IQ;
+
+import java.util.Collection;
+
+/**
+ * The <code>Agent</code> class is used to represent one agent in a Workgroup Queue.
+ *
+ * @author Derek DeMoro
+ */
+public class Agent {
+ private Connection connection;
+ private String workgroupJID;
+
+ public static Collection<String> getWorkgroups(String serviceJID, String agentJID, Connection connection) throws XMPPException {
+ AgentWorkgroups request = new AgentWorkgroups(agentJID);
+ request.setTo(serviceJID);
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ // Send the request
+ connection.sendPacket(request);
+
+ AgentWorkgroups response = (AgentWorkgroups)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response.getWorkgroups();
+ }
+
+ /**
+ * Constructs an Agent.
+ */
+ Agent(Connection connection, String workgroupJID) {
+ this.connection = connection;
+ this.workgroupJID = workgroupJID;
+ }
+
+ /**
+ * Return the agents JID
+ *
+ * @return - the agents JID.
+ */
+ public String getUser() {
+ return connection.getUser();
+ }
+
+ /**
+ * Return the agents name.
+ *
+ * @return - the agents name.
+ */
+ public String getName() throws XMPPException {
+ AgentInfo agentInfo = new AgentInfo();
+ agentInfo.setType(IQ.Type.GET);
+ agentInfo.setTo(workgroupJID);
+ agentInfo.setFrom(getUser());
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(agentInfo.getPacketID()));
+ // Send the request
+ connection.sendPacket(agentInfo);
+
+ AgentInfo response = (AgentInfo)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response.getName();
+ }
+
+ /**
+ * Changes the name of the agent in the server. The server may have this functionality
+ * disabled for all the agents or for this agent in particular. If the agent is not
+ * allowed to change his name then an exception will be thrown with a service_unavailable
+ * error code.
+ *
+ * @param newName the new name of the agent.
+ * @throws XMPPException if the agent is not allowed to change his name or no response was
+ * obtained from the server.
+ */
+ public void setName(String newName) throws XMPPException {
+ AgentInfo agentInfo = new AgentInfo();
+ agentInfo.setType(IQ.Type.SET);
+ agentInfo.setTo(workgroupJID);
+ agentInfo.setFrom(getUser());
+ agentInfo.setName(newName);
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(agentInfo.getPacketID()));
+ // Send the request
+ connection.sendPacket(agentInfo);
+
+ IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java
index 70c95ee2e..edeb195c7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRoster.java
@@ -1,386 +1,386 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import org.jivesoftware.smackx.workgroup.packet.AgentStatus;
-import org.jivesoftware.smackx.workgroup.packet.AgentStatusRequest;
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.Presence;
-import org.jivesoftware.smack.util.StringUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Manges information about the agents in a workgroup and their presence.
- *
- * @author Matt Tucker
- * @see AgentSession#getAgentRoster()
- */
-public class AgentRoster {
-
- private static final int EVENT_AGENT_ADDED = 0;
- private static final int EVENT_AGENT_REMOVED = 1;
- private static final int EVENT_PRESENCE_CHANGED = 2;
-
- private Connection connection;
- private String workgroupJID;
- private List<String> entries;
- private List<AgentRosterListener> listeners;
- private Map<String, Map<String, Presence>> presenceMap;
- // The roster is marked as initialized when at least a single roster packet
- // has been recieved and processed.
- boolean rosterInitialized = false;
-
- /**
- * Constructs a new AgentRoster.
- *
- * @param connection an XMPP connection.
- */
- AgentRoster(Connection connection, String workgroupJID) {
- this.connection = connection;
- this.workgroupJID = workgroupJID;
- entries = new ArrayList<String>();
- listeners = new ArrayList<AgentRosterListener>();
- presenceMap = new HashMap<String, Map<String, Presence>>();
- // Listen for any roster packets.
- PacketFilter rosterFilter = new PacketTypeFilter(AgentStatusRequest.class);
- connection.addPacketListener(new AgentStatusListener(), rosterFilter);
- // Listen for any presence packets.
- connection.addPacketListener(new PresencePacketListener(),
- new PacketTypeFilter(Presence.class));
-
- // Send request for roster.
- AgentStatusRequest request = new AgentStatusRequest();
- request.setTo(workgroupJID);
- connection.sendPacket(request);
- }
-
- /**
- * Reloads the entire roster from the server. This is an asynchronous operation,
- * which means the method will return immediately, and the roster will be
- * reloaded at a later point when the server responds to the reload request.
- */
- public void reload() {
- AgentStatusRequest request = new AgentStatusRequest();
- request.setTo(workgroupJID);
- connection.sendPacket(request);
- }
-
- /**
- * Adds a listener to this roster. The listener will be fired anytime one or more
- * changes to the roster are pushed from the server.
- *
- * @param listener an agent roster listener.
- */
- public void addListener(AgentRosterListener listener) {
- synchronized (listeners) {
- if (!listeners.contains(listener)) {
- listeners.add(listener);
-
- // Fire events for the existing entries and presences in the roster
- for (Iterator<String> it = getAgents().iterator(); it.hasNext();) {
- String jid = it.next();
- // Check again in case the agent is no longer in the roster (highly unlikely
- // but possible)
- if (entries.contains(jid)) {
- // Fire the agent added event
- listener.agentAdded(jid);
- Map<String,Presence> userPresences = presenceMap.get(jid);
- if (userPresences != null) {
- Iterator<Presence> presences = userPresences.values().iterator();
- while (presences.hasNext()) {
- // Fire the presence changed event
- listener.presenceChanged(presences.next());
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * Removes a listener from this roster. The listener will be fired anytime one or more
- * changes to the roster are pushed from the server.
- *
- * @param listener a roster listener.
- */
- public void removeListener(AgentRosterListener listener) {
- synchronized (listeners) {
- listeners.remove(listener);
- }
- }
-
- /**
- * Returns a count of all agents in the workgroup.
- *
- * @return the number of agents in the workgroup.
- */
- public int getAgentCount() {
- return entries.size();
- }
-
- /**
- * Returns all agents (String JID values) in the workgroup.
- *
- * @return all entries in the roster.
- */
- public Set<String> getAgents() {
- Set<String> agents = new HashSet<String>();
- synchronized (entries) {
- for (Iterator<String> i = entries.iterator(); i.hasNext();) {
- agents.add(i.next());
- }
- }
- return Collections.unmodifiableSet(agents);
- }
-
- /**
- * Returns true if the specified XMPP address is an agent in the workgroup.
- *
- * @param jid the XMPP address of the agent (eg "jsmith@example.com"). The
- * address can be in any valid format (e.g. "domain/resource", "user@domain"
- * or "user@domain/resource").
- * @return true if the XMPP address is an agent in the workgroup.
- */
- public boolean contains(String jid) {
- if (jid == null) {
- return false;
- }
- synchronized (entries) {
- for (Iterator<String> i = entries.iterator(); i.hasNext();) {
- String entry = i.next();
- if (entry.toLowerCase().equals(jid.toLowerCase())) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Returns the presence info for a particular agent, or <tt>null</tt> if the agent
- * is unavailable (offline) or if no presence information is available.<p>
- *
- * @param user a fully qualified xmpp JID. The address could be in any valid format (e.g.
- * "domain/resource", "user@domain" or "user@domain/resource").
- * @return the agent's current presence, or <tt>null</tt> if the agent is unavailable
- * or if no presence information is available..
- */
- public Presence getPresence(String user) {
- String key = getPresenceMapKey(user);
- Map<String, Presence> userPresences = presenceMap.get(key);
- if (userPresences == null) {
- Presence presence = new Presence(Presence.Type.unavailable);
- presence.setFrom(user);
- return presence;
- }
- else {
- // Find the resource with the highest priority
- // Might be changed to use the resource with the highest availability instead.
- Iterator<String> it = userPresences.keySet().iterator();
- Presence p;
- Presence presence = null;
-
- while (it.hasNext()) {
- p = (Presence)userPresences.get(it.next());
- if (presence == null){
- presence = p;
- }
- else {
- if (p.getPriority() > presence.getPriority()) {
- presence = p;
- }
- }
- }
- if (presence == null) {
- presence = new Presence(Presence.Type.unavailable);
- presence.setFrom(user);
- return presence;
- }
- else {
- return presence;
- }
- }
- }
-
- /**
- * Returns the key to use in the presenceMap for a fully qualified xmpp ID. The roster
- * can contain any valid address format such us "domain/resource", "user@domain" or
- * "user@domain/resource". If the roster contains an entry associated with the fully qualified
- * xmpp ID then use the fully qualified xmpp ID as the key in presenceMap, otherwise use the
- * bare address. Note: When the key in presenceMap is a fully qualified xmpp ID, the
- * userPresences is useless since it will always contain one entry for the user.
- *
- * @param user the fully qualified xmpp ID, e.g. jdoe@example.com/Work.
- * @return the key to use in the presenceMap for the fully qualified xmpp ID.
- */
- private String getPresenceMapKey(String user) {
- String key = user;
- if (!contains(user)) {
- key = StringUtils.parseBareAddress(user).toLowerCase();
- }
- return key;
- }
-
- /**
- * Fires event to listeners.
- */
- private void fireEvent(int eventType, Object eventObject) {
- AgentRosterListener[] listeners = null;
- synchronized (this.listeners) {
- listeners = new AgentRosterListener[this.listeners.size()];
- this.listeners.toArray(listeners);
- }
- for (int i = 0; i < listeners.length; i++) {
- switch (eventType) {
- case EVENT_AGENT_ADDED:
- listeners[i].agentAdded((String)eventObject);
- break;
- case EVENT_AGENT_REMOVED:
- listeners[i].agentRemoved((String)eventObject);
- break;
- case EVENT_PRESENCE_CHANGED:
- listeners[i].presenceChanged((Presence)eventObject);
- break;
- }
- }
- }
-
- /**
- * Listens for all presence packets and processes them.
- */
- private class PresencePacketListener implements PacketListener {
- public void processPacket(Packet packet) {
- Presence presence = (Presence)packet;
- String from = presence.getFrom();
- if (from == null) {
- // TODO Check if we need to ignore these presences or this is a server bug?
- System.out.println("Presence with no FROM: " + presence.toXML());
- return;
- }
- String key = getPresenceMapKey(from);
-
- // If an "available" packet, add it to the presence map. Each presence map will hold
- // for a particular user a map with the presence packets saved for each resource.
- if (presence.getType() == Presence.Type.available) {
- // Ignore the presence packet unless it has an agent status extension.
- AgentStatus agentStatus = (AgentStatus)presence.getExtension(
- AgentStatus.ELEMENT_NAME, AgentStatus.NAMESPACE);
- if (agentStatus == null) {
- return;
- }
- // Ensure that this presence is coming from an Agent of the same workgroup
- // of this Agent
- else if (!workgroupJID.equals(agentStatus.getWorkgroupJID())) {
- return;
- }
- Map<String, Presence> userPresences;
- // Get the user presence map
- if (presenceMap.get(key) == null) {
- userPresences = new HashMap<String, Presence>();
- presenceMap.put(key, userPresences);
- }
- else {
- userPresences = presenceMap.get(key);
- }
- // Add the new presence, using the resources as a key.
- synchronized (userPresences) {
- userPresences.put(StringUtils.parseResource(from), presence);
- }
- // Fire an event.
- synchronized (entries) {
- for (Iterator<String> i = entries.iterator(); i.hasNext();) {
- String entry = i.next();
- if (entry.toLowerCase().equals(StringUtils.parseBareAddress(key).toLowerCase())) {
- fireEvent(EVENT_PRESENCE_CHANGED, packet);
- }
- }
- }
- }
- // If an "unavailable" packet, remove any entries in the presence map.
- else if (presence.getType() == Presence.Type.unavailable) {
- if (presenceMap.get(key) != null) {
- Map<String,Presence> userPresences = presenceMap.get(key);
- synchronized (userPresences) {
- userPresences.remove(StringUtils.parseResource(from));
- }
- if (userPresences.isEmpty()) {
- presenceMap.remove(key);
- }
- }
- // Fire an event.
- synchronized (entries) {
- for (Iterator<String> i = entries.iterator(); i.hasNext();) {
- String entry = (String)i.next();
- if (entry.toLowerCase().equals(StringUtils.parseBareAddress(key).toLowerCase())) {
- fireEvent(EVENT_PRESENCE_CHANGED, packet);
- }
- }
- }
- }
- }
- }
-
- /**
- * Listens for all roster packets and processes them.
- */
- private class AgentStatusListener implements PacketListener {
-
- public void processPacket(Packet packet) {
- if (packet instanceof AgentStatusRequest) {
- AgentStatusRequest statusRequest = (AgentStatusRequest)packet;
- for (Iterator<AgentStatusRequest.Item> i = statusRequest.getAgents().iterator(); i.hasNext();) {
- AgentStatusRequest.Item item = i.next();
- String agentJID = item.getJID();
- if ("remove".equals(item.getType())) {
-
- // Removing the user from the roster, so remove any presence information
- // about them.
- String key = StringUtils.parseName(StringUtils.parseName(agentJID) + "@" +
- StringUtils.parseServer(agentJID));
- presenceMap.remove(key);
- // Fire event for roster listeners.
- fireEvent(EVENT_AGENT_REMOVED, agentJID);
- }
- else {
- entries.add(agentJID);
- // Fire event for roster listeners.
- fireEvent(EVENT_AGENT_ADDED, agentJID);
- }
- }
-
- // Mark the roster as initialized.
- rosterInitialized = true;
- }
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import org.jivesoftware.smackx.workgroup.packet.AgentStatus;
+import org.jivesoftware.smackx.workgroup.packet.AgentStatusRequest;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.Presence;
+import org.jivesoftware.smack.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Manges information about the agents in a workgroup and their presence.
+ *
+ * @author Matt Tucker
+ * @see AgentSession#getAgentRoster()
+ */
+public class AgentRoster {
+
+ private static final int EVENT_AGENT_ADDED = 0;
+ private static final int EVENT_AGENT_REMOVED = 1;
+ private static final int EVENT_PRESENCE_CHANGED = 2;
+
+ private Connection connection;
+ private String workgroupJID;
+ private List<String> entries;
+ private List<AgentRosterListener> listeners;
+ private Map<String, Map<String, Presence>> presenceMap;
+ // The roster is marked as initialized when at least a single roster packet
+ // has been recieved and processed.
+ boolean rosterInitialized = false;
+
+ /**
+ * Constructs a new AgentRoster.
+ *
+ * @param connection an XMPP connection.
+ */
+ AgentRoster(Connection connection, String workgroupJID) {
+ this.connection = connection;
+ this.workgroupJID = workgroupJID;
+ entries = new ArrayList<String>();
+ listeners = new ArrayList<AgentRosterListener>();
+ presenceMap = new HashMap<String, Map<String, Presence>>();
+ // Listen for any roster packets.
+ PacketFilter rosterFilter = new PacketTypeFilter(AgentStatusRequest.class);
+ connection.addPacketListener(new AgentStatusListener(), rosterFilter);
+ // Listen for any presence packets.
+ connection.addPacketListener(new PresencePacketListener(),
+ new PacketTypeFilter(Presence.class));
+
+ // Send request for roster.
+ AgentStatusRequest request = new AgentStatusRequest();
+ request.setTo(workgroupJID);
+ connection.sendPacket(request);
+ }
+
+ /**
+ * Reloads the entire roster from the server. This is an asynchronous operation,
+ * which means the method will return immediately, and the roster will be
+ * reloaded at a later point when the server responds to the reload request.
+ */
+ public void reload() {
+ AgentStatusRequest request = new AgentStatusRequest();
+ request.setTo(workgroupJID);
+ connection.sendPacket(request);
+ }
+
+ /**
+ * Adds a listener to this roster. The listener will be fired anytime one or more
+ * changes to the roster are pushed from the server.
+ *
+ * @param listener an agent roster listener.
+ */
+ public void addListener(AgentRosterListener listener) {
+ synchronized (listeners) {
+ if (!listeners.contains(listener)) {
+ listeners.add(listener);
+
+ // Fire events for the existing entries and presences in the roster
+ for (Iterator<String> it = getAgents().iterator(); it.hasNext();) {
+ String jid = it.next();
+ // Check again in case the agent is no longer in the roster (highly unlikely
+ // but possible)
+ if (entries.contains(jid)) {
+ // Fire the agent added event
+ listener.agentAdded(jid);
+ Map<String,Presence> userPresences = presenceMap.get(jid);
+ if (userPresences != null) {
+ Iterator<Presence> presences = userPresences.values().iterator();
+ while (presences.hasNext()) {
+ // Fire the presence changed event
+ listener.presenceChanged(presences.next());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a listener from this roster. The listener will be fired anytime one or more
+ * changes to the roster are pushed from the server.
+ *
+ * @param listener a roster listener.
+ */
+ public void removeListener(AgentRosterListener listener) {
+ synchronized (listeners) {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Returns a count of all agents in the workgroup.
+ *
+ * @return the number of agents in the workgroup.
+ */
+ public int getAgentCount() {
+ return entries.size();
+ }
+
+ /**
+ * Returns all agents (String JID values) in the workgroup.
+ *
+ * @return all entries in the roster.
+ */
+ public Set<String> getAgents() {
+ Set<String> agents = new HashSet<String>();
+ synchronized (entries) {
+ for (Iterator<String> i = entries.iterator(); i.hasNext();) {
+ agents.add(i.next());
+ }
+ }
+ return Collections.unmodifiableSet(agents);
+ }
+
+ /**
+ * Returns true if the specified XMPP address is an agent in the workgroup.
+ *
+ * @param jid the XMPP address of the agent (eg "jsmith@example.com"). The
+ * address can be in any valid format (e.g. "domain/resource", "user@domain"
+ * or "user@domain/resource").
+ * @return true if the XMPP address is an agent in the workgroup.
+ */
+ public boolean contains(String jid) {
+ if (jid == null) {
+ return false;
+ }
+ synchronized (entries) {
+ for (Iterator<String> i = entries.iterator(); i.hasNext();) {
+ String entry = i.next();
+ if (entry.toLowerCase().equals(jid.toLowerCase())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the presence info for a particular agent, or <tt>null</tt> if the agent
+ * is unavailable (offline) or if no presence information is available.<p>
+ *
+ * @param user a fully qualified xmpp JID. The address could be in any valid format (e.g.
+ * "domain/resource", "user@domain" or "user@domain/resource").
+ * @return the agent's current presence, or <tt>null</tt> if the agent is unavailable
+ * or if no presence information is available..
+ */
+ public Presence getPresence(String user) {
+ String key = getPresenceMapKey(user);
+ Map<String, Presence> userPresences = presenceMap.get(key);
+ if (userPresences == null) {
+ Presence presence = new Presence(Presence.Type.unavailable);
+ presence.setFrom(user);
+ return presence;
+ }
+ else {
+ // Find the resource with the highest priority
+ // Might be changed to use the resource with the highest availability instead.
+ Iterator<String> it = userPresences.keySet().iterator();
+ Presence p;
+ Presence presence = null;
+
+ while (it.hasNext()) {
+ p = (Presence)userPresences.get(it.next());
+ if (presence == null){
+ presence = p;
+ }
+ else {
+ if (p.getPriority() > presence.getPriority()) {
+ presence = p;
+ }
+ }
+ }
+ if (presence == null) {
+ presence = new Presence(Presence.Type.unavailable);
+ presence.setFrom(user);
+ return presence;
+ }
+ else {
+ return presence;
+ }
+ }
+ }
+
+ /**
+ * Returns the key to use in the presenceMap for a fully qualified xmpp ID. The roster
+ * can contain any valid address format such us "domain/resource", "user@domain" or
+ * "user@domain/resource". If the roster contains an entry associated with the fully qualified
+ * xmpp ID then use the fully qualified xmpp ID as the key in presenceMap, otherwise use the
+ * bare address. Note: When the key in presenceMap is a fully qualified xmpp ID, the
+ * userPresences is useless since it will always contain one entry for the user.
+ *
+ * @param user the fully qualified xmpp ID, e.g. jdoe@example.com/Work.
+ * @return the key to use in the presenceMap for the fully qualified xmpp ID.
+ */
+ private String getPresenceMapKey(String user) {
+ String key = user;
+ if (!contains(user)) {
+ key = StringUtils.parseBareAddress(user).toLowerCase();
+ }
+ return key;
+ }
+
+ /**
+ * Fires event to listeners.
+ */
+ private void fireEvent(int eventType, Object eventObject) {
+ AgentRosterListener[] listeners = null;
+ synchronized (this.listeners) {
+ listeners = new AgentRosterListener[this.listeners.size()];
+ this.listeners.toArray(listeners);
+ }
+ for (int i = 0; i < listeners.length; i++) {
+ switch (eventType) {
+ case EVENT_AGENT_ADDED:
+ listeners[i].agentAdded((String)eventObject);
+ break;
+ case EVENT_AGENT_REMOVED:
+ listeners[i].agentRemoved((String)eventObject);
+ break;
+ case EVENT_PRESENCE_CHANGED:
+ listeners[i].presenceChanged((Presence)eventObject);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Listens for all presence packets and processes them.
+ */
+ private class PresencePacketListener implements PacketListener {
+ public void processPacket(Packet packet) {
+ Presence presence = (Presence)packet;
+ String from = presence.getFrom();
+ if (from == null) {
+ // TODO Check if we need to ignore these presences or this is a server bug?
+ System.out.println("Presence with no FROM: " + presence.toXML());
+ return;
+ }
+ String key = getPresenceMapKey(from);
+
+ // If an "available" packet, add it to the presence map. Each presence map will hold
+ // for a particular user a map with the presence packets saved for each resource.
+ if (presence.getType() == Presence.Type.available) {
+ // Ignore the presence packet unless it has an agent status extension.
+ AgentStatus agentStatus = (AgentStatus)presence.getExtension(
+ AgentStatus.ELEMENT_NAME, AgentStatus.NAMESPACE);
+ if (agentStatus == null) {
+ return;
+ }
+ // Ensure that this presence is coming from an Agent of the same workgroup
+ // of this Agent
+ else if (!workgroupJID.equals(agentStatus.getWorkgroupJID())) {
+ return;
+ }
+ Map<String, Presence> userPresences;
+ // Get the user presence map
+ if (presenceMap.get(key) == null) {
+ userPresences = new HashMap<String, Presence>();
+ presenceMap.put(key, userPresences);
+ }
+ else {
+ userPresences = presenceMap.get(key);
+ }
+ // Add the new presence, using the resources as a key.
+ synchronized (userPresences) {
+ userPresences.put(StringUtils.parseResource(from), presence);
+ }
+ // Fire an event.
+ synchronized (entries) {
+ for (Iterator<String> i = entries.iterator(); i.hasNext();) {
+ String entry = i.next();
+ if (entry.toLowerCase().equals(StringUtils.parseBareAddress(key).toLowerCase())) {
+ fireEvent(EVENT_PRESENCE_CHANGED, packet);
+ }
+ }
+ }
+ }
+ // If an "unavailable" packet, remove any entries in the presence map.
+ else if (presence.getType() == Presence.Type.unavailable) {
+ if (presenceMap.get(key) != null) {
+ Map<String,Presence> userPresences = presenceMap.get(key);
+ synchronized (userPresences) {
+ userPresences.remove(StringUtils.parseResource(from));
+ }
+ if (userPresences.isEmpty()) {
+ presenceMap.remove(key);
+ }
+ }
+ // Fire an event.
+ synchronized (entries) {
+ for (Iterator<String> i = entries.iterator(); i.hasNext();) {
+ String entry = (String)i.next();
+ if (entry.toLowerCase().equals(StringUtils.parseBareAddress(key).toLowerCase())) {
+ fireEvent(EVENT_PRESENCE_CHANGED, packet);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Listens for all roster packets and processes them.
+ */
+ private class AgentStatusListener implements PacketListener {
+
+ public void processPacket(Packet packet) {
+ if (packet instanceof AgentStatusRequest) {
+ AgentStatusRequest statusRequest = (AgentStatusRequest)packet;
+ for (Iterator<AgentStatusRequest.Item> i = statusRequest.getAgents().iterator(); i.hasNext();) {
+ AgentStatusRequest.Item item = i.next();
+ String agentJID = item.getJID();
+ if ("remove".equals(item.getType())) {
+
+ // Removing the user from the roster, so remove any presence information
+ // about them.
+ String key = StringUtils.parseName(StringUtils.parseName(agentJID) + "@" +
+ StringUtils.parseServer(agentJID));
+ presenceMap.remove(key);
+ // Fire event for roster listeners.
+ fireEvent(EVENT_AGENT_REMOVED, agentJID);
+ }
+ else {
+ entries.add(agentJID);
+ // Fire event for roster listeners.
+ fireEvent(EVENT_AGENT_ADDED, agentJID);
+ }
+ }
+
+ // Mark the roster as initialized.
+ rosterInitialized = true;
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRosterListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRosterListener.java
index 4db920377..afea9ff98 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRosterListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentRosterListener.java
@@ -1,35 +1,35 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import org.jivesoftware.smack.packet.Presence;
-
-/**
- *
- * @author Matt Tucker
- */
-public interface AgentRosterListener {
-
- public void agentAdded(String jid);
-
- public void agentRemoved(String jid);
-
- public void presenceChanged(Presence presence);
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import org.jivesoftware.smack.packet.Presence;
+
+/**
+ *
+ * @author Matt Tucker
+ */
+public interface AgentRosterListener {
+
+ public void agentAdded(String jid);
+
+ public void agentRemoved(String jid);
+
+ public void presenceChanged(Presence presence);
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentSession.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentSession.java
index 46d19d0d5..0600644e5 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentSession.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/AgentSession.java
@@ -1,1185 +1,1185 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import org.jivesoftware.smackx.workgroup.MetaData;
-import org.jivesoftware.smackx.workgroup.QueueUser;
-import org.jivesoftware.smackx.workgroup.WorkgroupInvitation;
-import org.jivesoftware.smackx.workgroup.WorkgroupInvitationListener;
-import org.jivesoftware.smackx.workgroup.ext.history.AgentChatHistory;
-import org.jivesoftware.smackx.workgroup.ext.history.ChatMetadata;
-import org.jivesoftware.smackx.workgroup.ext.macros.MacroGroup;
-import org.jivesoftware.smackx.workgroup.ext.macros.Macros;
-import org.jivesoftware.smackx.workgroup.ext.notes.ChatNotes;
-import org.jivesoftware.smackx.workgroup.packet.*;
-import org.jivesoftware.smackx.workgroup.settings.GenericSettings;
-import org.jivesoftware.smackx.workgroup.settings.SearchSettings;
-import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.filter.*;
-import org.jivesoftware.smack.packet.*;
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.ReportedData;
-import org.jivesoftware.smackx.packet.MUCUser;
-
-import java.util.*;
-
-/**
- * This class embodies the agent's active presence within a given workgroup. The application
- * should have N instances of this class, where N is the number of workgroups to which the
- * owning agent of the application belongs. This class provides all functionality that a
- * session within a given workgroup is expected to have from an agent's perspective -- setting
- * the status, tracking the status of queues to which the agent belongs within the workgroup, and
- * dequeuing customers.
- *
- * @author Matt Tucker
- * @author Derek DeMoro
- */
-public class AgentSession {
-
- private Connection connection;
-
- private String workgroupJID;
-
- private boolean online = false;
- private Presence.Mode presenceMode;
- private int maxChats;
- private final Map<String, List<String>> metaData;
-
- private Map<String, WorkgroupQueue> queues;
-
- private final List<OfferListener> offerListeners;
- private final List<WorkgroupInvitationListener> invitationListeners;
- private final List<QueueUsersListener> queueUsersListeners;
-
- private AgentRoster agentRoster = null;
- private TranscriptManager transcriptManager;
- private TranscriptSearchManager transcriptSearchManager;
- private Agent agent;
- private PacketListener packetListener;
-
- /**
- * Constructs a new agent session instance. Note, the {@link #setOnline(boolean)}
- * method must be called with an argument of <tt>true</tt> to mark the agent
- * as available to accept chat requests.
- *
- * @param connection a connection instance which must have already gone through
- * authentication.
- * @param workgroupJID the fully qualified JID of the workgroup.
- */
- public AgentSession(String workgroupJID, Connection connection) {
- // Login must have been done before passing in connection.
- if (!connection.isAuthenticated()) {
- throw new IllegalStateException("Must login to server before creating workgroup.");
- }
-
- this.workgroupJID = workgroupJID;
- this.connection = connection;
- this.transcriptManager = new TranscriptManager(connection);
- this.transcriptSearchManager = new TranscriptSearchManager(connection);
-
- this.maxChats = -1;
-
- this.metaData = new HashMap<String, List<String>>();
-
- this.queues = new HashMap<String, WorkgroupQueue>();
-
- offerListeners = new ArrayList<OfferListener>();
- invitationListeners = new ArrayList<WorkgroupInvitationListener>();
- queueUsersListeners = new ArrayList<QueueUsersListener>();
-
- // Create a filter to listen for packets we're interested in.
- OrFilter filter = new OrFilter();
- filter.addFilter(new PacketTypeFilter(OfferRequestProvider.OfferRequestPacket.class));
- filter.addFilter(new PacketTypeFilter(OfferRevokeProvider.OfferRevokePacket.class));
- filter.addFilter(new PacketTypeFilter(Presence.class));
- filter.addFilter(new PacketTypeFilter(Message.class));
-
- packetListener = new PacketListener() {
- public void processPacket(Packet packet) {
- try {
- handlePacket(packet);
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- };
- connection.addPacketListener(packetListener, filter);
- // Create the agent associated to this session
- agent = new Agent(connection, workgroupJID);
- }
-
- /**
- * Close the agent session. The underlying connection will remain opened but the
- * packet listeners that were added by this agent session will be removed.
- */
- public void close() {
- connection.removePacketListener(packetListener);
- }
-
- /**
- * Returns the agent roster for the workgroup, which contains
- *
- * @return the AgentRoster
- */
- public AgentRoster getAgentRoster() {
- if (agentRoster == null) {
- agentRoster = new AgentRoster(connection, workgroupJID);
- }
-
- // This might be the first time the user has asked for the roster. If so, we
- // want to wait up to 2 seconds for the server to send back the list of agents.
- // This behavior shields API users from having to worry about the fact that the
- // operation is asynchronous, although they'll still have to listen for changes
- // to the roster.
- int elapsed = 0;
- while (!agentRoster.rosterInitialized && elapsed <= 2000) {
- try {
- Thread.sleep(500);
- }
- catch (Exception e) {
- // Ignore
- }
- elapsed += 500;
- }
- return agentRoster;
- }
-
- /**
- * Returns the agent's current presence mode.
- *
- * @return the agent's current presence mode.
- */
- public Presence.Mode getPresenceMode() {
- return presenceMode;
- }
-
- /**
- * Returns the maximum number of chats the agent can participate in.
- *
- * @return the maximum number of chats the agent can participate in.
- */
- public int getMaxChats() {
- return maxChats;
- }
-
- /**
- * Returns true if the agent is online with the workgroup.
- *
- * @return true if the agent is online with the workgroup.
- */
- public boolean isOnline() {
- return online;
- }
-
- /**
- * Allows the addition of a new key-value pair to the agent's meta data, if the value is
- * new data, the revised meta data will be rebroadcast in an agent's presence broadcast.
- *
- * @param key the meta data key
- * @param val the non-null meta data value
- * @throws XMPPException if an exception occurs.
- */
- public void setMetaData(String key, String val) throws XMPPException {
- synchronized (this.metaData) {
- List<String> oldVals = metaData.get(key);
-
- if ((oldVals == null) || (!oldVals.get(0).equals(val))) {
- oldVals.set(0, val);
-
- setStatus(presenceMode, maxChats);
- }
- }
- }
-
- /**
- * Allows the removal of data from the agent's meta data, if the key represents existing data,
- * the revised meta data will be rebroadcast in an agent's presence broadcast.
- *
- * @param key the meta data key.
- * @throws XMPPException if an exception occurs.
- */
- public void removeMetaData(String key) throws XMPPException {
- synchronized (this.metaData) {
- List<String> oldVal = metaData.remove(key);
-
- if (oldVal != null) {
- setStatus(presenceMode, maxChats);
- }
- }
- }
-
- /**
- * Allows the retrieval of meta data for a specified key.
- *
- * @param key the meta data key
- * @return the meta data value associated with the key or <tt>null</tt> if the meta-data
- * doesn't exist..
- */
- public List<String> getMetaData(String key) {
- return metaData.get(key);
- }
-
- /**
- * Sets whether the agent is online with the workgroup. If the user tries to go online with
- * the workgroup but is not allowed to be an agent, an XMPPError with error code 401 will
- * be thrown.
- *
- * @param online true to set the agent as online with the workgroup.
- * @throws XMPPException if an error occurs setting the online status.
- */
- public void setOnline(boolean online) throws XMPPException {
- // If the online status hasn't changed, do nothing.
- if (this.online == online) {
- return;
- }
-
- Presence presence;
-
- // If the user is going online...
- if (online) {
- presence = new Presence(Presence.Type.available);
- presence.setTo(workgroupJID);
- presence.addExtension(new DefaultPacketExtension(AgentStatus.ELEMENT_NAME,
- AgentStatus.NAMESPACE));
-
- PacketCollector collector = this.connection.createPacketCollector(new AndFilter(new PacketTypeFilter(Presence.class), new FromContainsFilter(workgroupJID)));
-
- connection.sendPacket(presence);
-
- presence = (Presence)collector.nextResult(5000);
- collector.cancel();
- if (!presence.isAvailable()) {
- throw new XMPPException("No response from server on status set.");
- }
-
- if (presence.getError() != null) {
- throw new XMPPException(presence.getError());
- }
-
- // We can safely update this iv since we didn't get any error
- this.online = online;
- }
- // Otherwise the user is going offline...
- else {
- // Update this iv now since we don't care at this point of any error
- this.online = online;
-
- presence = new Presence(Presence.Type.unavailable);
- presence.setTo(workgroupJID);
- presence.addExtension(new DefaultPacketExtension(AgentStatus.ELEMENT_NAME,
- AgentStatus.NAMESPACE));
- connection.sendPacket(presence);
- }
- }
-
- /**
- * Sets the agent's current status with the workgroup. The presence mode affects
- * how offers are routed to the agent. The possible presence modes with their
- * meanings are as follows:<ul>
- * <p/>
- * <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
- * (equivalent to Presence.Mode.CHAT).
- * <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
- * However, special case, or extreme urgency chats may still be offered to the agent.
- * <li>Presence.Mode.AWAY -- the agent is not available and should not
- * have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
- * <p/>
- * The max chats value is the maximum number of chats the agent is willing to have
- * routed to them at once. Some servers may be configured to only accept max chat
- * values in a certain range; for example, between two and five. In that case, the
- * maxChats value the agent sends may be adjusted by the server to a value within that
- * range.
- *
- * @param presenceMode the presence mode of the agent.
- * @param maxChats the maximum number of chats the agent is willing to accept.
- * @throws XMPPException if an error occurs setting the agent status.
- * @throws IllegalStateException if the agent is not online with the workgroup.
- */
- public void setStatus(Presence.Mode presenceMode, int maxChats) throws XMPPException {
- setStatus(presenceMode, maxChats, null);
- }
-
- /**
- * Sets the agent's current status with the workgroup. The presence mode affects how offers
- * are routed to the agent. The possible presence modes with their meanings are as follows:<ul>
- * <p/>
- * <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
- * (equivalent to Presence.Mode.CHAT).
- * <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
- * However, special case, or extreme urgency chats may still be offered to the agent.
- * <li>Presence.Mode.AWAY -- the agent is not available and should not
- * have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
- * <p/>
- * The max chats value is the maximum number of chats the agent is willing to have routed to
- * them at once. Some servers may be configured to only accept max chat values in a certain
- * range; for example, between two and five. In that case, the maxChats value the agent sends
- * may be adjusted by the server to a value within that range.
- *
- * @param presenceMode the presence mode of the agent.
- * @param maxChats the maximum number of chats the agent is willing to accept.
- * @param status sets the status message of the presence update.
- * @throws XMPPException if an error occurs setting the agent status.
- * @throws IllegalStateException if the agent is not online with the workgroup.
- */
- public void setStatus(Presence.Mode presenceMode, int maxChats, String status)
- throws XMPPException {
- if (!online) {
- throw new IllegalStateException("Cannot set status when the agent is not online.");
- }
-
- if (presenceMode == null) {
- presenceMode = Presence.Mode.available;
- }
- this.presenceMode = presenceMode;
- this.maxChats = maxChats;
-
- Presence presence = new Presence(Presence.Type.available);
- presence.setMode(presenceMode);
- presence.setTo(this.getWorkgroupJID());
-
- if (status != null) {
- presence.setStatus(status);
- }
- // Send information about max chats and current chats as a packet extension.
- DefaultPacketExtension agentStatus = new DefaultPacketExtension(AgentStatus.ELEMENT_NAME,
- AgentStatus.NAMESPACE);
- agentStatus.setValue("max-chats", "" + maxChats);
- presence.addExtension(agentStatus);
- presence.addExtension(new MetaData(this.metaData));
-
- PacketCollector collector = this.connection.createPacketCollector(new AndFilter(new PacketTypeFilter(Presence.class), new FromContainsFilter(workgroupJID)));
-
- this.connection.sendPacket(presence);
-
- presence = (Presence)collector.nextResult(5000);
- collector.cancel();
- if (!presence.isAvailable()) {
- throw new XMPPException("No response from server on status set.");
- }
-
- if (presence.getError() != null) {
- throw new XMPPException(presence.getError());
- }
- }
-
- /**
- * Sets the agent's current status with the workgroup. The presence mode affects how offers
- * are routed to the agent. The possible presence modes with their meanings are as follows:<ul>
- * <p/>
- * <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
- * (equivalent to Presence.Mode.CHAT).
- * <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
- * However, special case, or extreme urgency chats may still be offered to the agent.
- * <li>Presence.Mode.AWAY -- the agent is not available and should not
- * have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
- *
- * @param presenceMode the presence mode of the agent.
- * @param status sets the status message of the presence update.
- * @throws XMPPException if an error occurs setting the agent status.
- * @throws IllegalStateException if the agent is not online with the workgroup.
- */
- public void setStatus(Presence.Mode presenceMode, String status) throws XMPPException {
- if (!online) {
- throw new IllegalStateException("Cannot set status when the agent is not online.");
- }
-
- if (presenceMode == null) {
- presenceMode = Presence.Mode.available;
- }
- this.presenceMode = presenceMode;
-
- Presence presence = new Presence(Presence.Type.available);
- presence.setMode(presenceMode);
- presence.setTo(this.getWorkgroupJID());
-
- if (status != null) {
- presence.setStatus(status);
- }
- presence.addExtension(new MetaData(this.metaData));
-
- PacketCollector collector = this.connection.createPacketCollector(new AndFilter(new PacketTypeFilter(Presence.class),
- new FromContainsFilter(workgroupJID)));
-
- this.connection.sendPacket(presence);
-
- presence = (Presence)collector.nextResult(5000);
- collector.cancel();
- if (!presence.isAvailable()) {
- throw new XMPPException("No response from server on status set.");
- }
-
- if (presence.getError() != null) {
- throw new XMPPException(presence.getError());
- }
- }
-
- /**
- * Removes a user from the workgroup queue. This is an administrative action that the
- * <p/>
- * The agent is not guaranteed of having privileges to perform this action; an exception
- * denying the request may be thrown.
- *
- * @param userID the ID of the user to remove.
- * @throws XMPPException if an exception occurs.
- */
- public void dequeueUser(String userID) throws XMPPException {
- // todo: this method simply won't work right now.
- DepartQueuePacket departPacket = new DepartQueuePacket(this.workgroupJID);
-
- // PENDING
- this.connection.sendPacket(departPacket);
- }
-
- /**
- * Returns the transcripts of a given user. The answer will contain the complete history of
- * conversations that a user had.
- *
- * @param userID the id of the user to get his conversations.
- * @return the transcripts of a given user.
- * @throws XMPPException if an error occurs while getting the information.
- */
- public Transcripts getTranscripts(String userID) throws XMPPException {
- return transcriptManager.getTranscripts(workgroupJID, userID);
- }
-
- /**
- * Returns the full conversation transcript of a given session.
- *
- * @param sessionID the id of the session to get the full transcript.
- * @return the full conversation transcript of a given session.
- * @throws XMPPException if an error occurs while getting the information.
- */
- public Transcript getTranscript(String sessionID) throws XMPPException {
- return transcriptManager.getTranscript(workgroupJID, sessionID);
- }
-
- /**
- * Returns the Form to use for searching transcripts. It is unlikely that the server
- * will change the form (without a restart) so it is safe to keep the returned form
- * for future submissions.
- *
- * @return the Form to use for searching transcripts.
- * @throws XMPPException if an error occurs while sending the request to the server.
- */
- public Form getTranscriptSearchForm() throws XMPPException {
- return transcriptSearchManager.getSearchForm(StringUtils.parseServer(workgroupJID));
- }
-
- /**
- * Submits the completed form and returns the result of the transcript search. The result
- * will include all the data returned from the server so be careful with the amount of
- * data that the search may return.
- *
- * @param completedForm the filled out search form.
- * @return the result of the transcript search.
- * @throws XMPPException if an error occurs while submiting the search to the server.
- */
- public ReportedData searchTranscripts(Form completedForm) throws XMPPException {
- return transcriptSearchManager.submitSearch(StringUtils.parseServer(workgroupJID),
- completedForm);
- }
-
- /**
- * Asks the workgroup for information about the occupants of the specified room. The returned
- * information will include the real JID of the occupants, the nickname of the user in the
- * room as well as the date when the user joined the room.
- *
- * @param roomID the room to get information about its occupants.
- * @return information about the occupants of the specified room.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public OccupantsInfo getOccupantsInfo(String roomID) throws XMPPException {
- OccupantsInfo request = new OccupantsInfo(roomID);
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
- OccupantsInfo response = (OccupantsInfo)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * @return the fully-qualified name of the workgroup for which this session exists
- */
- public String getWorkgroupJID() {
- return workgroupJID;
- }
-
- /**
- * Returns the Agent associated to this session.
- *
- * @return the Agent associated to this session.
- */
- public Agent getAgent() {
- return agent;
- }
-
- /**
- * @param queueName the name of the queue
- * @return an instance of WorkgroupQueue for the argument queue name, or null if none exists
- */
- public WorkgroupQueue getQueue(String queueName) {
- return queues.get(queueName);
- }
-
- public Iterator<WorkgroupQueue> getQueues() {
- return Collections.unmodifiableMap((new HashMap<String, WorkgroupQueue>(queues))).values().iterator();
- }
-
- public void addQueueUsersListener(QueueUsersListener listener) {
- synchronized (queueUsersListeners) {
- if (!queueUsersListeners.contains(listener)) {
- queueUsersListeners.add(listener);
- }
- }
- }
-
- public void removeQueueUsersListener(QueueUsersListener listener) {
- synchronized (queueUsersListeners) {
- queueUsersListeners.remove(listener);
- }
- }
-
- /**
- * Adds an offer listener.
- *
- * @param offerListener the offer listener.
- */
- public void addOfferListener(OfferListener offerListener) {
- synchronized (offerListeners) {
- if (!offerListeners.contains(offerListener)) {
- offerListeners.add(offerListener);
- }
- }
- }
-
- /**
- * Removes an offer listener.
- *
- * @param offerListener the offer listener.
- */
- public void removeOfferListener(OfferListener offerListener) {
- synchronized (offerListeners) {
- offerListeners.remove(offerListener);
- }
- }
-
- /**
- * Adds an invitation listener.
- *
- * @param invitationListener the invitation listener.
- */
- public void addInvitationListener(WorkgroupInvitationListener invitationListener) {
- synchronized (invitationListeners) {
- if (!invitationListeners.contains(invitationListener)) {
- invitationListeners.add(invitationListener);
- }
- }
- }
-
- /**
- * Removes an invitation listener.
- *
- * @param invitationListener the invitation listener.
- */
- public void removeInvitationListener(WorkgroupInvitationListener invitationListener) {
- synchronized (invitationListeners) {
- invitationListeners.remove(invitationListener);
- }
- }
-
- private void fireOfferRequestEvent(OfferRequestProvider.OfferRequestPacket requestPacket) {
- Offer offer = new Offer(this.connection, this, requestPacket.getUserID(),
- requestPacket.getUserJID(), this.getWorkgroupJID(),
- new Date((new Date()).getTime() + (requestPacket.getTimeout() * 1000)),
- requestPacket.getSessionID(), requestPacket.getMetaData(), requestPacket.getContent());
-
- synchronized (offerListeners) {
- for (OfferListener listener : offerListeners) {
- listener.offerReceived(offer);
- }
- }
- }
-
- private void fireOfferRevokeEvent(OfferRevokeProvider.OfferRevokePacket orp) {
- RevokedOffer revokedOffer = new RevokedOffer(orp.getUserJID(), orp.getUserID(),
- this.getWorkgroupJID(), orp.getSessionID(), orp.getReason(), new Date());
-
- synchronized (offerListeners) {
- for (OfferListener listener : offerListeners) {
- listener.offerRevoked(revokedOffer);
- }
- }
- }
-
- private void fireInvitationEvent(String groupChatJID, String sessionID, String body,
- String from, Map<String, List<String>> metaData) {
- WorkgroupInvitation invitation = new WorkgroupInvitation(connection.getUser(), groupChatJID,
- workgroupJID, sessionID, body, from, metaData);
-
- synchronized (invitationListeners) {
- for (WorkgroupInvitationListener listener : invitationListeners) {
- listener.invitationReceived(invitation);
- }
- }
- }
-
- private void fireQueueUsersEvent(WorkgroupQueue queue, WorkgroupQueue.Status status,
- int averageWaitTime, Date oldestEntry, Set<QueueUser> users) {
- synchronized (queueUsersListeners) {
- for (QueueUsersListener listener : queueUsersListeners) {
- if (status != null) {
- listener.statusUpdated(queue, status);
- }
- if (averageWaitTime != -1) {
- listener.averageWaitTimeUpdated(queue, averageWaitTime);
- }
- if (oldestEntry != null) {
- listener.oldestEntryUpdated(queue, oldestEntry);
- }
- if (users != null) {
- listener.usersUpdated(queue, users);
- }
- }
- }
- }
-
- // PacketListener Implementation.
-
- private void handlePacket(Packet packet) {
- if (packet instanceof OfferRequestProvider.OfferRequestPacket) {
- // Acknowledge the IQ set.
- IQ reply = new IQ() {
- public String getChildElementXML() {
- return null;
- }
- };
- reply.setPacketID(packet.getPacketID());
- reply.setTo(packet.getFrom());
- reply.setType(IQ.Type.RESULT);
- connection.sendPacket(reply);
-
- fireOfferRequestEvent((OfferRequestProvider.OfferRequestPacket)packet);
- }
- else if (packet instanceof Presence) {
- Presence presence = (Presence)packet;
-
- // The workgroup can send us a number of different presence packets. We
- // check for different packet extensions to see what type of presence
- // packet it is.
-
- String queueName = StringUtils.parseResource(presence.getFrom());
- WorkgroupQueue queue = queues.get(queueName);
- // If there isn't already an entry for the queue, create a new one.
- if (queue == null) {
- queue = new WorkgroupQueue(queueName);
- queues.put(queueName, queue);
- }
-
- // QueueOverview packet extensions contain basic information about a queue.
- QueueOverview queueOverview = (QueueOverview)presence.getExtension(QueueOverview.ELEMENT_NAME, QueueOverview.NAMESPACE);
- if (queueOverview != null) {
- if (queueOverview.getStatus() == null) {
- queue.setStatus(WorkgroupQueue.Status.CLOSED);
- }
- else {
- queue.setStatus(queueOverview.getStatus());
- }
- queue.setAverageWaitTime(queueOverview.getAverageWaitTime());
- queue.setOldestEntry(queueOverview.getOldestEntry());
- // Fire event.
- fireQueueUsersEvent(queue, queueOverview.getStatus(),
- queueOverview.getAverageWaitTime(), queueOverview.getOldestEntry(),
- null);
- return;
- }
-
- // QueueDetails packet extensions contain information about the users in
- // a queue.
- QueueDetails queueDetails = (QueueDetails)packet.getExtension(QueueDetails.ELEMENT_NAME, QueueDetails.NAMESPACE);
- if (queueDetails != null) {
- queue.setUsers(queueDetails.getUsers());
- // Fire event.
- fireQueueUsersEvent(queue, null, -1, null, queueDetails.getUsers());
- return;
- }
-
- // Notify agent packets gives an overview of agent activity in a queue.
- DefaultPacketExtension notifyAgents = (DefaultPacketExtension)presence.getExtension("notify-agents", "http://jabber.org/protocol/workgroup");
- if (notifyAgents != null) {
- int currentChats = Integer.parseInt(notifyAgents.getValue("current-chats"));
- int maxChats = Integer.parseInt(notifyAgents.getValue("max-chats"));
- queue.setCurrentChats(currentChats);
- queue.setMaxChats(maxChats);
- // Fire event.
- // TODO: might need another event for current chats and max chats of queue
- return;
- }
- }
- else if (packet instanceof Message) {
- Message message = (Message)packet;
-
- // Check if a room invitation was sent and if the sender is the workgroup
- MUCUser mucUser = (MUCUser)message.getExtension("x",
- "http://jabber.org/protocol/muc#user");
- MUCUser.Invite invite = mucUser != null ? mucUser.getInvite() : null;
- if (invite != null && workgroupJID.equals(invite.getFrom())) {
- String sessionID = null;
- Map<String, List<String>> metaData = null;
-
- SessionID sessionIDExt = (SessionID)message.getExtension(SessionID.ELEMENT_NAME,
- SessionID.NAMESPACE);
- if (sessionIDExt != null) {
- sessionID = sessionIDExt.getSessionID();
- }
-
- MetaData metaDataExt = (MetaData)message.getExtension(MetaData.ELEMENT_NAME,
- MetaData.NAMESPACE);
- if (metaDataExt != null) {
- metaData = metaDataExt.getMetaData();
- }
-
- this.fireInvitationEvent(message.getFrom(), sessionID, message.getBody(),
- message.getFrom(), metaData);
- }
- }
- else if (packet instanceof OfferRevokeProvider.OfferRevokePacket) {
- // Acknowledge the IQ set.
- IQ reply = new IQ() {
- public String getChildElementXML() {
- return null;
- }
- };
- reply.setPacketID(packet.getPacketID());
- reply.setType(IQ.Type.RESULT);
- connection.sendPacket(reply);
-
- fireOfferRevokeEvent((OfferRevokeProvider.OfferRevokePacket)packet);
- }
- }
-
- /**
- * Creates a ChatNote that will be mapped to the given chat session.
- *
- * @param sessionID the session id of a Chat Session.
- * @param note the chat note to add.
- * @throws XMPPException is thrown if an error occurs while adding the note.
- */
- public void setNote(String sessionID, String note) throws XMPPException {
- note = ChatNotes.replace(note, "\n", "\\n");
- note = StringUtils.escapeForXML(note);
-
- ChatNotes notes = new ChatNotes();
- notes.setType(IQ.Type.SET);
- notes.setTo(workgroupJID);
- notes.setSessionID(sessionID);
- notes.setNotes(note);
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(notes.getPacketID()));
- // Send the request
- connection.sendPacket(notes);
-
- IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- }
-
- /**
- * Retrieves the ChatNote associated with a given chat session.
- *
- * @param sessionID the sessionID of the chat session.
- * @return the <code>ChatNote</code> associated with a given chat session.
- * @throws XMPPException if an error occurs while retrieving the ChatNote.
- */
- public ChatNotes getNote(String sessionID) throws XMPPException {
- ChatNotes request = new ChatNotes();
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
- request.setSessionID(sessionID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
- ChatNotes response = (ChatNotes)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
-
- }
-
- /**
- * Retrieves the AgentChatHistory associated with a particular agent jid.
- *
- * @param jid the jid of the agent.
- * @param maxSessions the max number of sessions to retrieve.
- * @param startDate the starting date of sessions to retrieve.
- * @return the chat history associated with a given jid.
- * @throws XMPPException if an error occurs while retrieving the AgentChatHistory.
- */
- public AgentChatHistory getAgentHistory(String jid, int maxSessions, Date startDate) throws XMPPException {
- AgentChatHistory request;
- if (startDate != null) {
- request = new AgentChatHistory(jid, maxSessions, startDate);
- }
- else {
- request = new AgentChatHistory(jid, maxSessions);
- }
-
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
- AgentChatHistory response = (AgentChatHistory)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * Asks the workgroup for it's Search Settings.
- *
- * @return SearchSettings the search settings for this workgroup.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public SearchSettings getSearchSettings() throws XMPPException {
- SearchSettings request = new SearchSettings();
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- SearchSettings response = (SearchSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * Asks the workgroup for it's Global Macros.
- *
- * @param global true to retrieve global macros, otherwise false for personal macros.
- * @return MacroGroup the root macro group.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public MacroGroup getMacros(boolean global) throws XMPPException {
- Macros request = new Macros();
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
- request.setPersonal(!global);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- Macros response = (Macros)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response.getRootGroup();
- }
-
- /**
- * Persists the Personal Macro for an agent.
- *
- * @param group the macro group to save.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public void saveMacros(MacroGroup group) throws XMPPException {
- Macros request = new Macros();
- request.setType(IQ.Type.SET);
- request.setTo(workgroupJID);
- request.setPersonal(true);
- request.setPersonalMacroGroup(group);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- }
-
- /**
- * Query for metadata associated with a session id.
- *
- * @param sessionID the sessionID to query for.
- * @return Map a map of all metadata associated with the sessionID.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public Map<String, List<String>> getChatMetadata(String sessionID) throws XMPPException {
- ChatMetadata request = new ChatMetadata();
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
- request.setSessionID(sessionID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- ChatMetadata response = (ChatMetadata)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response.getMetadata();
- }
-
- /**
- * Invites a user or agent to an existing session support. The provided invitee's JID can be of
- * a user, an agent, a queue or a workgroup. In the case of a queue or a workgroup the workgroup service
- * will decide the best agent to receive the invitation.<p>
- *
- * This method will return either when the service returned an ACK of the request or if an error occured
- * while requesting the invitation. After sending the ACK the service will send the invitation to the target
- * entity. When dealing with agents the common sequence of offer-response will be followed. However, when
- * sending an invitation to a user a standard MUC invitation will be sent.<p>
- *
- * The agent or user that accepted the offer <b>MUST</b> join the room. Failing to do so will make
- * the invitation to fail. The inviter will eventually receive a message error indicating that the invitee
- * accepted the offer but failed to join the room.
- *
- * Different situations may lead to a failed invitation. Possible cases are: 1) all agents rejected the
- * offer and ther are no agents available, 2) the agent that accepted the offer failed to join the room or
- * 2) the user that received the MUC invitation never replied or joined the room. In any of these cases
- * (or other failing cases) the inviter will get an error message with the failed notification.
- *
- * @param type type of entity that will get the invitation.
- * @param invitee JID of entity that will get the invitation.
- * @param sessionID ID of the support session that the invitee is being invited.
- * @param reason the reason of the invitation.
- * @throws XMPPException if the sender of the invitation is not an agent or the service failed to process
- * the request.
- */
- public void sendRoomInvitation(RoomInvitation.Type type, String invitee, String sessionID, String reason)
- throws XMPPException {
- final RoomInvitation invitation = new RoomInvitation(type, invitee, sessionID, reason);
- IQ iq = new IQ() {
-
- public String getChildElementXML() {
- return invitation.toXML();
- }
- };
- iq.setType(IQ.Type.SET);
- iq.setTo(workgroupJID);
- iq.setFrom(connection.getUser());
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(iq.getPacketID()));
- connection.sendPacket(iq);
-
- IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- }
-
- /**
- * Transfer an existing session support to another user or agent. The provided invitee's JID can be of
- * a user, an agent, a queue or a workgroup. In the case of a queue or a workgroup the workgroup service
- * will decide the best agent to receive the invitation.<p>
- *
- * This method will return either when the service returned an ACK of the request or if an error occured
- * while requesting the transfer. After sending the ACK the service will send the invitation to the target
- * entity. When dealing with agents the common sequence of offer-response will be followed. However, when
- * sending an invitation to a user a standard MUC invitation will be sent.<p>
- *
- * Once the invitee joins the support room the workgroup service will kick the inviter from the room.<p>
- *
- * Different situations may lead to a failed transfers. Possible cases are: 1) all agents rejected the
- * offer and there are no agents available, 2) the agent that accepted the offer failed to join the room
- * or 2) the user that received the MUC invitation never replied or joined the room. In any of these cases
- * (or other failing cases) the inviter will get an error message with the failed notification.
- *
- * @param type type of entity that will get the invitation.
- * @param invitee JID of entity that will get the invitation.
- * @param sessionID ID of the support session that the invitee is being invited.
- * @param reason the reason of the invitation.
- * @throws XMPPException if the sender of the invitation is not an agent or the service failed to process
- * the request.
- */
- public void sendRoomTransfer(RoomTransfer.Type type, String invitee, String sessionID, String reason)
- throws XMPPException {
- final RoomTransfer transfer = new RoomTransfer(type, invitee, sessionID, reason);
- IQ iq = new IQ() {
-
- public String getChildElementXML() {
- return transfer.toXML();
- }
- };
- iq.setType(IQ.Type.SET);
- iq.setTo(workgroupJID);
- iq.setFrom(connection.getUser());
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(iq.getPacketID()));
- connection.sendPacket(iq);
-
- IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- }
-
- /**
- * Returns the generic metadata of the workgroup the agent belongs to.
- *
- * @param con the Connection to use.
- * @param query an optional query object used to tell the server what metadata to retrieve. This can be null.
- * @throws XMPPException if an error occurs while sending the request to the server.
- * @return the settings for the workgroup.
- */
- public GenericSettings getGenericSettings(Connection con, String query) throws XMPPException {
- GenericSettings setting = new GenericSettings();
- setting.setType(IQ.Type.GET);
- setting.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(setting.getPacketID()));
- connection.sendPacket(setting);
-
- GenericSettings response = (GenericSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- public boolean hasMonitorPrivileges(Connection con) throws XMPPException {
- MonitorPacket request = new MonitorPacket();
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
- MonitorPacket response = (MonitorPacket)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response.isMonitor();
-
- }
-
- public void makeRoomOwner(Connection con, String sessionID) throws XMPPException {
- MonitorPacket request = new MonitorPacket();
- request.setType(IQ.Type.SET);
- request.setTo(workgroupJID);
- request.setSessionID(sessionID);
-
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
- Packet response = collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import org.jivesoftware.smackx.workgroup.MetaData;
+import org.jivesoftware.smackx.workgroup.QueueUser;
+import org.jivesoftware.smackx.workgroup.WorkgroupInvitation;
+import org.jivesoftware.smackx.workgroup.WorkgroupInvitationListener;
+import org.jivesoftware.smackx.workgroup.ext.history.AgentChatHistory;
+import org.jivesoftware.smackx.workgroup.ext.history.ChatMetadata;
+import org.jivesoftware.smackx.workgroup.ext.macros.MacroGroup;
+import org.jivesoftware.smackx.workgroup.ext.macros.Macros;
+import org.jivesoftware.smackx.workgroup.ext.notes.ChatNotes;
+import org.jivesoftware.smackx.workgroup.packet.*;
+import org.jivesoftware.smackx.workgroup.settings.GenericSettings;
+import org.jivesoftware.smackx.workgroup.settings.SearchSettings;
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.ReportedData;
+import org.jivesoftware.smackx.packet.MUCUser;
+
+import java.util.*;
+
+/**
+ * This class embodies the agent's active presence within a given workgroup. The application
+ * should have N instances of this class, where N is the number of workgroups to which the
+ * owning agent of the application belongs. This class provides all functionality that a
+ * session within a given workgroup is expected to have from an agent's perspective -- setting
+ * the status, tracking the status of queues to which the agent belongs within the workgroup, and
+ * dequeuing customers.
+ *
+ * @author Matt Tucker
+ * @author Derek DeMoro
+ */
+public class AgentSession {
+
+ private Connection connection;
+
+ private String workgroupJID;
+
+ private boolean online = false;
+ private Presence.Mode presenceMode;
+ private int maxChats;
+ private final Map<String, List<String>> metaData;
+
+ private Map<String, WorkgroupQueue> queues;
+
+ private final List<OfferListener> offerListeners;
+ private final List<WorkgroupInvitationListener> invitationListeners;
+ private final List<QueueUsersListener> queueUsersListeners;
+
+ private AgentRoster agentRoster = null;
+ private TranscriptManager transcriptManager;
+ private TranscriptSearchManager transcriptSearchManager;
+ private Agent agent;
+ private PacketListener packetListener;
+
+ /**
+ * Constructs a new agent session instance. Note, the {@link #setOnline(boolean)}
+ * method must be called with an argument of <tt>true</tt> to mark the agent
+ * as available to accept chat requests.
+ *
+ * @param connection a connection instance which must have already gone through
+ * authentication.
+ * @param workgroupJID the fully qualified JID of the workgroup.
+ */
+ public AgentSession(String workgroupJID, Connection connection) {
+ // Login must have been done before passing in connection.
+ if (!connection.isAuthenticated()) {
+ throw new IllegalStateException("Must login to server before creating workgroup.");
+ }
+
+ this.workgroupJID = workgroupJID;
+ this.connection = connection;
+ this.transcriptManager = new TranscriptManager(connection);
+ this.transcriptSearchManager = new TranscriptSearchManager(connection);
+
+ this.maxChats = -1;
+
+ this.metaData = new HashMap<String, List<String>>();
+
+ this.queues = new HashMap<String, WorkgroupQueue>();
+
+ offerListeners = new ArrayList<OfferListener>();
+ invitationListeners = new ArrayList<WorkgroupInvitationListener>();
+ queueUsersListeners = new ArrayList<QueueUsersListener>();
+
+ // Create a filter to listen for packets we're interested in.
+ OrFilter filter = new OrFilter();
+ filter.addFilter(new PacketTypeFilter(OfferRequestProvider.OfferRequestPacket.class));
+ filter.addFilter(new PacketTypeFilter(OfferRevokeProvider.OfferRevokePacket.class));
+ filter.addFilter(new PacketTypeFilter(Presence.class));
+ filter.addFilter(new PacketTypeFilter(Message.class));
+
+ packetListener = new PacketListener() {
+ public void processPacket(Packet packet) {
+ try {
+ handlePacket(packet);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ connection.addPacketListener(packetListener, filter);
+ // Create the agent associated to this session
+ agent = new Agent(connection, workgroupJID);
+ }
+
+ /**
+ * Close the agent session. The underlying connection will remain opened but the
+ * packet listeners that were added by this agent session will be removed.
+ */
+ public void close() {
+ connection.removePacketListener(packetListener);
+ }
+
+ /**
+ * Returns the agent roster for the workgroup, which contains
+ *
+ * @return the AgentRoster
+ */
+ public AgentRoster getAgentRoster() {
+ if (agentRoster == null) {
+ agentRoster = new AgentRoster(connection, workgroupJID);
+ }
+
+ // This might be the first time the user has asked for the roster. If so, we
+ // want to wait up to 2 seconds for the server to send back the list of agents.
+ // This behavior shields API users from having to worry about the fact that the
+ // operation is asynchronous, although they'll still have to listen for changes
+ // to the roster.
+ int elapsed = 0;
+ while (!agentRoster.rosterInitialized && elapsed <= 2000) {
+ try {
+ Thread.sleep(500);
+ }
+ catch (Exception e) {
+ // Ignore
+ }
+ elapsed += 500;
+ }
+ return agentRoster;
+ }
+
+ /**
+ * Returns the agent's current presence mode.
+ *
+ * @return the agent's current presence mode.
+ */
+ public Presence.Mode getPresenceMode() {
+ return presenceMode;
+ }
+
+ /**
+ * Returns the maximum number of chats the agent can participate in.
+ *
+ * @return the maximum number of chats the agent can participate in.
+ */
+ public int getMaxChats() {
+ return maxChats;
+ }
+
+ /**
+ * Returns true if the agent is online with the workgroup.
+ *
+ * @return true if the agent is online with the workgroup.
+ */
+ public boolean isOnline() {
+ return online;
+ }
+
+ /**
+ * Allows the addition of a new key-value pair to the agent's meta data, if the value is
+ * new data, the revised meta data will be rebroadcast in an agent's presence broadcast.
+ *
+ * @param key the meta data key
+ * @param val the non-null meta data value
+ * @throws XMPPException if an exception occurs.
+ */
+ public void setMetaData(String key, String val) throws XMPPException {
+ synchronized (this.metaData) {
+ List<String> oldVals = metaData.get(key);
+
+ if ((oldVals == null) || (!oldVals.get(0).equals(val))) {
+ oldVals.set(0, val);
+
+ setStatus(presenceMode, maxChats);
+ }
+ }
+ }
+
+ /**
+ * Allows the removal of data from the agent's meta data, if the key represents existing data,
+ * the revised meta data will be rebroadcast in an agent's presence broadcast.
+ *
+ * @param key the meta data key.
+ * @throws XMPPException if an exception occurs.
+ */
+ public void removeMetaData(String key) throws XMPPException {
+ synchronized (this.metaData) {
+ List<String> oldVal = metaData.remove(key);
+
+ if (oldVal != null) {
+ setStatus(presenceMode, maxChats);
+ }
+ }
+ }
+
+ /**
+ * Allows the retrieval of meta data for a specified key.
+ *
+ * @param key the meta data key
+ * @return the meta data value associated with the key or <tt>null</tt> if the meta-data
+ * doesn't exist..
+ */
+ public List<String> getMetaData(String key) {
+ return metaData.get(key);
+ }
+
+ /**
+ * Sets whether the agent is online with the workgroup. If the user tries to go online with
+ * the workgroup but is not allowed to be an agent, an XMPPError with error code 401 will
+ * be thrown.
+ *
+ * @param online true to set the agent as online with the workgroup.
+ * @throws XMPPException if an error occurs setting the online status.
+ */
+ public void setOnline(boolean online) throws XMPPException {
+ // If the online status hasn't changed, do nothing.
+ if (this.online == online) {
+ return;
+ }
+
+ Presence presence;
+
+ // If the user is going online...
+ if (online) {
+ presence = new Presence(Presence.Type.available);
+ presence.setTo(workgroupJID);
+ presence.addExtension(new DefaultPacketExtension(AgentStatus.ELEMENT_NAME,
+ AgentStatus.NAMESPACE));
+
+ PacketCollector collector = this.connection.createPacketCollector(new AndFilter(new PacketTypeFilter(Presence.class), new FromContainsFilter(workgroupJID)));
+
+ connection.sendPacket(presence);
+
+ presence = (Presence)collector.nextResult(5000);
+ collector.cancel();
+ if (!presence.isAvailable()) {
+ throw new XMPPException("No response from server on status set.");
+ }
+
+ if (presence.getError() != null) {
+ throw new XMPPException(presence.getError());
+ }
+
+ // We can safely update this iv since we didn't get any error
+ this.online = online;
+ }
+ // Otherwise the user is going offline...
+ else {
+ // Update this iv now since we don't care at this point of any error
+ this.online = online;
+
+ presence = new Presence(Presence.Type.unavailable);
+ presence.setTo(workgroupJID);
+ presence.addExtension(new DefaultPacketExtension(AgentStatus.ELEMENT_NAME,
+ AgentStatus.NAMESPACE));
+ connection.sendPacket(presence);
+ }
+ }
+
+ /**
+ * Sets the agent's current status with the workgroup. The presence mode affects
+ * how offers are routed to the agent. The possible presence modes with their
+ * meanings are as follows:<ul>
+ * <p/>
+ * <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
+ * (equivalent to Presence.Mode.CHAT).
+ * <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
+ * However, special case, or extreme urgency chats may still be offered to the agent.
+ * <li>Presence.Mode.AWAY -- the agent is not available and should not
+ * have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
+ * <p/>
+ * The max chats value is the maximum number of chats the agent is willing to have
+ * routed to them at once. Some servers may be configured to only accept max chat
+ * values in a certain range; for example, between two and five. In that case, the
+ * maxChats value the agent sends may be adjusted by the server to a value within that
+ * range.
+ *
+ * @param presenceMode the presence mode of the agent.
+ * @param maxChats the maximum number of chats the agent is willing to accept.
+ * @throws XMPPException if an error occurs setting the agent status.
+ * @throws IllegalStateException if the agent is not online with the workgroup.
+ */
+ public void setStatus(Presence.Mode presenceMode, int maxChats) throws XMPPException {
+ setStatus(presenceMode, maxChats, null);
+ }
+
+ /**
+ * Sets the agent's current status with the workgroup. The presence mode affects how offers
+ * are routed to the agent. The possible presence modes with their meanings are as follows:<ul>
+ * <p/>
+ * <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
+ * (equivalent to Presence.Mode.CHAT).
+ * <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
+ * However, special case, or extreme urgency chats may still be offered to the agent.
+ * <li>Presence.Mode.AWAY -- the agent is not available and should not
+ * have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
+ * <p/>
+ * The max chats value is the maximum number of chats the agent is willing to have routed to
+ * them at once. Some servers may be configured to only accept max chat values in a certain
+ * range; for example, between two and five. In that case, the maxChats value the agent sends
+ * may be adjusted by the server to a value within that range.
+ *
+ * @param presenceMode the presence mode of the agent.
+ * @param maxChats the maximum number of chats the agent is willing to accept.
+ * @param status sets the status message of the presence update.
+ * @throws XMPPException if an error occurs setting the agent status.
+ * @throws IllegalStateException if the agent is not online with the workgroup.
+ */
+ public void setStatus(Presence.Mode presenceMode, int maxChats, String status)
+ throws XMPPException {
+ if (!online) {
+ throw new IllegalStateException("Cannot set status when the agent is not online.");
+ }
+
+ if (presenceMode == null) {
+ presenceMode = Presence.Mode.available;
+ }
+ this.presenceMode = presenceMode;
+ this.maxChats = maxChats;
+
+ Presence presence = new Presence(Presence.Type.available);
+ presence.setMode(presenceMode);
+ presence.setTo(this.getWorkgroupJID());
+
+ if (status != null) {
+ presence.setStatus(status);
+ }
+ // Send information about max chats and current chats as a packet extension.
+ DefaultPacketExtension agentStatus = new DefaultPacketExtension(AgentStatus.ELEMENT_NAME,
+ AgentStatus.NAMESPACE);
+ agentStatus.setValue("max-chats", "" + maxChats);
+ presence.addExtension(agentStatus);
+ presence.addExtension(new MetaData(this.metaData));
+
+ PacketCollector collector = this.connection.createPacketCollector(new AndFilter(new PacketTypeFilter(Presence.class), new FromContainsFilter(workgroupJID)));
+
+ this.connection.sendPacket(presence);
+
+ presence = (Presence)collector.nextResult(5000);
+ collector.cancel();
+ if (!presence.isAvailable()) {
+ throw new XMPPException("No response from server on status set.");
+ }
+
+ if (presence.getError() != null) {
+ throw new XMPPException(presence.getError());
+ }
+ }
+
+ /**
+ * Sets the agent's current status with the workgroup. The presence mode affects how offers
+ * are routed to the agent. The possible presence modes with their meanings are as follows:<ul>
+ * <p/>
+ * <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
+ * (equivalent to Presence.Mode.CHAT).
+ * <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
+ * However, special case, or extreme urgency chats may still be offered to the agent.
+ * <li>Presence.Mode.AWAY -- the agent is not available and should not
+ * have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
+ *
+ * @param presenceMode the presence mode of the agent.
+ * @param status sets the status message of the presence update.
+ * @throws XMPPException if an error occurs setting the agent status.
+ * @throws IllegalStateException if the agent is not online with the workgroup.
+ */
+ public void setStatus(Presence.Mode presenceMode, String status) throws XMPPException {
+ if (!online) {
+ throw new IllegalStateException("Cannot set status when the agent is not online.");
+ }
+
+ if (presenceMode == null) {
+ presenceMode = Presence.Mode.available;
+ }
+ this.presenceMode = presenceMode;
+
+ Presence presence = new Presence(Presence.Type.available);
+ presence.setMode(presenceMode);
+ presence.setTo(this.getWorkgroupJID());
+
+ if (status != null) {
+ presence.setStatus(status);
+ }
+ presence.addExtension(new MetaData(this.metaData));
+
+ PacketCollector collector = this.connection.createPacketCollector(new AndFilter(new PacketTypeFilter(Presence.class),
+ new FromContainsFilter(workgroupJID)));
+
+ this.connection.sendPacket(presence);
+
+ presence = (Presence)collector.nextResult(5000);
+ collector.cancel();
+ if (!presence.isAvailable()) {
+ throw new XMPPException("No response from server on status set.");
+ }
+
+ if (presence.getError() != null) {
+ throw new XMPPException(presence.getError());
+ }
+ }
+
+ /**
+ * Removes a user from the workgroup queue. This is an administrative action that the
+ * <p/>
+ * The agent is not guaranteed of having privileges to perform this action; an exception
+ * denying the request may be thrown.
+ *
+ * @param userID the ID of the user to remove.
+ * @throws XMPPException if an exception occurs.
+ */
+ public void dequeueUser(String userID) throws XMPPException {
+ // todo: this method simply won't work right now.
+ DepartQueuePacket departPacket = new DepartQueuePacket(this.workgroupJID);
+
+ // PENDING
+ this.connection.sendPacket(departPacket);
+ }
+
+ /**
+ * Returns the transcripts of a given user. The answer will contain the complete history of
+ * conversations that a user had.
+ *
+ * @param userID the id of the user to get his conversations.
+ * @return the transcripts of a given user.
+ * @throws XMPPException if an error occurs while getting the information.
+ */
+ public Transcripts getTranscripts(String userID) throws XMPPException {
+ return transcriptManager.getTranscripts(workgroupJID, userID);
+ }
+
+ /**
+ * Returns the full conversation transcript of a given session.
+ *
+ * @param sessionID the id of the session to get the full transcript.
+ * @return the full conversation transcript of a given session.
+ * @throws XMPPException if an error occurs while getting the information.
+ */
+ public Transcript getTranscript(String sessionID) throws XMPPException {
+ return transcriptManager.getTranscript(workgroupJID, sessionID);
+ }
+
+ /**
+ * Returns the Form to use for searching transcripts. It is unlikely that the server
+ * will change the form (without a restart) so it is safe to keep the returned form
+ * for future submissions.
+ *
+ * @return the Form to use for searching transcripts.
+ * @throws XMPPException if an error occurs while sending the request to the server.
+ */
+ public Form getTranscriptSearchForm() throws XMPPException {
+ return transcriptSearchManager.getSearchForm(StringUtils.parseServer(workgroupJID));
+ }
+
+ /**
+ * Submits the completed form and returns the result of the transcript search. The result
+ * will include all the data returned from the server so be careful with the amount of
+ * data that the search may return.
+ *
+ * @param completedForm the filled out search form.
+ * @return the result of the transcript search.
+ * @throws XMPPException if an error occurs while submiting the search to the server.
+ */
+ public ReportedData searchTranscripts(Form completedForm) throws XMPPException {
+ return transcriptSearchManager.submitSearch(StringUtils.parseServer(workgroupJID),
+ completedForm);
+ }
+
+ /**
+ * Asks the workgroup for information about the occupants of the specified room. The returned
+ * information will include the real JID of the occupants, the nickname of the user in the
+ * room as well as the date when the user joined the room.
+ *
+ * @param roomID the room to get information about its occupants.
+ * @return information about the occupants of the specified room.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public OccupantsInfo getOccupantsInfo(String roomID) throws XMPPException {
+ OccupantsInfo request = new OccupantsInfo(roomID);
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+ OccupantsInfo response = (OccupantsInfo)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * @return the fully-qualified name of the workgroup for which this session exists
+ */
+ public String getWorkgroupJID() {
+ return workgroupJID;
+ }
+
+ /**
+ * Returns the Agent associated to this session.
+ *
+ * @return the Agent associated to this session.
+ */
+ public Agent getAgent() {
+ return agent;
+ }
+
+ /**
+ * @param queueName the name of the queue
+ * @return an instance of WorkgroupQueue for the argument queue name, or null if none exists
+ */
+ public WorkgroupQueue getQueue(String queueName) {
+ return queues.get(queueName);
+ }
+
+ public Iterator<WorkgroupQueue> getQueues() {
+ return Collections.unmodifiableMap((new HashMap<String, WorkgroupQueue>(queues))).values().iterator();
+ }
+
+ public void addQueueUsersListener(QueueUsersListener listener) {
+ synchronized (queueUsersListeners) {
+ if (!queueUsersListeners.contains(listener)) {
+ queueUsersListeners.add(listener);
+ }
+ }
+ }
+
+ public void removeQueueUsersListener(QueueUsersListener listener) {
+ synchronized (queueUsersListeners) {
+ queueUsersListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Adds an offer listener.
+ *
+ * @param offerListener the offer listener.
+ */
+ public void addOfferListener(OfferListener offerListener) {
+ synchronized (offerListeners) {
+ if (!offerListeners.contains(offerListener)) {
+ offerListeners.add(offerListener);
+ }
+ }
+ }
+
+ /**
+ * Removes an offer listener.
+ *
+ * @param offerListener the offer listener.
+ */
+ public void removeOfferListener(OfferListener offerListener) {
+ synchronized (offerListeners) {
+ offerListeners.remove(offerListener);
+ }
+ }
+
+ /**
+ * Adds an invitation listener.
+ *
+ * @param invitationListener the invitation listener.
+ */
+ public void addInvitationListener(WorkgroupInvitationListener invitationListener) {
+ synchronized (invitationListeners) {
+ if (!invitationListeners.contains(invitationListener)) {
+ invitationListeners.add(invitationListener);
+ }
+ }
+ }
+
+ /**
+ * Removes an invitation listener.
+ *
+ * @param invitationListener the invitation listener.
+ */
+ public void removeInvitationListener(WorkgroupInvitationListener invitationListener) {
+ synchronized (invitationListeners) {
+ invitationListeners.remove(invitationListener);
+ }
+ }
+
+ private void fireOfferRequestEvent(OfferRequestProvider.OfferRequestPacket requestPacket) {
+ Offer offer = new Offer(this.connection, this, requestPacket.getUserID(),
+ requestPacket.getUserJID(), this.getWorkgroupJID(),
+ new Date((new Date()).getTime() + (requestPacket.getTimeout() * 1000)),
+ requestPacket.getSessionID(), requestPacket.getMetaData(), requestPacket.getContent());
+
+ synchronized (offerListeners) {
+ for (OfferListener listener : offerListeners) {
+ listener.offerReceived(offer);
+ }
+ }
+ }
+
+ private void fireOfferRevokeEvent(OfferRevokeProvider.OfferRevokePacket orp) {
+ RevokedOffer revokedOffer = new RevokedOffer(orp.getUserJID(), orp.getUserID(),
+ this.getWorkgroupJID(), orp.getSessionID(), orp.getReason(), new Date());
+
+ synchronized (offerListeners) {
+ for (OfferListener listener : offerListeners) {
+ listener.offerRevoked(revokedOffer);
+ }
+ }
+ }
+
+ private void fireInvitationEvent(String groupChatJID, String sessionID, String body,
+ String from, Map<String, List<String>> metaData) {
+ WorkgroupInvitation invitation = new WorkgroupInvitation(connection.getUser(), groupChatJID,
+ workgroupJID, sessionID, body, from, metaData);
+
+ synchronized (invitationListeners) {
+ for (WorkgroupInvitationListener listener : invitationListeners) {
+ listener.invitationReceived(invitation);
+ }
+ }
+ }
+
+ private void fireQueueUsersEvent(WorkgroupQueue queue, WorkgroupQueue.Status status,
+ int averageWaitTime, Date oldestEntry, Set<QueueUser> users) {
+ synchronized (queueUsersListeners) {
+ for (QueueUsersListener listener : queueUsersListeners) {
+ if (status != null) {
+ listener.statusUpdated(queue, status);
+ }
+ if (averageWaitTime != -1) {
+ listener.averageWaitTimeUpdated(queue, averageWaitTime);
+ }
+ if (oldestEntry != null) {
+ listener.oldestEntryUpdated(queue, oldestEntry);
+ }
+ if (users != null) {
+ listener.usersUpdated(queue, users);
+ }
+ }
+ }
+ }
+
+ // PacketListener Implementation.
+
+ private void handlePacket(Packet packet) {
+ if (packet instanceof OfferRequestProvider.OfferRequestPacket) {
+ // Acknowledge the IQ set.
+ IQ reply = new IQ() {
+ public String getChildElementXML() {
+ return null;
+ }
+ };
+ reply.setPacketID(packet.getPacketID());
+ reply.setTo(packet.getFrom());
+ reply.setType(IQ.Type.RESULT);
+ connection.sendPacket(reply);
+
+ fireOfferRequestEvent((OfferRequestProvider.OfferRequestPacket)packet);
+ }
+ else if (packet instanceof Presence) {
+ Presence presence = (Presence)packet;
+
+ // The workgroup can send us a number of different presence packets. We
+ // check for different packet extensions to see what type of presence
+ // packet it is.
+
+ String queueName = StringUtils.parseResource(presence.getFrom());
+ WorkgroupQueue queue = queues.get(queueName);
+ // If there isn't already an entry for the queue, create a new one.
+ if (queue == null) {
+ queue = new WorkgroupQueue(queueName);
+ queues.put(queueName, queue);
+ }
+
+ // QueueOverview packet extensions contain basic information about a queue.
+ QueueOverview queueOverview = (QueueOverview)presence.getExtension(QueueOverview.ELEMENT_NAME, QueueOverview.NAMESPACE);
+ if (queueOverview != null) {
+ if (queueOverview.getStatus() == null) {
+ queue.setStatus(WorkgroupQueue.Status.CLOSED);
+ }
+ else {
+ queue.setStatus(queueOverview.getStatus());
+ }
+ queue.setAverageWaitTime(queueOverview.getAverageWaitTime());
+ queue.setOldestEntry(queueOverview.getOldestEntry());
+ // Fire event.
+ fireQueueUsersEvent(queue, queueOverview.getStatus(),
+ queueOverview.getAverageWaitTime(), queueOverview.getOldestEntry(),
+ null);
+ return;
+ }
+
+ // QueueDetails packet extensions contain information about the users in
+ // a queue.
+ QueueDetails queueDetails = (QueueDetails)packet.getExtension(QueueDetails.ELEMENT_NAME, QueueDetails.NAMESPACE);
+ if (queueDetails != null) {
+ queue.setUsers(queueDetails.getUsers());
+ // Fire event.
+ fireQueueUsersEvent(queue, null, -1, null, queueDetails.getUsers());
+ return;
+ }
+
+ // Notify agent packets gives an overview of agent activity in a queue.
+ DefaultPacketExtension notifyAgents = (DefaultPacketExtension)presence.getExtension("notify-agents", "http://jabber.org/protocol/workgroup");
+ if (notifyAgents != null) {
+ int currentChats = Integer.parseInt(notifyAgents.getValue("current-chats"));
+ int maxChats = Integer.parseInt(notifyAgents.getValue("max-chats"));
+ queue.setCurrentChats(currentChats);
+ queue.setMaxChats(maxChats);
+ // Fire event.
+ // TODO: might need another event for current chats and max chats of queue
+ return;
+ }
+ }
+ else if (packet instanceof Message) {
+ Message message = (Message)packet;
+
+ // Check if a room invitation was sent and if the sender is the workgroup
+ MUCUser mucUser = (MUCUser)message.getExtension("x",
+ "http://jabber.org/protocol/muc#user");
+ MUCUser.Invite invite = mucUser != null ? mucUser.getInvite() : null;
+ if (invite != null && workgroupJID.equals(invite.getFrom())) {
+ String sessionID = null;
+ Map<String, List<String>> metaData = null;
+
+ SessionID sessionIDExt = (SessionID)message.getExtension(SessionID.ELEMENT_NAME,
+ SessionID.NAMESPACE);
+ if (sessionIDExt != null) {
+ sessionID = sessionIDExt.getSessionID();
+ }
+
+ MetaData metaDataExt = (MetaData)message.getExtension(MetaData.ELEMENT_NAME,
+ MetaData.NAMESPACE);
+ if (metaDataExt != null) {
+ metaData = metaDataExt.getMetaData();
+ }
+
+ this.fireInvitationEvent(message.getFrom(), sessionID, message.getBody(),
+ message.getFrom(), metaData);
+ }
+ }
+ else if (packet instanceof OfferRevokeProvider.OfferRevokePacket) {
+ // Acknowledge the IQ set.
+ IQ reply = new IQ() {
+ public String getChildElementXML() {
+ return null;
+ }
+ };
+ reply.setPacketID(packet.getPacketID());
+ reply.setType(IQ.Type.RESULT);
+ connection.sendPacket(reply);
+
+ fireOfferRevokeEvent((OfferRevokeProvider.OfferRevokePacket)packet);
+ }
+ }
+
+ /**
+ * Creates a ChatNote that will be mapped to the given chat session.
+ *
+ * @param sessionID the session id of a Chat Session.
+ * @param note the chat note to add.
+ * @throws XMPPException is thrown if an error occurs while adding the note.
+ */
+ public void setNote(String sessionID, String note) throws XMPPException {
+ note = ChatNotes.replace(note, "\n", "\\n");
+ note = StringUtils.escapeForXML(note);
+
+ ChatNotes notes = new ChatNotes();
+ notes.setType(IQ.Type.SET);
+ notes.setTo(workgroupJID);
+ notes.setSessionID(sessionID);
+ notes.setNotes(note);
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(notes.getPacketID()));
+ // Send the request
+ connection.sendPacket(notes);
+
+ IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ }
+
+ /**
+ * Retrieves the ChatNote associated with a given chat session.
+ *
+ * @param sessionID the sessionID of the chat session.
+ * @return the <code>ChatNote</code> associated with a given chat session.
+ * @throws XMPPException if an error occurs while retrieving the ChatNote.
+ */
+ public ChatNotes getNote(String sessionID) throws XMPPException {
+ ChatNotes request = new ChatNotes();
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+ request.setSessionID(sessionID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+ ChatNotes response = (ChatNotes)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+
+ }
+
+ /**
+ * Retrieves the AgentChatHistory associated with a particular agent jid.
+ *
+ * @param jid the jid of the agent.
+ * @param maxSessions the max number of sessions to retrieve.
+ * @param startDate the starting date of sessions to retrieve.
+ * @return the chat history associated with a given jid.
+ * @throws XMPPException if an error occurs while retrieving the AgentChatHistory.
+ */
+ public AgentChatHistory getAgentHistory(String jid, int maxSessions, Date startDate) throws XMPPException {
+ AgentChatHistory request;
+ if (startDate != null) {
+ request = new AgentChatHistory(jid, maxSessions, startDate);
+ }
+ else {
+ request = new AgentChatHistory(jid, maxSessions);
+ }
+
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+ AgentChatHistory response = (AgentChatHistory)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * Asks the workgroup for it's Search Settings.
+ *
+ * @return SearchSettings the search settings for this workgroup.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public SearchSettings getSearchSettings() throws XMPPException {
+ SearchSettings request = new SearchSettings();
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ SearchSettings response = (SearchSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * Asks the workgroup for it's Global Macros.
+ *
+ * @param global true to retrieve global macros, otherwise false for personal macros.
+ * @return MacroGroup the root macro group.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public MacroGroup getMacros(boolean global) throws XMPPException {
+ Macros request = new Macros();
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+ request.setPersonal(!global);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ Macros response = (Macros)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response.getRootGroup();
+ }
+
+ /**
+ * Persists the Personal Macro for an agent.
+ *
+ * @param group the macro group to save.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public void saveMacros(MacroGroup group) throws XMPPException {
+ Macros request = new Macros();
+ request.setType(IQ.Type.SET);
+ request.setTo(workgroupJID);
+ request.setPersonal(true);
+ request.setPersonalMacroGroup(group);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ }
+
+ /**
+ * Query for metadata associated with a session id.
+ *
+ * @param sessionID the sessionID to query for.
+ * @return Map a map of all metadata associated with the sessionID.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public Map<String, List<String>> getChatMetadata(String sessionID) throws XMPPException {
+ ChatMetadata request = new ChatMetadata();
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+ request.setSessionID(sessionID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ ChatMetadata response = (ChatMetadata)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response.getMetadata();
+ }
+
+ /**
+ * Invites a user or agent to an existing session support. The provided invitee's JID can be of
+ * a user, an agent, a queue or a workgroup. In the case of a queue or a workgroup the workgroup service
+ * will decide the best agent to receive the invitation.<p>
+ *
+ * This method will return either when the service returned an ACK of the request or if an error occured
+ * while requesting the invitation. After sending the ACK the service will send the invitation to the target
+ * entity. When dealing with agents the common sequence of offer-response will be followed. However, when
+ * sending an invitation to a user a standard MUC invitation will be sent.<p>
+ *
+ * The agent or user that accepted the offer <b>MUST</b> join the room. Failing to do so will make
+ * the invitation to fail. The inviter will eventually receive a message error indicating that the invitee
+ * accepted the offer but failed to join the room.
+ *
+ * Different situations may lead to a failed invitation. Possible cases are: 1) all agents rejected the
+ * offer and ther are no agents available, 2) the agent that accepted the offer failed to join the room or
+ * 2) the user that received the MUC invitation never replied or joined the room. In any of these cases
+ * (or other failing cases) the inviter will get an error message with the failed notification.
+ *
+ * @param type type of entity that will get the invitation.
+ * @param invitee JID of entity that will get the invitation.
+ * @param sessionID ID of the support session that the invitee is being invited.
+ * @param reason the reason of the invitation.
+ * @throws XMPPException if the sender of the invitation is not an agent or the service failed to process
+ * the request.
+ */
+ public void sendRoomInvitation(RoomInvitation.Type type, String invitee, String sessionID, String reason)
+ throws XMPPException {
+ final RoomInvitation invitation = new RoomInvitation(type, invitee, sessionID, reason);
+ IQ iq = new IQ() {
+
+ public String getChildElementXML() {
+ return invitation.toXML();
+ }
+ };
+ iq.setType(IQ.Type.SET);
+ iq.setTo(workgroupJID);
+ iq.setFrom(connection.getUser());
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(iq.getPacketID()));
+ connection.sendPacket(iq);
+
+ IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ }
+
+ /**
+ * Transfer an existing session support to another user or agent. The provided invitee's JID can be of
+ * a user, an agent, a queue or a workgroup. In the case of a queue or a workgroup the workgroup service
+ * will decide the best agent to receive the invitation.<p>
+ *
+ * This method will return either when the service returned an ACK of the request or if an error occured
+ * while requesting the transfer. After sending the ACK the service will send the invitation to the target
+ * entity. When dealing with agents the common sequence of offer-response will be followed. However, when
+ * sending an invitation to a user a standard MUC invitation will be sent.<p>
+ *
+ * Once the invitee joins the support room the workgroup service will kick the inviter from the room.<p>
+ *
+ * Different situations may lead to a failed transfers. Possible cases are: 1) all agents rejected the
+ * offer and there are no agents available, 2) the agent that accepted the offer failed to join the room
+ * or 2) the user that received the MUC invitation never replied or joined the room. In any of these cases
+ * (or other failing cases) the inviter will get an error message with the failed notification.
+ *
+ * @param type type of entity that will get the invitation.
+ * @param invitee JID of entity that will get the invitation.
+ * @param sessionID ID of the support session that the invitee is being invited.
+ * @param reason the reason of the invitation.
+ * @throws XMPPException if the sender of the invitation is not an agent or the service failed to process
+ * the request.
+ */
+ public void sendRoomTransfer(RoomTransfer.Type type, String invitee, String sessionID, String reason)
+ throws XMPPException {
+ final RoomTransfer transfer = new RoomTransfer(type, invitee, sessionID, reason);
+ IQ iq = new IQ() {
+
+ public String getChildElementXML() {
+ return transfer.toXML();
+ }
+ };
+ iq.setType(IQ.Type.SET);
+ iq.setTo(workgroupJID);
+ iq.setFrom(connection.getUser());
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(iq.getPacketID()));
+ connection.sendPacket(iq);
+
+ IQ response = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ }
+
+ /**
+ * Returns the generic metadata of the workgroup the agent belongs to.
+ *
+ * @param con the Connection to use.
+ * @param query an optional query object used to tell the server what metadata to retrieve. This can be null.
+ * @throws XMPPException if an error occurs while sending the request to the server.
+ * @return the settings for the workgroup.
+ */
+ public GenericSettings getGenericSettings(Connection con, String query) throws XMPPException {
+ GenericSettings setting = new GenericSettings();
+ setting.setType(IQ.Type.GET);
+ setting.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(setting.getPacketID()));
+ connection.sendPacket(setting);
+
+ GenericSettings response = (GenericSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ public boolean hasMonitorPrivileges(Connection con) throws XMPPException {
+ MonitorPacket request = new MonitorPacket();
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+ MonitorPacket response = (MonitorPacket)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response.isMonitor();
+
+ }
+
+ public void makeRoomOwner(Connection con, String sessionID) throws XMPPException {
+ MonitorPacket request = new MonitorPacket();
+ request.setType(IQ.Type.SET);
+ request.setTo(workgroupJID);
+ request.setSessionID(sessionID);
+
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+ Packet response = collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/InvitationRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/InvitationRequest.java
index 16b324ae2..33629befd 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/InvitationRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/InvitationRequest.java
@@ -1,62 +1,62 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-/**
- * Request sent by an agent to invite another agent or user.
- *
- * @author Gaston Dombiak
- */
-public class InvitationRequest extends OfferContent {
-
- private String inviter;
- private String room;
- private String reason;
-
- public InvitationRequest(String inviter, String room, String reason) {
- this.inviter = inviter;
- this.room = room;
- this.reason = reason;
- }
-
- public String getInviter() {
- return inviter;
- }
-
- public String getRoom() {
- return room;
- }
-
- public String getReason() {
- return reason;
- }
-
- boolean isUserRequest() {
- return false;
- }
-
- boolean isInvitation() {
- return true;
- }
-
- boolean isTransfer() {
- return false;
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+/**
+ * Request sent by an agent to invite another agent or user.
+ *
+ * @author Gaston Dombiak
+ */
+public class InvitationRequest extends OfferContent {
+
+ private String inviter;
+ private String room;
+ private String reason;
+
+ public InvitationRequest(String inviter, String room, String reason) {
+ this.inviter = inviter;
+ this.room = room;
+ this.reason = reason;
+ }
+
+ public String getInviter() {
+ return inviter;
+ }
+
+ public String getRoom() {
+ return room;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ boolean isUserRequest() {
+ return false;
+ }
+
+ boolean isInvitation() {
+ return true;
+ }
+
+ boolean isTransfer() {
+ return false;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Offer.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Offer.java
index ece8c6fde..98070c614 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Offer.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/Offer.java
@@ -1,223 +1,223 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A class embodying the semantic agent chat offer; specific instances allow the acceptance or
- * rejecting of the offer.<br>
- *
- * @author Matt Tucker
- * @author loki der quaeler
- * @author Derek DeMoro
- */
-public class Offer {
-
- private Connection connection;
- private AgentSession session;
-
- private String sessionID;
- private String userJID;
- private String userID;
- private String workgroupName;
- private Date expiresDate;
- private Map<String, List<String>> metaData;
- private OfferContent content;
-
- private boolean accepted = false;
- private boolean rejected = false;
-
- /**
- * Creates a new offer.
- *
- * @param conn the XMPP connection with which the issuing session was created.
- * @param agentSession the agent session instance through which this offer was issued.
- * @param userID the userID of the user from which the offer originates.
- * @param userJID the XMPP address of the user from which the offer originates.
- * @param workgroupName the fully qualified name of the workgroup.
- * @param expiresDate the date at which this offer expires.
- * @param sessionID the session id associated with the offer.
- * @param metaData the metadata associated with the offer.
- * @param content content of the offer. The content explains the reason for the offer
- * (e.g. user request, transfer)
- */
- Offer(Connection conn, AgentSession agentSession, String userID,
- String userJID, String workgroupName, Date expiresDate,
- String sessionID, Map<String, List<String>> metaData, OfferContent content)
- {
- this.connection = conn;
- this.session = agentSession;
- this.userID = userID;
- this.userJID = userJID;
- this.workgroupName = workgroupName;
- this.expiresDate = expiresDate;
- this.sessionID = sessionID;
- this.metaData = metaData;
- this.content = content;
- }
-
- /**
- * Accepts the offer.
- */
- public void accept() {
- Packet acceptPacket = new AcceptPacket(this.session.getWorkgroupJID());
- connection.sendPacket(acceptPacket);
- // TODO: listen for a reply.
- accepted = true;
- }
-
- /**
- * Rejects the offer.
- */
- public void reject() {
- RejectPacket rejectPacket = new RejectPacket(this.session.getWorkgroupJID());
- connection.sendPacket(rejectPacket);
- // TODO: listen for a reply.
- rejected = true;
- }
-
- /**
- * Returns the userID that the offer originates from. In most cases, the
- * userID will simply be the JID of the requesting user. However, users can
- * also manually specify a userID for their request. In that case, that value will
- * be returned.
- *
- * @return the userID of the user from which the offer originates.
- */
- public String getUserID() {
- return userID;
- }
-
- /**
- * Returns the JID of the user that made the offer request.
- *
- * @return the user's JID.
- */
- public String getUserJID() {
- return userJID;
- }
-
- /**
- * The fully qualified name of the workgroup (eg support@example.com).
- *
- * @return the name of the workgroup.
- */
- public String getWorkgroupName() {
- return this.workgroupName;
- }
-
- /**
- * The date when the offer will expire. The agent must {@link #accept()}
- * the offer before the expiration date or the offer will lapse and be
- * routed to another agent. Alternatively, the agent can {@link #reject()}
- * the offer at any time if they don't wish to accept it..
- *
- * @return the date at which this offer expires.
- */
- public Date getExpiresDate() {
- return this.expiresDate;
- }
-
- /**
- * The session ID associated with the offer.
- *
- * @return the session id associated with the offer.
- */
- public String getSessionID() {
- return this.sessionID;
- }
-
- /**
- * The meta-data associated with the offer.
- *
- * @return the offer meta-data.
- */
- public Map<String, List<String>> getMetaData() {
- return this.metaData;
- }
-
- /**
- * Returns the content of the offer. The content explains the reason for the offer
- * (e.g. user request, transfer)
- *
- * @return the content of the offer.
- */
- public OfferContent getContent() {
- return content;
- }
-
- /**
- * Returns true if the agent accepted this offer.
- *
- * @return true if the agent accepted this offer.
- */
- public boolean isAccepted() {
- return accepted;
- }
-
- /**
- * Return true if the agent rejected this offer.
- *
- * @return true if the agent rejected this offer.
- */
- public boolean isRejected() {
- return rejected;
- }
-
- /**
- * Packet for rejecting offers.
- */
- private class RejectPacket extends IQ {
-
- RejectPacket(String workgroup) {
- this.setTo(workgroup);
- this.setType(IQ.Type.SET);
- }
-
- public String getChildElementXML() {
- return "<offer-reject id=\"" + Offer.this.getSessionID() +
- "\" xmlns=\"http://jabber.org/protocol/workgroup" + "\"/>";
- }
- }
-
- /**
- * Packet for accepting an offer.
- */
- private class AcceptPacket extends IQ {
-
- AcceptPacket(String workgroup) {
- this.setTo(workgroup);
- this.setType(IQ.Type.SET);
- }
-
- public String getChildElementXML() {
- return "<offer-accept id=\"" + Offer.this.getSessionID() +
- "\" xmlns=\"http://jabber.org/protocol/workgroup" + "\"/>";
- }
- }
-
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A class embodying the semantic agent chat offer; specific instances allow the acceptance or
+ * rejecting of the offer.<br>
+ *
+ * @author Matt Tucker
+ * @author loki der quaeler
+ * @author Derek DeMoro
+ */
+public class Offer {
+
+ private Connection connection;
+ private AgentSession session;
+
+ private String sessionID;
+ private String userJID;
+ private String userID;
+ private String workgroupName;
+ private Date expiresDate;
+ private Map<String, List<String>> metaData;
+ private OfferContent content;
+
+ private boolean accepted = false;
+ private boolean rejected = false;
+
+ /**
+ * Creates a new offer.
+ *
+ * @param conn the XMPP connection with which the issuing session was created.
+ * @param agentSession the agent session instance through which this offer was issued.
+ * @param userID the userID of the user from which the offer originates.
+ * @param userJID the XMPP address of the user from which the offer originates.
+ * @param workgroupName the fully qualified name of the workgroup.
+ * @param expiresDate the date at which this offer expires.
+ * @param sessionID the session id associated with the offer.
+ * @param metaData the metadata associated with the offer.
+ * @param content content of the offer. The content explains the reason for the offer
+ * (e.g. user request, transfer)
+ */
+ Offer(Connection conn, AgentSession agentSession, String userID,
+ String userJID, String workgroupName, Date expiresDate,
+ String sessionID, Map<String, List<String>> metaData, OfferContent content)
+ {
+ this.connection = conn;
+ this.session = agentSession;
+ this.userID = userID;
+ this.userJID = userJID;
+ this.workgroupName = workgroupName;
+ this.expiresDate = expiresDate;
+ this.sessionID = sessionID;
+ this.metaData = metaData;
+ this.content = content;
+ }
+
+ /**
+ * Accepts the offer.
+ */
+ public void accept() {
+ Packet acceptPacket = new AcceptPacket(this.session.getWorkgroupJID());
+ connection.sendPacket(acceptPacket);
+ // TODO: listen for a reply.
+ accepted = true;
+ }
+
+ /**
+ * Rejects the offer.
+ */
+ public void reject() {
+ RejectPacket rejectPacket = new RejectPacket(this.session.getWorkgroupJID());
+ connection.sendPacket(rejectPacket);
+ // TODO: listen for a reply.
+ rejected = true;
+ }
+
+ /**
+ * Returns the userID that the offer originates from. In most cases, the
+ * userID will simply be the JID of the requesting user. However, users can
+ * also manually specify a userID for their request. In that case, that value will
+ * be returned.
+ *
+ * @return the userID of the user from which the offer originates.
+ */
+ public String getUserID() {
+ return userID;
+ }
+
+ /**
+ * Returns the JID of the user that made the offer request.
+ *
+ * @return the user's JID.
+ */
+ public String getUserJID() {
+ return userJID;
+ }
+
+ /**
+ * The fully qualified name of the workgroup (eg support@example.com).
+ *
+ * @return the name of the workgroup.
+ */
+ public String getWorkgroupName() {
+ return this.workgroupName;
+ }
+
+ /**
+ * The date when the offer will expire. The agent must {@link #accept()}
+ * the offer before the expiration date or the offer will lapse and be
+ * routed to another agent. Alternatively, the agent can {@link #reject()}
+ * the offer at any time if they don't wish to accept it..
+ *
+ * @return the date at which this offer expires.
+ */
+ public Date getExpiresDate() {
+ return this.expiresDate;
+ }
+
+ /**
+ * The session ID associated with the offer.
+ *
+ * @return the session id associated with the offer.
+ */
+ public String getSessionID() {
+ return this.sessionID;
+ }
+
+ /**
+ * The meta-data associated with the offer.
+ *
+ * @return the offer meta-data.
+ */
+ public Map<String, List<String>> getMetaData() {
+ return this.metaData;
+ }
+
+ /**
+ * Returns the content of the offer. The content explains the reason for the offer
+ * (e.g. user request, transfer)
+ *
+ * @return the content of the offer.
+ */
+ public OfferContent getContent() {
+ return content;
+ }
+
+ /**
+ * Returns true if the agent accepted this offer.
+ *
+ * @return true if the agent accepted this offer.
+ */
+ public boolean isAccepted() {
+ return accepted;
+ }
+
+ /**
+ * Return true if the agent rejected this offer.
+ *
+ * @return true if the agent rejected this offer.
+ */
+ public boolean isRejected() {
+ return rejected;
+ }
+
+ /**
+ * Packet for rejecting offers.
+ */
+ private class RejectPacket extends IQ {
+
+ RejectPacket(String workgroup) {
+ this.setTo(workgroup);
+ this.setType(IQ.Type.SET);
+ }
+
+ public String getChildElementXML() {
+ return "<offer-reject id=\"" + Offer.this.getSessionID() +
+ "\" xmlns=\"http://jabber.org/protocol/workgroup" + "\"/>";
+ }
+ }
+
+ /**
+ * Packet for accepting an offer.
+ */
+ private class AcceptPacket extends IQ {
+
+ AcceptPacket(String workgroup) {
+ this.setTo(workgroup);
+ this.setType(IQ.Type.SET);
+ }
+
+ public String getChildElementXML() {
+ return "<offer-accept id=\"" + Offer.this.getSessionID() +
+ "\" xmlns=\"http://jabber.org/protocol/workgroup" + "\"/>";
+ }
+ }
+
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmation.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmation.java
index f55d5881a..ea1eba72d 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmation.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmation.java
@@ -1,114 +1,114 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-
-public class OfferConfirmation extends IQ {
- private String userJID;
- private long sessionID;
-
- public String getUserJID() {
- return userJID;
- }
-
- public void setUserJID(String userJID) {
- this.userJID = userJID;
- }
-
- public long getSessionID() {
- return sessionID;
- }
-
- public void setSessionID(long sessionID) {
- this.sessionID = sessionID;
- }
-
-
- public void notifyService(Connection con, String workgroup, String createdRoomName) {
- NotifyServicePacket packet = new NotifyServicePacket(workgroup, createdRoomName);
- con.sendPacket(packet);
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<offer-confirmation xmlns=\"http://jabber.org/protocol/workgroup\">");
- buf.append("</offer-confirmation>");
- return buf.toString();
- }
-
- public static class Provider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- final OfferConfirmation confirmation = new OfferConfirmation();
-
- boolean done = false;
- while (!done) {
- parser.next();
- String elementName = parser.getName();
- if (parser.getEventType() == XmlPullParser.START_TAG && "user-jid".equals(elementName)) {
- try {
- confirmation.setUserJID(parser.nextText());
- }
- catch (NumberFormatException nfe) {
- }
- }
- else if (parser.getEventType() == XmlPullParser.START_TAG && "session-id".equals(elementName)) {
- try {
- confirmation.setSessionID(Long.valueOf(parser.nextText()));
- }
- catch (NumberFormatException nfe) {
- }
- }
- else if (parser.getEventType() == XmlPullParser.END_TAG && "offer-confirmation".equals(elementName)) {
- done = true;
- }
- }
-
-
- return confirmation;
- }
- }
-
-
- /**
- * Packet for notifying server of RoomName
- */
- private class NotifyServicePacket extends IQ {
- String roomName;
-
- NotifyServicePacket(String workgroup, String roomName) {
- this.setTo(workgroup);
- this.setType(IQ.Type.RESULT);
-
- this.roomName = roomName;
- }
-
- public String getChildElementXML() {
- return "<offer-confirmation roomname=\"" + roomName + "\" xmlns=\"http://jabber.org/protocol/workgroup" + "\"/>";
- }
- }
-
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+
+public class OfferConfirmation extends IQ {
+ private String userJID;
+ private long sessionID;
+
+ public String getUserJID() {
+ return userJID;
+ }
+
+ public void setUserJID(String userJID) {
+ this.userJID = userJID;
+ }
+
+ public long getSessionID() {
+ return sessionID;
+ }
+
+ public void setSessionID(long sessionID) {
+ this.sessionID = sessionID;
+ }
+
+
+ public void notifyService(Connection con, String workgroup, String createdRoomName) {
+ NotifyServicePacket packet = new NotifyServicePacket(workgroup, createdRoomName);
+ con.sendPacket(packet);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<offer-confirmation xmlns=\"http://jabber.org/protocol/workgroup\">");
+ buf.append("</offer-confirmation>");
+ return buf.toString();
+ }
+
+ public static class Provider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ final OfferConfirmation confirmation = new OfferConfirmation();
+
+ boolean done = false;
+ while (!done) {
+ parser.next();
+ String elementName = parser.getName();
+ if (parser.getEventType() == XmlPullParser.START_TAG && "user-jid".equals(elementName)) {
+ try {
+ confirmation.setUserJID(parser.nextText());
+ }
+ catch (NumberFormatException nfe) {
+ }
+ }
+ else if (parser.getEventType() == XmlPullParser.START_TAG && "session-id".equals(elementName)) {
+ try {
+ confirmation.setSessionID(Long.valueOf(parser.nextText()));
+ }
+ catch (NumberFormatException nfe) {
+ }
+ }
+ else if (parser.getEventType() == XmlPullParser.END_TAG && "offer-confirmation".equals(elementName)) {
+ done = true;
+ }
+ }
+
+
+ return confirmation;
+ }
+ }
+
+
+ /**
+ * Packet for notifying server of RoomName
+ */
+ private class NotifyServicePacket extends IQ {
+ String roomName;
+
+ NotifyServicePacket(String workgroup, String roomName) {
+ this.setTo(workgroup);
+ this.setType(IQ.Type.RESULT);
+
+ this.roomName = roomName;
+ }
+
+ public String getChildElementXML() {
+ return "<offer-confirmation roomname=\"" + roomName + "\" xmlns=\"http://jabber.org/protocol/workgroup" + "\"/>";
+ }
+ }
+
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmationListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmationListener.java
index fb10550cf..ec079e4ae 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmationListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferConfirmationListener.java
@@ -1,32 +1,32 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-public interface OfferConfirmationListener {
-
-
- /**
- * The implementing class instance will be notified via this when the AgentSession has confirmed
- * the acceptance of the <code>Offer</code>. The instance will then have the ability to create the room and
- * send the service the room name created for tracking.
- *
- * @param confirmedOffer the ConfirmedOffer
- */
- void offerConfirmed(OfferConfirmation confirmedOffer);
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+public interface OfferConfirmationListener {
+
+
+ /**
+ * The implementing class instance will be notified via this when the AgentSession has confirmed
+ * the acceptance of the <code>Offer</code>. The instance will then have the ability to create the room and
+ * send the service the room name created for tracking.
+ *
+ * @param confirmedOffer the ConfirmedOffer
+ */
+ void offerConfirmed(OfferConfirmation confirmedOffer);
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferContent.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferContent.java
index a11ddc3d8..f6d60ae88 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferContent.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferContent.java
@@ -1,55 +1,55 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-/**
- * Type of content being included in the offer. The content actually explains the reason
- * the agent is getting an offer.
- *
- * @author Gaston Dombiak
- */
-public abstract class OfferContent {
-
- /**
- * Returns true if the content of the offer is related to a user request. This is the
- * most common type of offers an agent should receive.
- *
- * @return true if the content of the offer is related to a user request.
- */
- abstract boolean isUserRequest();
-
- /**
- * Returns true if the content of the offer is related to a room invitation made by another
- * agent. This type of offer include the room to join, metadata sent by the user while joining
- * the queue and the reason why the agent is being invited.
- *
- * @return true if the content of the offer is related to a room invitation made by another agent.
- */
- abstract boolean isInvitation();
-
- /**
- * Returns true if the content of the offer is related to a service transfer made by another
- * agent. This type of offers include the room to join, metadata sent by the user while joining the
- * queue and the reason why the agent is receiving the transfer offer.
- *
- * @return true if the content of the offer is related to a service transfer made by another agent.
- */
- abstract boolean isTransfer();
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+/**
+ * Type of content being included in the offer. The content actually explains the reason
+ * the agent is getting an offer.
+ *
+ * @author Gaston Dombiak
+ */
+public abstract class OfferContent {
+
+ /**
+ * Returns true if the content of the offer is related to a user request. This is the
+ * most common type of offers an agent should receive.
+ *
+ * @return true if the content of the offer is related to a user request.
+ */
+ abstract boolean isUserRequest();
+
+ /**
+ * Returns true if the content of the offer is related to a room invitation made by another
+ * agent. This type of offer include the room to join, metadata sent by the user while joining
+ * the queue and the reason why the agent is being invited.
+ *
+ * @return true if the content of the offer is related to a room invitation made by another agent.
+ */
+ abstract boolean isInvitation();
+
+ /**
+ * Returns true if the content of the offer is related to a service transfer made by another
+ * agent. This type of offers include the room to join, metadata sent by the user while joining the
+ * queue and the reason why the agent is receiving the transfer offer.
+ *
+ * @return true if the content of the offer is related to a service transfer made by another agent.
+ */
+ abstract boolean isTransfer();
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferListener.java
index 5efde9919..72e50e378 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/OfferListener.java
@@ -1,49 +1,49 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-/**
- * An interface which all classes interested in hearing about chat offers associated to a particular
- * AgentSession instance should implement.<br>
- *
- * @author Matt Tucker
- * @author loki der quaeler
- * @see org.jivesoftware.smackx.workgroup.agent.AgentSession
- */
-public interface OfferListener {
-
- /**
- * The implementing class instance will be notified via this when the AgentSession has received
- * an offer for a chat. The instance will then have the ability to accept, reject, or ignore
- * the request (resulting in a revocation-by-timeout).
- *
- * @param request the Offer instance embodying the details of the offer
- */
- public void offerReceived (Offer request);
-
- /**
- * The implementing class instance will be notified via this when the AgentSessino has received
- * a revocation of a previously extended offer.
- *
- * @param revokedOffer the RevokedOffer instance embodying the details of the revoked offer
- */
- public void offerRevoked (RevokedOffer revokedOffer);
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+/**
+ * An interface which all classes interested in hearing about chat offers associated to a particular
+ * AgentSession instance should implement.<br>
+ *
+ * @author Matt Tucker
+ * @author loki der quaeler
+ * @see org.jivesoftware.smackx.workgroup.agent.AgentSession
+ */
+public interface OfferListener {
+
+ /**
+ * The implementing class instance will be notified via this when the AgentSession has received
+ * an offer for a chat. The instance will then have the ability to accept, reject, or ignore
+ * the request (resulting in a revocation-by-timeout).
+ *
+ * @param request the Offer instance embodying the details of the offer
+ */
+ public void offerReceived (Offer request);
+
+ /**
+ * The implementing class instance will be notified via this when the AgentSessino has received
+ * a revocation of a previously extended offer.
+ *
+ * @param revokedOffer the RevokedOffer instance embodying the details of the revoked offer
+ */
+ public void offerRevoked (RevokedOffer revokedOffer);
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/QueueUsersListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/QueueUsersListener.java
index 9fcff9a7b..e7510d628 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/QueueUsersListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/QueueUsersListener.java
@@ -1,60 +1,60 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import java.util.Date;
-import java.util.Set;
-
-import org.jivesoftware.smackx.workgroup.QueueUser;
-
-public interface QueueUsersListener {
-
- /**
- * The status of the queue was updated.
- *
- * @param queue the workgroup queue.
- * @param status the status of queue.
- */
- public void statusUpdated(WorkgroupQueue queue, WorkgroupQueue.Status status);
-
- /**
- * The average wait time of the queue was updated.
- *
- * @param queue the workgroup queue.
- * @param averageWaitTime the average wait time of the queue.
- */
- public void averageWaitTimeUpdated(WorkgroupQueue queue, int averageWaitTime);
-
- /**
- * The date of oldest entry waiting in the queue was updated.
- *
- * @param queue the workgroup queue.
- * @param oldestEntry the date of the oldest entry waiting in the queue.
- */
- public void oldestEntryUpdated(WorkgroupQueue queue, Date oldestEntry);
-
- /**
- * The list of users waiting in the queue was updated.
- *
- * @param queue the workgroup queue.
- * @param users the list of users waiting in the queue.
- */
- public void usersUpdated(WorkgroupQueue queue, Set<QueueUser> users);
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import java.util.Date;
+import java.util.Set;
+
+import org.jivesoftware.smackx.workgroup.QueueUser;
+
+public interface QueueUsersListener {
+
+ /**
+ * The status of the queue was updated.
+ *
+ * @param queue the workgroup queue.
+ * @param status the status of queue.
+ */
+ public void statusUpdated(WorkgroupQueue queue, WorkgroupQueue.Status status);
+
+ /**
+ * The average wait time of the queue was updated.
+ *
+ * @param queue the workgroup queue.
+ * @param averageWaitTime the average wait time of the queue.
+ */
+ public void averageWaitTimeUpdated(WorkgroupQueue queue, int averageWaitTime);
+
+ /**
+ * The date of oldest entry waiting in the queue was updated.
+ *
+ * @param queue the workgroup queue.
+ * @param oldestEntry the date of the oldest entry waiting in the queue.
+ */
+ public void oldestEntryUpdated(WorkgroupQueue queue, Date oldestEntry);
+
+ /**
+ * The list of users waiting in the queue was updated.
+ *
+ * @param queue the workgroup queue.
+ * @param users the list of users waiting in the queue.
+ */
+ public void usersUpdated(WorkgroupQueue queue, Set<QueueUser> users);
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/RevokedOffer.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/RevokedOffer.java
index dab4d912f..88250b2aa 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/RevokedOffer.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/RevokedOffer.java
@@ -1,98 +1,98 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import java.util.Date;
-
-/**
- * An immutable simple class to embody the information concerning a revoked offer, this is namely
- * the reason, the workgroup, the userJID, and the timestamp which the message was received.<br>
- *
- * @author loki der quaeler
- */
-public class RevokedOffer {
-
- private String userJID;
- private String userID;
- private String workgroupName;
- private String sessionID;
- private String reason;
- private Date timestamp;
-
- /**
- *
- * @param userJID the JID of the user for which this revocation was issued.
- * @param userID the user ID of the user for which this revocation was issued.
- * @param workgroupName the fully qualified name of the workgroup
- * @param sessionID the session id attributed to this chain of packets
- * @param reason the server issued message as to why this revocation was issued.
- * @param timestamp the timestamp at which the revocation was issued
- */
- RevokedOffer(String userJID, String userID, String workgroupName, String sessionID,
- String reason, Date timestamp) {
- super();
-
- this.userJID = userJID;
- this.userID = userID;
- this.workgroupName = workgroupName;
- this.sessionID = sessionID;
- this.reason = reason;
- this.timestamp = timestamp;
- }
-
- public String getUserJID() {
- return userJID;
- }
-
- /**
- * @return the jid of the user for which this revocation was issued
- */
- public String getUserID() {
- return this.userID;
- }
-
- /**
- * @return the fully qualified name of the workgroup
- */
- public String getWorkgroupName() {
- return this.workgroupName;
- }
-
- /**
- * @return the session id which will associate all packets for the pending chat
- */
- public String getSessionID() {
- return this.sessionID;
- }
-
- /**
- * @return the server issued message as to why this revocation was issued
- */
- public String getReason() {
- return this.reason;
- }
-
- /**
- * @return the timestamp at which the revocation was issued
- */
- public Date getTimestamp() {
- return this.timestamp;
- }
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import java.util.Date;
+
+/**
+ * An immutable simple class to embody the information concerning a revoked offer, this is namely
+ * the reason, the workgroup, the userJID, and the timestamp which the message was received.<br>
+ *
+ * @author loki der quaeler
+ */
+public class RevokedOffer {
+
+ private String userJID;
+ private String userID;
+ private String workgroupName;
+ private String sessionID;
+ private String reason;
+ private Date timestamp;
+
+ /**
+ *
+ * @param userJID the JID of the user for which this revocation was issued.
+ * @param userID the user ID of the user for which this revocation was issued.
+ * @param workgroupName the fully qualified name of the workgroup
+ * @param sessionID the session id attributed to this chain of packets
+ * @param reason the server issued message as to why this revocation was issued.
+ * @param timestamp the timestamp at which the revocation was issued
+ */
+ RevokedOffer(String userJID, String userID, String workgroupName, String sessionID,
+ String reason, Date timestamp) {
+ super();
+
+ this.userJID = userJID;
+ this.userID = userID;
+ this.workgroupName = workgroupName;
+ this.sessionID = sessionID;
+ this.reason = reason;
+ this.timestamp = timestamp;
+ }
+
+ public String getUserJID() {
+ return userJID;
+ }
+
+ /**
+ * @return the jid of the user for which this revocation was issued
+ */
+ public String getUserID() {
+ return this.userID;
+ }
+
+ /**
+ * @return the fully qualified name of the workgroup
+ */
+ public String getWorkgroupName() {
+ return this.workgroupName;
+ }
+
+ /**
+ * @return the session id which will associate all packets for the pending chat
+ */
+ public String getSessionID() {
+ return this.sessionID;
+ }
+
+ /**
+ * @return the server issued message as to why this revocation was issued
+ */
+ public String getReason() {
+ return this.reason;
+ }
+
+ /**
+ * @return the timestamp at which the revocation was issued
+ */
+ public Date getTimestamp() {
+ return this.timestamp;
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptManager.java
index 8a3801fcf..2a17b471e 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptManager.java
@@ -1,100 +1,100 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import org.jivesoftware.smackx.workgroup.packet.Transcript;
-import org.jivesoftware.smackx.workgroup.packet.Transcripts;
-import org.jivesoftware.smack.PacketCollector;
-import org.jivesoftware.smack.SmackConfiguration;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.PacketIDFilter;
-
-/**
- * A TranscriptManager helps to retrieve the full conversation transcript of a given session
- * {@link #getTranscript(String, String)} or to retrieve a list with the summary of all the
- * conversations that a user had {@link #getTranscripts(String, String)}.
- *
- * @author Gaston Dombiak
- */
-public class TranscriptManager {
- private Connection connection;
-
- public TranscriptManager(Connection connection) {
- this.connection = connection;
- }
-
- /**
- * Returns the full conversation transcript of a given session.
- *
- * @param sessionID the id of the session to get the full transcript.
- * @param workgroupJID the JID of the workgroup that will process the request.
- * @return the full conversation transcript of a given session.
- * @throws XMPPException if an error occurs while getting the information.
- */
- public Transcript getTranscript(String workgroupJID, String sessionID) throws XMPPException {
- Transcript request = new Transcript(sessionID);
- request.setTo(workgroupJID);
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- // Send the request
- connection.sendPacket(request);
-
- Transcript response = (Transcript) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * Returns the transcripts of a given user. The answer will contain the complete history of
- * conversations that a user had.
- *
- * @param userID the id of the user to get his conversations.
- * @param workgroupJID the JID of the workgroup that will process the request.
- * @return the transcripts of a given user.
- * @throws XMPPException if an error occurs while getting the information.
- */
- public Transcripts getTranscripts(String workgroupJID, String userID) throws XMPPException {
- Transcripts request = new Transcripts(userID);
- request.setTo(workgroupJID);
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- // Send the request
- connection.sendPacket(request);
-
- Transcripts response = (Transcripts) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import org.jivesoftware.smackx.workgroup.packet.Transcript;
+import org.jivesoftware.smackx.workgroup.packet.Transcripts;
+import org.jivesoftware.smack.PacketCollector;
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketIDFilter;
+
+/**
+ * A TranscriptManager helps to retrieve the full conversation transcript of a given session
+ * {@link #getTranscript(String, String)} or to retrieve a list with the summary of all the
+ * conversations that a user had {@link #getTranscripts(String, String)}.
+ *
+ * @author Gaston Dombiak
+ */
+public class TranscriptManager {
+ private Connection connection;
+
+ public TranscriptManager(Connection connection) {
+ this.connection = connection;
+ }
+
+ /**
+ * Returns the full conversation transcript of a given session.
+ *
+ * @param sessionID the id of the session to get the full transcript.
+ * @param workgroupJID the JID of the workgroup that will process the request.
+ * @return the full conversation transcript of a given session.
+ * @throws XMPPException if an error occurs while getting the information.
+ */
+ public Transcript getTranscript(String workgroupJID, String sessionID) throws XMPPException {
+ Transcript request = new Transcript(sessionID);
+ request.setTo(workgroupJID);
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ // Send the request
+ connection.sendPacket(request);
+
+ Transcript response = (Transcript) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * Returns the transcripts of a given user. The answer will contain the complete history of
+ * conversations that a user had.
+ *
+ * @param userID the id of the user to get his conversations.
+ * @param workgroupJID the JID of the workgroup that will process the request.
+ * @return the transcripts of a given user.
+ * @throws XMPPException if an error occurs while getting the information.
+ */
+ public Transcripts getTranscripts(String workgroupJID, String userID) throws XMPPException {
+ Transcripts request = new Transcripts(userID);
+ request.setTo(workgroupJID);
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ // Send the request
+ connection.sendPacket(request);
+
+ Transcripts response = (Transcripts) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptSearchManager.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptSearchManager.java
index 8260cd6b1..498cc8abb 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptSearchManager.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TranscriptSearchManager.java
@@ -1,111 +1,111 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import org.jivesoftware.smackx.workgroup.packet.TranscriptSearch;
-import org.jivesoftware.smack.PacketCollector;
-import org.jivesoftware.smack.SmackConfiguration;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.filter.PacketIDFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.ReportedData;
-
-/**
- * A TranscriptSearchManager helps to retrieve the form to use for searching transcripts
- * {@link #getSearchForm(String)} or to submit a search form and return the results of
- * the search {@link #submitSearch(String, Form)}.
- *
- * @author Gaston Dombiak
- */
-public class TranscriptSearchManager {
- private Connection connection;
-
- public TranscriptSearchManager(Connection connection) {
- this.connection = connection;
- }
-
- /**
- * Returns the Form to use for searching transcripts. It is unlikely that the server
- * will change the form (without a restart) so it is safe to keep the returned form
- * for future submissions.
- *
- * @param serviceJID the address of the workgroup service.
- * @return the Form to use for searching transcripts.
- * @throws XMPPException if an error occurs while sending the request to the server.
- */
- public Form getSearchForm(String serviceJID) throws XMPPException {
- TranscriptSearch search = new TranscriptSearch();
- search.setType(IQ.Type.GET);
- search.setTo(serviceJID);
-
- PacketCollector collector = connection.createPacketCollector(
- new PacketIDFilter(search.getPacketID()));
- connection.sendPacket(search);
-
- TranscriptSearch response = (TranscriptSearch) collector.nextResult(
- SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return Form.getFormFrom(response);
- }
-
- /**
- * Submits the completed form and returns the result of the transcript search. The result
- * will include all the data returned from the server so be careful with the amount of
- * data that the search may return.
- *
- * @param serviceJID the address of the workgroup service.
- * @param completedForm the filled out search form.
- * @return the result of the transcript search.
- * @throws XMPPException if an error occurs while submiting the search to the server.
- */
- public ReportedData submitSearch(String serviceJID, Form completedForm) throws XMPPException {
- TranscriptSearch search = new TranscriptSearch();
- search.setType(IQ.Type.GET);
- search.setTo(serviceJID);
- search.addExtension(completedForm.getDataFormToSend());
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(search.getPacketID()));
- connection.sendPacket(search);
-
- TranscriptSearch response = (TranscriptSearch) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return ReportedData.getReportedDataFrom(response);
- }
-}
-
-
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import org.jivesoftware.smackx.workgroup.packet.TranscriptSearch;
+import org.jivesoftware.smack.PacketCollector;
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketIDFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.ReportedData;
+
+/**
+ * A TranscriptSearchManager helps to retrieve the form to use for searching transcripts
+ * {@link #getSearchForm(String)} or to submit a search form and return the results of
+ * the search {@link #submitSearch(String, Form)}.
+ *
+ * @author Gaston Dombiak
+ */
+public class TranscriptSearchManager {
+ private Connection connection;
+
+ public TranscriptSearchManager(Connection connection) {
+ this.connection = connection;
+ }
+
+ /**
+ * Returns the Form to use for searching transcripts. It is unlikely that the server
+ * will change the form (without a restart) so it is safe to keep the returned form
+ * for future submissions.
+ *
+ * @param serviceJID the address of the workgroup service.
+ * @return the Form to use for searching transcripts.
+ * @throws XMPPException if an error occurs while sending the request to the server.
+ */
+ public Form getSearchForm(String serviceJID) throws XMPPException {
+ TranscriptSearch search = new TranscriptSearch();
+ search.setType(IQ.Type.GET);
+ search.setTo(serviceJID);
+
+ PacketCollector collector = connection.createPacketCollector(
+ new PacketIDFilter(search.getPacketID()));
+ connection.sendPacket(search);
+
+ TranscriptSearch response = (TranscriptSearch) collector.nextResult(
+ SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return Form.getFormFrom(response);
+ }
+
+ /**
+ * Submits the completed form and returns the result of the transcript search. The result
+ * will include all the data returned from the server so be careful with the amount of
+ * data that the search may return.
+ *
+ * @param serviceJID the address of the workgroup service.
+ * @param completedForm the filled out search form.
+ * @return the result of the transcript search.
+ * @throws XMPPException if an error occurs while submiting the search to the server.
+ */
+ public ReportedData submitSearch(String serviceJID, Form completedForm) throws XMPPException {
+ TranscriptSearch search = new TranscriptSearch();
+ search.setType(IQ.Type.GET);
+ search.setTo(serviceJID);
+ search.addExtension(completedForm.getDataFormToSend());
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(search.getPacketID()));
+ connection.sendPacket(search);
+
+ TranscriptSearch response = (TranscriptSearch) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return ReportedData.getReportedDataFrom(response);
+ }
+}
+
+
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TransferRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TransferRequest.java
index a3abbaa38..0d0f87e12 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TransferRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/TransferRequest.java
@@ -1,62 +1,62 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-/**
- * Request sent by an agent to transfer a support session to another agent or user.
- *
- * @author Gaston Dombiak
- */
-public class TransferRequest extends OfferContent {
-
- private String inviter;
- private String room;
- private String reason;
-
- public TransferRequest(String inviter, String room, String reason) {
- this.inviter = inviter;
- this.room = room;
- this.reason = reason;
- }
-
- public String getInviter() {
- return inviter;
- }
-
- public String getRoom() {
- return room;
- }
-
- public String getReason() {
- return reason;
- }
-
- boolean isUserRequest() {
- return false;
- }
-
- boolean isInvitation() {
- return false;
- }
-
- boolean isTransfer() {
- return true;
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+/**
+ * Request sent by an agent to transfer a support session to another agent or user.
+ *
+ * @author Gaston Dombiak
+ */
+public class TransferRequest extends OfferContent {
+
+ private String inviter;
+ private String room;
+ private String reason;
+
+ public TransferRequest(String inviter, String room, String reason) {
+ this.inviter = inviter;
+ this.room = room;
+ this.reason = reason;
+ }
+
+ public String getInviter() {
+ return inviter;
+ }
+
+ public String getRoom() {
+ return room;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ boolean isUserRequest() {
+ return false;
+ }
+
+ boolean isInvitation() {
+ return false;
+ }
+
+ boolean isTransfer() {
+ return true;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/UserRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/UserRequest.java
index ccaaaf37a..f24208daa 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/UserRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/UserRequest.java
@@ -1,47 +1,47 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-/**
- * Requests made by users to get support by some agent.
- *
- * @author Gaston Dombiak
- */
-public class UserRequest extends OfferContent {
- // TODO Do we want to use a singleton? Should we store the userID here?
- private static UserRequest instance = new UserRequest();
-
- public static OfferContent getInstance() {
- return instance;
- }
-
- boolean isUserRequest() {
- return true;
- }
-
- boolean isInvitation() {
- return false;
- }
-
- boolean isTransfer() {
- return false;
- }
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+/**
+ * Requests made by users to get support by some agent.
+ *
+ * @author Gaston Dombiak
+ */
+public class UserRequest extends OfferContent {
+ // TODO Do we want to use a singleton? Should we store the userID here?
+ private static UserRequest instance = new UserRequest();
+
+ public static OfferContent getInstance() {
+ return instance;
+ }
+
+ boolean isUserRequest() {
+ return true;
+ }
+
+ boolean isInvitation() {
+ return false;
+ }
+
+ boolean isTransfer() {
+ return false;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/WorkgroupQueue.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/WorkgroupQueue.java
index b43c82608..b0d07a645 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/WorkgroupQueue.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/agent/WorkgroupQueue.java
@@ -1,224 +1,224 @@
-/**
- * $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
- *
- * 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.workgroup.agent;
-
-import java.util.*;
-
-import org.jivesoftware.smackx.workgroup.QueueUser;
-
-/**
- * A queue in a workgroup, which is a pool of agents that are routed a specific type of
- * chat request.
- */
-public class WorkgroupQueue {
-
- private String name;
- private Status status = Status.CLOSED;
-
- private int averageWaitTime = -1;
- private Date oldestEntry = null;
- private Set<QueueUser> users = Collections.emptySet();
-
- private int maxChats = 0;
- private int currentChats = 0;
-
- /**
- * Creates a new workgroup queue instance.
- *
- * @param name the name of the queue.
- */
- WorkgroupQueue(String name) {
- this.name = name;
- }
-
- /**
- * Returns the name of the queue.
- *
- * @return the name of the queue.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the status of the queue.
- *
- * @return the status of the queue.
- */
- public Status getStatus() {
- return status;
- }
-
- void setStatus(Status status) {
- this.status = status;
- }
-
- /**
- * Returns the number of users waiting in the queue waiting to be routed to
- * an agent.
- *
- * @return the number of users waiting in the queue.
- */
- public int getUserCount() {
- if (users == null) {
- return 0;
- }
- return users.size();
- }
-
- /**
- * Returns an Iterator for the users in the queue waiting to be routed to
- * an agent (QueueUser instances).
- *
- * @return an Iterator for the users waiting in the queue.
- */
- public Iterator<QueueUser> getUsers() {
- if (users == null) {
- return new HashSet<QueueUser>().iterator();
- }
- return Collections.unmodifiableSet(users).iterator();
- }
-
- void setUsers(Set<QueueUser> users) {
- this.users = users;
- }
-
- /**
- * Returns the average amount of time users wait in the queue before being
- * routed to an agent. If average wait time info isn't available, -1 will
- * be returned.
- *
- * @return the average wait time
- */
- public int getAverageWaitTime() {
- return averageWaitTime;
- }
-
- void setAverageWaitTime(int averageTime) {
- this.averageWaitTime = averageTime;
- }
-
- /**
- * Returns the date of the oldest request waiting in the queue. If there
- * are no requests waiting to be routed, this method will return <tt>null</tt>.
- *
- * @return the date of the oldest request in the queue.
- */
- public Date getOldestEntry() {
- return oldestEntry;
- }
-
- void setOldestEntry(Date oldestEntry) {
- this.oldestEntry = oldestEntry;
- }
-
- /**
- * Returns the maximum number of simultaneous chats the queue can handle.
- *
- * @return the max number of chats the queue can handle.
- */
- public int getMaxChats() {
- return maxChats;
- }
-
- void setMaxChats(int maxChats) {
- this.maxChats = maxChats;
- }
-
- /**
- * Returns the current number of active chat sessions in the queue.
- *
- * @return the current number of active chat sessions in the queue.
- */
- public int getCurrentChats() {
- return currentChats;
- }
-
- void setCurrentChats(int currentChats) {
- this.currentChats = currentChats;
- }
-
- /**
- * A class to represent the status of the workgroup. The possible values are:
- *
- * <ul>
- * <li>WorkgroupQueue.Status.OPEN -- the queue is active and accepting new chat requests.
- * <li>WorkgroupQueue.Status.ACTIVE -- the queue is active but NOT accepting new chat
- * requests.
- * <li>WorkgroupQueue.Status.CLOSED -- the queue is NOT active and NOT accepting new
- * chat requests.
- * </ul>
- */
- public static class Status {
-
- /**
- * The queue is active and accepting new chat requests.
- */
- public static final Status OPEN = new Status("open");
-
- /**
- * The queue is active but NOT accepting new chat requests. This state might
- * occur when the workgroup has closed because regular support hours have closed,
- * but there are still several requests left in the queue.
- */
- public static final Status ACTIVE = new Status("active");
-
- /**
- * The queue is NOT active and NOT accepting new chat requests.
- */
- public static final Status CLOSED = new Status("closed");
-
- /**
- * Converts a String into the corresponding status. Valid String values
- * that can be converted to a status are: "open", "active", and "closed".
- *
- * @param type the String value to covert.
- * @return the corresponding Type.
- */
- public static Status fromString(String type) {
- if (type == null) {
- return null;
- }
- type = type.toLowerCase();
- if (OPEN.toString().equals(type)) {
- return OPEN;
- }
- else if (ACTIVE.toString().equals(type)) {
- return ACTIVE;
- }
- else if (CLOSED.toString().equals(type)) {
- return CLOSED;
- }
- else {
- return null;
- }
- }
-
- private String value;
-
- private Status(String value) {
- this.value = value;
- }
-
- public String toString() {
- return value;
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.agent;
+
+import java.util.*;
+
+import org.jivesoftware.smackx.workgroup.QueueUser;
+
+/**
+ * A queue in a workgroup, which is a pool of agents that are routed a specific type of
+ * chat request.
+ */
+public class WorkgroupQueue {
+
+ private String name;
+ private Status status = Status.CLOSED;
+
+ private int averageWaitTime = -1;
+ private Date oldestEntry = null;
+ private Set<QueueUser> users = Collections.emptySet();
+
+ private int maxChats = 0;
+ private int currentChats = 0;
+
+ /**
+ * Creates a new workgroup queue instance.
+ *
+ * @param name the name of the queue.
+ */
+ WorkgroupQueue(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of the queue.
+ *
+ * @return the name of the queue.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the status of the queue.
+ *
+ * @return the status of the queue.
+ */
+ public Status getStatus() {
+ return status;
+ }
+
+ void setStatus(Status status) {
+ this.status = status;
+ }
+
+ /**
+ * Returns the number of users waiting in the queue waiting to be routed to
+ * an agent.
+ *
+ * @return the number of users waiting in the queue.
+ */
+ public int getUserCount() {
+ if (users == null) {
+ return 0;
+ }
+ return users.size();
+ }
+
+ /**
+ * Returns an Iterator for the users in the queue waiting to be routed to
+ * an agent (QueueUser instances).
+ *
+ * @return an Iterator for the users waiting in the queue.
+ */
+ public Iterator<QueueUser> getUsers() {
+ if (users == null) {
+ return new HashSet<QueueUser>().iterator();
+ }
+ return Collections.unmodifiableSet(users).iterator();
+ }
+
+ void setUsers(Set<QueueUser> users) {
+ this.users = users;
+ }
+
+ /**
+ * Returns the average amount of time users wait in the queue before being
+ * routed to an agent. If average wait time info isn't available, -1 will
+ * be returned.
+ *
+ * @return the average wait time
+ */
+ public int getAverageWaitTime() {
+ return averageWaitTime;
+ }
+
+ void setAverageWaitTime(int averageTime) {
+ this.averageWaitTime = averageTime;
+ }
+
+ /**
+ * Returns the date of the oldest request waiting in the queue. If there
+ * are no requests waiting to be routed, this method will return <tt>null</tt>.
+ *
+ * @return the date of the oldest request in the queue.
+ */
+ public Date getOldestEntry() {
+ return oldestEntry;
+ }
+
+ void setOldestEntry(Date oldestEntry) {
+ this.oldestEntry = oldestEntry;
+ }
+
+ /**
+ * Returns the maximum number of simultaneous chats the queue can handle.
+ *
+ * @return the max number of chats the queue can handle.
+ */
+ public int getMaxChats() {
+ return maxChats;
+ }
+
+ void setMaxChats(int maxChats) {
+ this.maxChats = maxChats;
+ }
+
+ /**
+ * Returns the current number of active chat sessions in the queue.
+ *
+ * @return the current number of active chat sessions in the queue.
+ */
+ public int getCurrentChats() {
+ return currentChats;
+ }
+
+ void setCurrentChats(int currentChats) {
+ this.currentChats = currentChats;
+ }
+
+ /**
+ * A class to represent the status of the workgroup. The possible values are:
+ *
+ * <ul>
+ * <li>WorkgroupQueue.Status.OPEN -- the queue is active and accepting new chat requests.
+ * <li>WorkgroupQueue.Status.ACTIVE -- the queue is active but NOT accepting new chat
+ * requests.
+ * <li>WorkgroupQueue.Status.CLOSED -- the queue is NOT active and NOT accepting new
+ * chat requests.
+ * </ul>
+ */
+ public static class Status {
+
+ /**
+ * The queue is active and accepting new chat requests.
+ */
+ public static final Status OPEN = new Status("open");
+
+ /**
+ * The queue is active but NOT accepting new chat requests. This state might
+ * occur when the workgroup has closed because regular support hours have closed,
+ * but there are still several requests left in the queue.
+ */
+ public static final Status ACTIVE = new Status("active");
+
+ /**
+ * The queue is NOT active and NOT accepting new chat requests.
+ */
+ public static final Status CLOSED = new Status("closed");
+
+ /**
+ * Converts a String into the corresponding status. Valid String values
+ * that can be converted to a status are: "open", "active", and "closed".
+ *
+ * @param type the String value to covert.
+ * @return the corresponding Type.
+ */
+ public static Status fromString(String type) {
+ if (type == null) {
+ return null;
+ }
+ type = type.toLowerCase();
+ if (OPEN.toString().equals(type)) {
+ return OPEN;
+ }
+ else if (ACTIVE.toString().equals(type)) {
+ return ACTIVE;
+ }
+ else if (CLOSED.toString().equals(type)) {
+ return CLOSED;
+ }
+ else {
+ return null;
+ }
+ }
+
+ private String value;
+
+ private Status(String value) {
+ this.value = value;
+ }
+
+ public String toString() {
+ return value;
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/forms/WorkgroupForm.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/forms/WorkgroupForm.java
index f2dc08e90..8348d9713 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/forms/WorkgroupForm.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/forms/WorkgroupForm.java
@@ -1,82 +1,82 @@
-/**
- * $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
- *
- * 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.workgroup.ext.forms;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.xmlpull.v1.XmlPullParser;
-
-public class WorkgroupForm extends IQ {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "workgroup-form";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
- // Add packet extensions, if any are defined.
- buf.append(getExtensionsXML());
- buf.append("</").append(ELEMENT_NAME).append("> ");
-
- return buf.toString();
- }
-
- /**
- * An IQProvider for WebForm packets.
- *
- * @author Derek DeMoro
- */
- public static class InternalProvider implements IQProvider {
-
- public InternalProvider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- WorkgroupForm answer = new WorkgroupForm();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- // Parse the packet extension
- answer.addExtension(PacketParserUtils.parsePacketExtension(parser.getName(),
- parser.getNamespace(), parser));
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(ELEMENT_NAME)) {
- done = true;
- }
- }
- }
-
- return answer;
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.ext.forms;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.xmlpull.v1.XmlPullParser;
+
+public class WorkgroupForm extends IQ {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "workgroup-form";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+ // Add packet extensions, if any are defined.
+ buf.append(getExtensionsXML());
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * An IQProvider for WebForm packets.
+ *
+ * @author Derek DeMoro
+ */
+ public static class InternalProvider implements IQProvider {
+
+ public InternalProvider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ WorkgroupForm answer = new WorkgroupForm();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ // Parse the packet extension
+ answer.addExtension(PacketParserUtils.parsePacketExtension(parser.getName(),
+ parser.getNamespace(), parser));
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(ELEMENT_NAME)) {
+ done = true;
+ }
+ }
+ }
+
+ return answer;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java
index 7b8d200fc..fcc9de041 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatHistory.java
@@ -1,155 +1,155 @@
-/**
- * $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
- *
- * 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.workgroup.ext.history;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
-/**
- * IQ provider used to retrieve individual agent information. Each chat session can be mapped
- * to one or more jids and therefore retrievable.
- */
-public class AgentChatHistory extends IQ {
- private String agentJID;
- private int maxSessions;
- private long startDate;
-
- private List<AgentChatSession> agentChatSessions = new ArrayList<AgentChatSession>();
-
- public AgentChatHistory(String agentJID, int maxSessions, Date startDate) {
- this.agentJID = agentJID;
- this.maxSessions = maxSessions;
- this.startDate = startDate.getTime();
- }
-
- public AgentChatHistory(String agentJID, int maxSessions) {
- this.agentJID = agentJID;
- this.maxSessions = maxSessions;
- this.startDate = 0;
- }
-
- public AgentChatHistory() {
- }
-
- public void addChatSession(AgentChatSession chatSession) {
- agentChatSessions.add(chatSession);
- }
-
- public Collection<AgentChatSession> getAgentChatSessions() {
- return agentChatSessions;
- }
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "chat-sessions";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=");
- buf.append('"');
- buf.append(NAMESPACE);
- buf.append('"');
- buf.append(" agentJID=\"" + agentJID + "\"");
- buf.append(" maxSessions=\"" + maxSessions + "\"");
- buf.append(" startDate=\"" + startDate + "\"");
-
- buf.append("></").append(ELEMENT_NAME).append("> ");
- return buf.toString();
- }
-
- /**
- * Packet extension provider for AgentHistory packets.
- */
- public static class InternalProvider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- throw new IllegalStateException("Parser not in proper position, or bad XML.");
- }
-
- AgentChatHistory agentChatHistory = new AgentChatHistory();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("chat-session".equals(parser.getName()))) {
- agentChatHistory.addChatSession(parseChatSetting(parser));
-
- }
- else if (eventType == XmlPullParser.END_TAG && ELEMENT_NAME.equals(parser.getName())) {
- done = true;
- }
- }
- return agentChatHistory;
- }
-
- private AgentChatSession parseChatSetting(XmlPullParser parser) throws Exception {
-
- boolean done = false;
- Date date = null;
- long duration = 0;
- String visitorsName = null;
- String visitorsEmail = null;
- String sessionID = null;
- String question = null;
-
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("date".equals(parser.getName()))) {
- String dateStr = parser.nextText();
- long l = Long.valueOf(dateStr).longValue();
- date = new Date(l);
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("duration".equals(parser.getName()))) {
- duration = Long.valueOf(parser.nextText()).longValue();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("visitorsName".equals(parser.getName()))) {
- visitorsName = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("visitorsEmail".equals(parser.getName()))) {
- visitorsEmail = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("sessionID".equals(parser.getName()))) {
- sessionID = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("question".equals(parser.getName()))) {
- question = parser.nextText();
- }
- else if (eventType == XmlPullParser.END_TAG && "chat-session".equals(parser.getName())) {
- done = true;
- }
- }
- return new AgentChatSession(date, duration, visitorsName, visitorsEmail, sessionID, question);
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.ext.history;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * IQ provider used to retrieve individual agent information. Each chat session can be mapped
+ * to one or more jids and therefore retrievable.
+ */
+public class AgentChatHistory extends IQ {
+ private String agentJID;
+ private int maxSessions;
+ private long startDate;
+
+ private List<AgentChatSession> agentChatSessions = new ArrayList<AgentChatSession>();
+
+ public AgentChatHistory(String agentJID, int maxSessions, Date startDate) {
+ this.agentJID = agentJID;
+ this.maxSessions = maxSessions;
+ this.startDate = startDate.getTime();
+ }
+
+ public AgentChatHistory(String agentJID, int maxSessions) {
+ this.agentJID = agentJID;
+ this.maxSessions = maxSessions;
+ this.startDate = 0;
+ }
+
+ public AgentChatHistory() {
+ }
+
+ public void addChatSession(AgentChatSession chatSession) {
+ agentChatSessions.add(chatSession);
+ }
+
+ public Collection<AgentChatSession> getAgentChatSessions() {
+ return agentChatSessions;
+ }
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "chat-sessions";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=");
+ buf.append('"');
+ buf.append(NAMESPACE);
+ buf.append('"');
+ buf.append(" agentJID=\"" + agentJID + "\"");
+ buf.append(" maxSessions=\"" + maxSessions + "\"");
+ buf.append(" startDate=\"" + startDate + "\"");
+
+ buf.append("></").append(ELEMENT_NAME).append("> ");
+ return buf.toString();
+ }
+
+ /**
+ * Packet extension provider for AgentHistory packets.
+ */
+ public static class InternalProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("Parser not in proper position, or bad XML.");
+ }
+
+ AgentChatHistory agentChatHistory = new AgentChatHistory();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("chat-session".equals(parser.getName()))) {
+ agentChatHistory.addChatSession(parseChatSetting(parser));
+
+ }
+ else if (eventType == XmlPullParser.END_TAG && ELEMENT_NAME.equals(parser.getName())) {
+ done = true;
+ }
+ }
+ return agentChatHistory;
+ }
+
+ private AgentChatSession parseChatSetting(XmlPullParser parser) throws Exception {
+
+ boolean done = false;
+ Date date = null;
+ long duration = 0;
+ String visitorsName = null;
+ String visitorsEmail = null;
+ String sessionID = null;
+ String question = null;
+
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("date".equals(parser.getName()))) {
+ String dateStr = parser.nextText();
+ long l = Long.valueOf(dateStr).longValue();
+ date = new Date(l);
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("duration".equals(parser.getName()))) {
+ duration = Long.valueOf(parser.nextText()).longValue();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("visitorsName".equals(parser.getName()))) {
+ visitorsName = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("visitorsEmail".equals(parser.getName()))) {
+ visitorsEmail = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("sessionID".equals(parser.getName()))) {
+ sessionID = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("question".equals(parser.getName()))) {
+ question = parser.nextText();
+ }
+ else if (eventType == XmlPullParser.END_TAG && "chat-session".equals(parser.getName())) {
+ done = true;
+ }
+ }
+ return new AgentChatSession(date, duration, visitorsName, visitorsEmail, sessionID, question);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatSession.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatSession.java
index 5113cda1e..290a562e3 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatSession.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/AgentChatSession.java
@@ -1,93 +1,93 @@
-/**
- * $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
- *
- * 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.workgroup.ext.history;
-
-import java.util.Date;
-
-/**
- * Represents one chat session for an agent.
- */
-public class AgentChatSession {
- public Date startDate;
- public long duration;
- public String visitorsName;
- public String visitorsEmail;
- public String sessionID;
- public String question;
-
- public AgentChatSession(Date date, long duration, String visitorsName, String visitorsEmail, String sessionID, String question) {
- this.startDate = date;
- this.duration = duration;
- this.visitorsName = visitorsName;
- this.visitorsEmail = visitorsEmail;
- this.sessionID = sessionID;
- this.question = question;
- }
-
- public Date getStartDate() {
- return startDate;
- }
-
- public void setStartDate(Date startDate) {
- this.startDate = startDate;
- }
-
- public long getDuration() {
- return duration;
- }
-
- public void setDuration(long duration) {
- this.duration = duration;
- }
-
- public String getVisitorsName() {
- return visitorsName;
- }
-
- public void setVisitorsName(String visitorsName) {
- this.visitorsName = visitorsName;
- }
-
- public String getVisitorsEmail() {
- return visitorsEmail;
- }
-
- public void setVisitorsEmail(String visitorsEmail) {
- this.visitorsEmail = visitorsEmail;
- }
-
- public String getSessionID() {
- return sessionID;
- }
-
- public void setSessionID(String sessionID) {
- this.sessionID = sessionID;
- }
-
- public void setQuestion(String question){
- this.question = question;
- }
-
- public String getQuestion(){
- return question;
- }
-
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup.ext.history;
+
+import java.util.Date;
+
+/**
+ * Represents one chat session for an agent.
+ */
+public class AgentChatSession {
+ public Date startDate;
+ public long duration;
+ public String visitorsName;
+ public String visitorsEmail;
+ public String sessionID;
+ public String question;
+
+ public AgentChatSession(Date date, long duration, String visitorsName, String visitorsEmail, String sessionID, String question) {
+ this.startDate = date;
+ this.duration = duration;
+ this.visitorsName = visitorsName;
+ this.visitorsEmail = visitorsEmail;
+ this.sessionID = sessionID;
+ this.question = question;
+ }
+
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ public void setStartDate(Date startDate) {
+ this.startDate = startDate;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public void setDuration(long duration) {
+ this.duration = duration;
+ }
+
+ public String getVisitorsName() {
+ return visitorsName;
+ }
+
+ public void setVisitorsName(String visitorsName) {
+ this.visitorsName = visitorsName;
+ }
+
+ public String getVisitorsEmail() {
+ return visitorsEmail;
+ }
+
+ public void setVisitorsEmail(String visitorsEmail) {
+ this.visitorsEmail = visitorsEmail;
+ }
+
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ public void setSessionID(String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+ public void setQuestion(String question){
+ this.question = question;
+ }
+
+ public String getQuestion(){
+ return question;
+ }
+
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/ChatMetadata.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/ChatMetadata.java
index 301e1a53c..1eaf30f49 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/ChatMetadata.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/history/ChatMetadata.java
@@ -1,116 +1,116 @@
-/**
- * $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
- *
- * 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.workgroup.ext.history;
-
-import org.jivesoftware.smackx.workgroup.util.MetaDataUtils;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class ChatMetadata extends IQ {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "chat-metadata";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
-
- private String sessionID;
-
- public String getSessionID() {
- return sessionID;
- }
-
- public void setSessionID(String sessionID) {
- this.sessionID = sessionID;
- }
-
-
- private Map<String, List<String>> map = new HashMap<String, List<String>>();
-
- public void setMetadata(Map<String, List<String>> metadata){
- this.map = metadata;
- }
-
- public Map<String, List<String>> getMetadata(){
- return map;
- }
-
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
- buf.append("<sessionID>").append(getSessionID()).append("</sessionID>");
- buf.append("</").append(ELEMENT_NAME).append("> ");
-
- return buf.toString();
- }
-
- /**
- * An IQProvider for Metadata packets.
- *
- * @author Derek DeMoro
- */
- public static class Provider implements IQProvider {
-
- public Provider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- final ChatMetadata chatM = new ChatMetadata();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("sessionID")) {
- chatM.setSessionID(parser.nextText());
- }
- else if (parser.getName().equals("metadata")) {
- Map<String, List<String>> map = MetaDataUtils.parseMetaData(parser);
- chatM.setMetadata(map);
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(ELEMENT_NAME)) {
- done = true;
- }
- }
- }
-
- return chatM;
- }
- }
-}
-
-
-
-
+/**
+ * $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
+ *
+ * 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.workgroup.ext.history;
+
+import org.jivesoftware.smackx.workgroup.util.MetaDataUtils;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ChatMetadata extends IQ {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "chat-metadata";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+
+ private String sessionID;
+
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ public void setSessionID(String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+
+ private Map<String, List<String>> map = new HashMap<String, List<String>>();
+
+ public void setMetadata(Map<String, List<String>> metadata){
+ this.map = metadata;
+ }
+
+ public Map<String, List<String>> getMetadata(){
+ return map;
+ }
+
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+ buf.append("<sessionID>").append(getSessionID()).append("</sessionID>");
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * An IQProvider for Metadata packets.
+ *
+ * @author Derek DeMoro
+ */
+ public static class Provider implements IQProvider {
+
+ public Provider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ final ChatMetadata chatM = new ChatMetadata();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("sessionID")) {
+ chatM.setSessionID(parser.nextText());
+ }
+ else if (parser.getName().equals("metadata")) {
+ Map<String, List<String>> map = MetaDataUtils.parseMetaData(parser);
+ chatM.setMetadata(map);
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(ELEMENT_NAME)) {
+ done = true;
+ }
+ }
+ }
+
+ return chatM;
+ }
+ }
+}
+
+
+
+
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macro.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macro.java
index acf619687..114902f6c 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macro.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macro.java
@@ -1,68 +1,68 @@
-/**
- * $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
- *
- * 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.workgroup.ext.macros;
-
-/**
- * Macro datamodel.
- */
-public class Macro {
- public static final int TEXT = 0;
- public static final int URL = 1;
- public static final int IMAGE = 2;
-
-
- private String title;
- private String description;
- private String response;
- private int type;
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getResponse() {
- return response;
- }
-
- public void setResponse(String response) {
- this.response = response;
- }
-
- public int getType() {
- return type;
- }
-
- public void setType(int type) {
- this.type = type;
- }
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup.ext.macros;
+
+/**
+ * Macro datamodel.
+ */
+public class Macro {
+ public static final int TEXT = 0;
+ public static final int URL = 1;
+ public static final int IMAGE = 2;
+
+
+ private String title;
+ private String description;
+ private String response;
+ private int type;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getResponse() {
+ return response;
+ }
+
+ public void setResponse(String response) {
+ this.response = response;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/MacroGroup.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/MacroGroup.java
index 0742b3d26..bb583ae2f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/MacroGroup.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/MacroGroup.java
@@ -1,143 +1,143 @@
-/**
- * $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
- *
- * 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.workgroup.ext.macros;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * MacroGroup datamodel.
- */
-public class MacroGroup {
- private List<Macro> macros;
- private List<MacroGroup> macroGroups;
-
-
- // Define MacroGroup
- private String title;
-
- public MacroGroup() {
- macros = new ArrayList<Macro>();
- macroGroups = new ArrayList<MacroGroup>();
- }
-
- public void addMacro(Macro macro) {
- macros.add(macro);
- }
-
- public void removeMacro(Macro macro) {
- macros.remove(macro);
- }
-
- public Macro getMacroByTitle(String title) {
- Collection<Macro> col = Collections.unmodifiableList(macros);
- Iterator<Macro> iter = col.iterator();
- while (iter.hasNext()) {
- Macro macro = (Macro)iter.next();
- if (macro.getTitle().equalsIgnoreCase(title)) {
- return macro;
- }
- }
- return null;
- }
-
- public void addMacroGroup(MacroGroup group) {
- macroGroups.add(group);
- }
-
- public void removeMacroGroup(MacroGroup group) {
- macroGroups.remove(group);
- }
-
- public Macro getMacro(int location) {
- return (Macro)macros.get(location);
- }
-
- public MacroGroup getMacroGroupByTitle(String title) {
- Collection<MacroGroup> col = Collections.unmodifiableList(macroGroups);
- Iterator<MacroGroup> iter = col.iterator();
- while (iter.hasNext()) {
- MacroGroup group = (MacroGroup)iter.next();
- if (group.getTitle().equalsIgnoreCase(title)) {
- return group;
- }
- }
- return null;
- }
-
- public MacroGroup getMacroGroup(int location) {
- return (MacroGroup)macroGroups.get(location);
- }
-
-
- public List<Macro> getMacros() {
- return macros;
- }
-
- public void setMacros(List<Macro> macros) {
- this.macros = macros;
- }
-
- public List<MacroGroup> getMacroGroups() {
- return macroGroups;
- }
-
- public void setMacroGroups(List<MacroGroup> macroGroups) {
- this.macroGroups = macroGroups;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<macrogroup>");
- buf.append("<title>" + getTitle() + "</title>");
- buf.append("<macros>");
- for (Macro macro : getMacros())
- {
- buf.append("<macro>");
- buf.append("<title>" + macro.getTitle() + "</title>");
- buf.append("<type>" + macro.getType() + "</type>");
- buf.append("<description>" + macro.getDescription() + "</description>");
- buf.append("<response>" + macro.getResponse() + "</response>");
- buf.append("</macro>");
- }
- buf.append("</macros>");
-
- if (getMacroGroups().size() > 0) {
- buf.append("<macroGroups>");
- for (MacroGroup groups : getMacroGroups()) {
- buf.append(groups.toXML());
- }
- buf.append("</macroGroups>");
- }
- buf.append("</macrogroup>");
- return buf.toString();
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.ext.macros;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * MacroGroup datamodel.
+ */
+public class MacroGroup {
+ private List<Macro> macros;
+ private List<MacroGroup> macroGroups;
+
+
+ // Define MacroGroup
+ private String title;
+
+ public MacroGroup() {
+ macros = new ArrayList<Macro>();
+ macroGroups = new ArrayList<MacroGroup>();
+ }
+
+ public void addMacro(Macro macro) {
+ macros.add(macro);
+ }
+
+ public void removeMacro(Macro macro) {
+ macros.remove(macro);
+ }
+
+ public Macro getMacroByTitle(String title) {
+ Collection<Macro> col = Collections.unmodifiableList(macros);
+ Iterator<Macro> iter = col.iterator();
+ while (iter.hasNext()) {
+ Macro macro = (Macro)iter.next();
+ if (macro.getTitle().equalsIgnoreCase(title)) {
+ return macro;
+ }
+ }
+ return null;
+ }
+
+ public void addMacroGroup(MacroGroup group) {
+ macroGroups.add(group);
+ }
+
+ public void removeMacroGroup(MacroGroup group) {
+ macroGroups.remove(group);
+ }
+
+ public Macro getMacro(int location) {
+ return (Macro)macros.get(location);
+ }
+
+ public MacroGroup getMacroGroupByTitle(String title) {
+ Collection<MacroGroup> col = Collections.unmodifiableList(macroGroups);
+ Iterator<MacroGroup> iter = col.iterator();
+ while (iter.hasNext()) {
+ MacroGroup group = (MacroGroup)iter.next();
+ if (group.getTitle().equalsIgnoreCase(title)) {
+ return group;
+ }
+ }
+ return null;
+ }
+
+ public MacroGroup getMacroGroup(int location) {
+ return (MacroGroup)macroGroups.get(location);
+ }
+
+
+ public List<Macro> getMacros() {
+ return macros;
+ }
+
+ public void setMacros(List<Macro> macros) {
+ this.macros = macros;
+ }
+
+ public List<MacroGroup> getMacroGroups() {
+ return macroGroups;
+ }
+
+ public void setMacroGroups(List<MacroGroup> macroGroups) {
+ this.macroGroups = macroGroups;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<macrogroup>");
+ buf.append("<title>" + getTitle() + "</title>");
+ buf.append("<macros>");
+ for (Macro macro : getMacros())
+ {
+ buf.append("<macro>");
+ buf.append("<title>" + macro.getTitle() + "</title>");
+ buf.append("<type>" + macro.getType() + "</type>");
+ buf.append("<description>" + macro.getDescription() + "</description>");
+ buf.append("<response>" + macro.getResponse() + "</response>");
+ buf.append("</macro>");
+ }
+ buf.append("</macros>");
+
+ if (getMacroGroups().size() > 0) {
+ buf.append("<macroGroups>");
+ for (MacroGroup groups : getMacroGroups()) {
+ buf.append(groups.toXML());
+ }
+ buf.append("</macroGroups>");
+ }
+ buf.append("</macrogroup>");
+ return buf.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macros.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macros.java
index b658bf965..c0718c240 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macros.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/macros/Macros.java
@@ -1,198 +1,198 @@
-/**
- * $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
- *
- * 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.workgroup.ext.macros;
-
-import java.io.StringReader;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.util.StringUtils;
-import org.xmlpull.mxp1.MXParser;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Macros iq is responsible for handling global and personal macros in the a Live Assistant
- * Workgroup.
- */
-public class Macros extends IQ {
-
- private MacroGroup rootGroup;
- private boolean personal;
- private MacroGroup personalMacroGroup;
-
- public MacroGroup getRootGroup() {
- return rootGroup;
- }
-
- public void setRootGroup(MacroGroup rootGroup) {
- this.rootGroup = rootGroup;
- }
-
- public boolean isPersonal() {
- return personal;
- }
-
- public void setPersonal(boolean personal) {
- this.personal = personal;
- }
-
- public MacroGroup getPersonalMacroGroup() {
- return personalMacroGroup;
- }
-
- public void setPersonalMacroGroup(MacroGroup personalMacroGroup) {
- this.personalMacroGroup = personalMacroGroup;
- }
-
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "macros";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
- if (isPersonal()) {
- buf.append("<personal>true</personal>");
- }
- if (getPersonalMacroGroup() != null) {
- buf.append("<personalMacro>");
- buf.append(StringUtils.escapeForXML(getPersonalMacroGroup().toXML()));
- buf.append("</personalMacro>");
- }
- buf.append("</").append(ELEMENT_NAME).append("> ");
-
- return buf.toString();
- }
-
- /**
- * An IQProvider for Macro packets.
- *
- * @author Derek DeMoro
- */
- public static class InternalProvider implements IQProvider {
-
- public InternalProvider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- Macros macroGroup = new Macros();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("model")) {
- String macros = parser.nextText();
- MacroGroup group = parseMacroGroups(macros);
- macroGroup.setRootGroup(group);
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(ELEMENT_NAME)) {
- done = true;
- }
- }
- }
-
- return macroGroup;
- }
-
- public Macro parseMacro(XmlPullParser parser) throws Exception {
- Macro macro = new Macro();
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("title")) {
- parser.next();
- macro.setTitle(parser.getText());
- }
- else if (parser.getName().equals("description")) {
- macro.setDescription(parser.nextText());
- }
- else if (parser.getName().equals("response")) {
- macro.setResponse(parser.nextText());
- }
- else if (parser.getName().equals("type")) {
- macro.setType(Integer.valueOf(parser.nextText()).intValue());
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("macro")) {
- done = true;
- }
- }
- }
- return macro;
- }
-
- public MacroGroup parseMacroGroup(XmlPullParser parser) throws Exception {
- MacroGroup group = new MacroGroup();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("macrogroup")) {
- group.addMacroGroup(parseMacroGroup(parser));
- }
- if (parser.getName().equals("title")) {
- group.setTitle(parser.nextText());
- }
- if (parser.getName().equals("macro")) {
- group.addMacro(parseMacro(parser));
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("macrogroup")) {
- done = true;
- }
- }
- }
- return group;
- }
-
- public MacroGroup parseMacroGroups(String macros) throws Exception {
-
- MacroGroup group = null;
- XmlPullParser parser = new MXParser();
- parser.setInput(new StringReader(macros));
- int eventType = parser.getEventType();
- while (eventType != XmlPullParser.END_DOCUMENT) {
- eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("macrogroup")) {
- group = parseMacroGroup(parser);
- }
- }
- }
- return group;
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.ext.macros;
+
+import java.io.StringReader;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.util.StringUtils;
+import org.xmlpull.mxp1.MXParser;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Macros iq is responsible for handling global and personal macros in the a Live Assistant
+ * Workgroup.
+ */
+public class Macros extends IQ {
+
+ private MacroGroup rootGroup;
+ private boolean personal;
+ private MacroGroup personalMacroGroup;
+
+ public MacroGroup getRootGroup() {
+ return rootGroup;
+ }
+
+ public void setRootGroup(MacroGroup rootGroup) {
+ this.rootGroup = rootGroup;
+ }
+
+ public boolean isPersonal() {
+ return personal;
+ }
+
+ public void setPersonal(boolean personal) {
+ this.personal = personal;
+ }
+
+ public MacroGroup getPersonalMacroGroup() {
+ return personalMacroGroup;
+ }
+
+ public void setPersonalMacroGroup(MacroGroup personalMacroGroup) {
+ this.personalMacroGroup = personalMacroGroup;
+ }
+
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "macros";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+ if (isPersonal()) {
+ buf.append("<personal>true</personal>");
+ }
+ if (getPersonalMacroGroup() != null) {
+ buf.append("<personalMacro>");
+ buf.append(StringUtils.escapeForXML(getPersonalMacroGroup().toXML()));
+ buf.append("</personalMacro>");
+ }
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * An IQProvider for Macro packets.
+ *
+ * @author Derek DeMoro
+ */
+ public static class InternalProvider implements IQProvider {
+
+ public InternalProvider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ Macros macroGroup = new Macros();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("model")) {
+ String macros = parser.nextText();
+ MacroGroup group = parseMacroGroups(macros);
+ macroGroup.setRootGroup(group);
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(ELEMENT_NAME)) {
+ done = true;
+ }
+ }
+ }
+
+ return macroGroup;
+ }
+
+ public Macro parseMacro(XmlPullParser parser) throws Exception {
+ Macro macro = new Macro();
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("title")) {
+ parser.next();
+ macro.setTitle(parser.getText());
+ }
+ else if (parser.getName().equals("description")) {
+ macro.setDescription(parser.nextText());
+ }
+ else if (parser.getName().equals("response")) {
+ macro.setResponse(parser.nextText());
+ }
+ else if (parser.getName().equals("type")) {
+ macro.setType(Integer.valueOf(parser.nextText()).intValue());
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("macro")) {
+ done = true;
+ }
+ }
+ }
+ return macro;
+ }
+
+ public MacroGroup parseMacroGroup(XmlPullParser parser) throws Exception {
+ MacroGroup group = new MacroGroup();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("macrogroup")) {
+ group.addMacroGroup(parseMacroGroup(parser));
+ }
+ if (parser.getName().equals("title")) {
+ group.setTitle(parser.nextText());
+ }
+ if (parser.getName().equals("macro")) {
+ group.addMacro(parseMacro(parser));
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("macrogroup")) {
+ done = true;
+ }
+ }
+ }
+ return group;
+ }
+
+ public MacroGroup parseMacroGroups(String macros) throws Exception {
+
+ MacroGroup group = null;
+ XmlPullParser parser = new MXParser();
+ parser.setInput(new StringReader(macros));
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("macrogroup")) {
+ group = parseMacroGroup(parser);
+ }
+ }
+ }
+ return group;
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/notes/ChatNotes.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/notes/ChatNotes.java
index eff3c6c6d..3540006a4 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/notes/ChatNotes.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/ext/notes/ChatNotes.java
@@ -1,155 +1,155 @@
-/**
- * $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
- *
- * 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.workgroup.ext.notes;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * IQ packet for retrieving and adding Chat Notes.
- */
-public class ChatNotes extends IQ {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "chat-notes";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
-
- private String sessionID;
- private String notes;
-
- public String getSessionID() {
- return sessionID;
- }
-
- public void setSessionID(String sessionID) {
- this.sessionID = sessionID;
- }
-
- public String getNotes() {
- return notes;
- }
-
- public void setNotes(String notes) {
- this.notes = notes;
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
- buf.append("<sessionID>").append(getSessionID()).append("</sessionID>");
-
- if (getNotes() != null) {
- buf.append("<notes>").append(getNotes()).append("</notes>");
- }
- buf.append("</").append(ELEMENT_NAME).append("> ");
-
- return buf.toString();
- }
-
- /**
- * An IQProvider for ChatNotes packets.
- *
- * @author Derek DeMoro
- */
- public static class Provider implements IQProvider {
-
- public Provider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- ChatNotes chatNotes = new ChatNotes();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("sessionID")) {
- chatNotes.setSessionID(parser.nextText());
- }
- else if (parser.getName().equals("text")) {
- String note = parser.nextText();
- note = note.replaceAll("\\\\n", "\n");
- chatNotes.setNotes(note);
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(ELEMENT_NAME)) {
- done = true;
- }
- }
- }
-
- return chatNotes;
- }
- }
-
- /**
- * Replaces all instances of oldString with newString in string.
- *
- * @param string the String to search to perform replacements on
- * @param oldString the String that should be replaced by newString
- * @param newString the String that will replace all instances of oldString
- * @return a String will all instances of oldString replaced by newString
- */
- public static final String replace(String string, String oldString, String newString) {
- if (string == null) {
- return null;
- }
- // If the newString is null or zero length, just return the string since there's nothing
- // to replace.
- if (newString == null) {
- return string;
- }
- int i = 0;
- // Make sure that oldString appears at least once before doing any processing.
- if ((i = string.indexOf(oldString, i)) >= 0) {
- // Use char []'s, as they are more efficient to deal with.
- char[] string2 = string.toCharArray();
- char[] newString2 = newString.toCharArray();
- int oLength = oldString.length();
- StringBuilder buf = new StringBuilder(string2.length);
- buf.append(string2, 0, i).append(newString2);
- i += oLength;
- int j = i;
- // Replace all remaining instances of oldString with newString.
- while ((i = string.indexOf(oldString, i)) > 0) {
- buf.append(string2, j, i - j).append(newString2);
- i += oLength;
- j = i;
- }
- buf.append(string2, j, string2.length - j);
- return buf.toString();
- }
- return string;
- }
-}
-
-
-
+/**
+ * $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
+ *
+ * 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.workgroup.ext.notes;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * IQ packet for retrieving and adding Chat Notes.
+ */
+public class ChatNotes extends IQ {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "chat-notes";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+
+ private String sessionID;
+ private String notes;
+
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ public void setSessionID(String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+ public String getNotes() {
+ return notes;
+ }
+
+ public void setNotes(String notes) {
+ this.notes = notes;
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+ buf.append("<sessionID>").append(getSessionID()).append("</sessionID>");
+
+ if (getNotes() != null) {
+ buf.append("<notes>").append(getNotes()).append("</notes>");
+ }
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * An IQProvider for ChatNotes packets.
+ *
+ * @author Derek DeMoro
+ */
+ public static class Provider implements IQProvider {
+
+ public Provider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ ChatNotes chatNotes = new ChatNotes();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("sessionID")) {
+ chatNotes.setSessionID(parser.nextText());
+ }
+ else if (parser.getName().equals("text")) {
+ String note = parser.nextText();
+ note = note.replaceAll("\\\\n", "\n");
+ chatNotes.setNotes(note);
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(ELEMENT_NAME)) {
+ done = true;
+ }
+ }
+ }
+
+ return chatNotes;
+ }
+ }
+
+ /**
+ * Replaces all instances of oldString with newString in string.
+ *
+ * @param string the String to search to perform replacements on
+ * @param oldString the String that should be replaced by newString
+ * @param newString the String that will replace all instances of oldString
+ * @return a String will all instances of oldString replaced by newString
+ */
+ public static final String replace(String string, String oldString, String newString) {
+ if (string == null) {
+ return null;
+ }
+ // If the newString is null or zero length, just return the string since there's nothing
+ // to replace.
+ if (newString == null) {
+ return string;
+ }
+ int i = 0;
+ // Make sure that oldString appears at least once before doing any processing.
+ if ((i = string.indexOf(oldString, i)) >= 0) {
+ // Use char []'s, as they are more efficient to deal with.
+ char[] string2 = string.toCharArray();
+ char[] newString2 = newString.toCharArray();
+ int oLength = oldString.length();
+ StringBuilder buf = new StringBuilder(string2.length);
+ buf.append(string2, 0, i).append(newString2);
+ i += oLength;
+ int j = i;
+ // Replace all remaining instances of oldString with newString.
+ while ((i = string.indexOf(oldString, i)) > 0) {
+ buf.append(string2, j, i - j).append(newString2);
+ i += oLength;
+ j = i;
+ }
+ buf.append(string2, j, string2.length - j);
+ return buf.toString();
+ }
+ return string;
+ }
+}
+
+
+
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentInfo.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentInfo.java
index 8b9d23073..6502b88a4 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentInfo.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentInfo.java
@@ -1,132 +1,132 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * IQ packet for retrieving and changing the Agent personal information.
- */
-public class AgentInfo extends IQ {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "agent-info";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- private String jid;
- private String name;
-
- /**
- * Returns the Agent's jid.
- *
- * @return the Agent's jid.
- */
- public String getJid() {
- return jid;
- }
-
- /**
- * Sets the Agent's jid.
- *
- * @param jid the jid of the agent.
- */
- public void setJid(String jid) {
- this.jid = jid;
- }
-
- /**
- * Returns the Agent's name. The name of the agent may be different than the user's name.
- * This property may be shown in the webchat client.
- *
- * @return the Agent's name.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the Agent's name. The name of the agent may be different than the user's name.
- * This property may be shown in the webchat client.
- *
- * @param name the new name of the agent.
- */
- public void setName(String name) {
- this.name = name;
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
- if (jid != null) {
- buf.append("<jid>").append(getJid()).append("</jid>");
- }
- if (name != null) {
- buf.append("<name>").append(getName()).append("</name>");
- }
- buf.append("</").append(ELEMENT_NAME).append("> ");
-
- return buf.toString();
- }
-
- /**
- * An IQProvider for AgentInfo packets.
- *
- * @author Gaston Dombiak
- */
- public static class Provider implements IQProvider {
-
- public Provider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- AgentInfo answer = new AgentInfo();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("jid")) {
- answer.setJid(parser.nextText());
- }
- else if (parser.getName().equals("name")) {
- answer.setName(parser.nextText());
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(ELEMENT_NAME)) {
- done = true;
- }
- }
- }
-
- return answer;
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * IQ packet for retrieving and changing the Agent personal information.
+ */
+public class AgentInfo extends IQ {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "agent-info";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ private String jid;
+ private String name;
+
+ /**
+ * Returns the Agent's jid.
+ *
+ * @return the Agent's jid.
+ */
+ public String getJid() {
+ return jid;
+ }
+
+ /**
+ * Sets the Agent's jid.
+ *
+ * @param jid the jid of the agent.
+ */
+ public void setJid(String jid) {
+ this.jid = jid;
+ }
+
+ /**
+ * Returns the Agent's name. The name of the agent may be different than the user's name.
+ * This property may be shown in the webchat client.
+ *
+ * @return the Agent's name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the Agent's name. The name of the agent may be different than the user's name.
+ * This property may be shown in the webchat client.
+ *
+ * @param name the new name of the agent.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+ if (jid != null) {
+ buf.append("<jid>").append(getJid()).append("</jid>");
+ }
+ if (name != null) {
+ buf.append("<name>").append(getName()).append("</name>");
+ }
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * An IQProvider for AgentInfo packets.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Provider implements IQProvider {
+
+ public Provider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ AgentInfo answer = new AgentInfo();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("jid")) {
+ answer.setJid(parser.nextText());
+ }
+ else if (parser.getName().equals("name")) {
+ answer.setName(parser.nextText());
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(ELEMENT_NAME)) {
+ done = true;
+ }
+ }
+ }
+
+ return answer;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatus.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatus.java
index 9f4903316..f84fe5c6b 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatus.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatus.java
@@ -1,266 +1,266 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.*;
-
-/**
- * Agent status packet.
- *
- * @author Matt Tucker
- */
-public class AgentStatus implements PacketExtension {
-
- private static final SimpleDateFormat UTC_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
-
- static {
- UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
- }
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "agent-status";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
-
- private String workgroupJID;
- private List<ChatInfo> currentChats = new ArrayList<ChatInfo>();
- private int maxChats = -1;
-
- AgentStatus() {
- }
-
- public String getWorkgroupJID() {
- return workgroupJID;
- }
-
- /**
- * Returns a collection of ChatInfo where each ChatInfo represents a Chat where this agent
- * is participating.
- *
- * @return a collection of ChatInfo where each ChatInfo represents a Chat where this agent
- * is participating.
- */
- public List<ChatInfo> getCurrentChats() {
- return Collections.unmodifiableList(currentChats);
- }
-
- public int getMaxChats() {
- return maxChats;
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\"");
- if (workgroupJID != null) {
- buf.append(" jid=\"").append(workgroupJID).append("\"");
- }
- buf.append(">");
- if (maxChats != -1) {
- buf.append("<max-chats>").append(maxChats).append("</max-chats>");
- }
- if (!currentChats.isEmpty()) {
- buf.append("<current-chats xmlns= \"http://jivesoftware.com/protocol/workgroup\">");
- for (Iterator<ChatInfo> it = currentChats.iterator(); it.hasNext();) {
- buf.append(((ChatInfo)it.next()).toXML());
- }
- buf.append("</current-chats>");
- }
- buf.append("</").append(this.getElementName()).append("> ");
-
- return buf.toString();
- }
-
- /**
- * Represents information about a Chat where this Agent is participating.
- *
- * @author Gaston Dombiak
- */
- public static class ChatInfo {
-
- private String sessionID;
- private String userID;
- private Date date;
- private String email;
- private String username;
- private String question;
-
- public ChatInfo(String sessionID, String userID, Date date, String email, String username, String question) {
- this.sessionID = sessionID;
- this.userID = userID;
- this.date = date;
- this.email = email;
- this.username = username;
- this.question = question;
- }
-
- /**
- * Returns the sessionID associated to this chat. Each chat will have a unique sessionID
- * that could be used for retrieving the whole transcript of the conversation.
- *
- * @return the sessionID associated to this chat.
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Returns the user unique identification of the user that made the initial request and
- * for which this chat was generated. If the user joined using an anonymous connection
- * then the userID will be the value of the ID attribute of the USER element. Otherwise,
- * the userID will be the bare JID of the user that made the request.
- *
- * @return the user unique identification of the user that made the initial request.
- */
- public String getUserID() {
- return userID;
- }
-
- /**
- * Returns the date when this agent joined the chat.
- *
- * @return the date when this agent joined the chat.
- */
- public Date getDate() {
- return date;
- }
-
- /**
- * Returns the email address associated with the user.
- *
- * @return the email address associated with the user.
- */
- public String getEmail() {
- return email;
- }
-
- /**
- * Returns the username(nickname) associated with the user.
- *
- * @return the username associated with the user.
- */
- public String getUsername() {
- return username;
- }
-
- /**
- * Returns the question the user asked.
- *
- * @return the question the user asked, if any.
- */
- public String getQuestion() {
- return question;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<chat ");
- if (sessionID != null) {
- buf.append(" sessionID=\"").append(sessionID).append("\"");
- }
- if (userID != null) {
- buf.append(" userID=\"").append(userID).append("\"");
- }
- if (date != null) {
- buf.append(" startTime=\"").append(UTC_FORMAT.format(date)).append("\"");
- }
- if (email != null) {
- buf.append(" email=\"").append(email).append("\"");
- }
- if (username != null) {
- buf.append(" username=\"").append(username).append("\"");
- }
- if (question != null) {
- buf.append(" question=\"").append(question).append("\"");
- }
- buf.append("/>");
-
- return buf.toString();
- }
- }
-
- /**
- * Packet extension provider for AgentStatus packets.
- */
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- AgentStatus agentStatus = new AgentStatus();
-
- agentStatus.workgroupJID = parser.getAttributeValue("", "jid");
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
-
- if (eventType == XmlPullParser.START_TAG) {
- if ("chat".equals(parser.getName())) {
- agentStatus.currentChats.add(parseChatInfo(parser));
- }
- else if ("max-chats".equals(parser.getName())) {
- agentStatus.maxChats = Integer.parseInt(parser.nextText());
- }
- }
- else if (eventType == XmlPullParser.END_TAG &&
- ELEMENT_NAME.equals(parser.getName())) {
- done = true;
- }
- }
- return agentStatus;
- }
-
- private ChatInfo parseChatInfo(XmlPullParser parser) {
-
- String sessionID = parser.getAttributeValue("", "sessionID");
- String userID = parser.getAttributeValue("", "userID");
- Date date = null;
- try {
- date = UTC_FORMAT.parse(parser.getAttributeValue("", "startTime"));
- }
- catch (ParseException e) {
- }
-
- String email = parser.getAttributeValue("", "email");
- String username = parser.getAttributeValue("", "username");
- String question = parser.getAttributeValue("", "question");
-
- return new ChatInfo(sessionID, userID, date, email, username, question);
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * Agent status packet.
+ *
+ * @author Matt Tucker
+ */
+public class AgentStatus implements PacketExtension {
+
+ private static final SimpleDateFormat UTC_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
+
+ static {
+ UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
+ }
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "agent-status";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
+
+ private String workgroupJID;
+ private List<ChatInfo> currentChats = new ArrayList<ChatInfo>();
+ private int maxChats = -1;
+
+ AgentStatus() {
+ }
+
+ public String getWorkgroupJID() {
+ return workgroupJID;
+ }
+
+ /**
+ * Returns a collection of ChatInfo where each ChatInfo represents a Chat where this agent
+ * is participating.
+ *
+ * @return a collection of ChatInfo where each ChatInfo represents a Chat where this agent
+ * is participating.
+ */
+ public List<ChatInfo> getCurrentChats() {
+ return Collections.unmodifiableList(currentChats);
+ }
+
+ public int getMaxChats() {
+ return maxChats;
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\"");
+ if (workgroupJID != null) {
+ buf.append(" jid=\"").append(workgroupJID).append("\"");
+ }
+ buf.append(">");
+ if (maxChats != -1) {
+ buf.append("<max-chats>").append(maxChats).append("</max-chats>");
+ }
+ if (!currentChats.isEmpty()) {
+ buf.append("<current-chats xmlns= \"http://jivesoftware.com/protocol/workgroup\">");
+ for (Iterator<ChatInfo> it = currentChats.iterator(); it.hasNext();) {
+ buf.append(((ChatInfo)it.next()).toXML());
+ }
+ buf.append("</current-chats>");
+ }
+ buf.append("</").append(this.getElementName()).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * Represents information about a Chat where this Agent is participating.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class ChatInfo {
+
+ private String sessionID;
+ private String userID;
+ private Date date;
+ private String email;
+ private String username;
+ private String question;
+
+ public ChatInfo(String sessionID, String userID, Date date, String email, String username, String question) {
+ this.sessionID = sessionID;
+ this.userID = userID;
+ this.date = date;
+ this.email = email;
+ this.username = username;
+ this.question = question;
+ }
+
+ /**
+ * Returns the sessionID associated to this chat. Each chat will have a unique sessionID
+ * that could be used for retrieving the whole transcript of the conversation.
+ *
+ * @return the sessionID associated to this chat.
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Returns the user unique identification of the user that made the initial request and
+ * for which this chat was generated. If the user joined using an anonymous connection
+ * then the userID will be the value of the ID attribute of the USER element. Otherwise,
+ * the userID will be the bare JID of the user that made the request.
+ *
+ * @return the user unique identification of the user that made the initial request.
+ */
+ public String getUserID() {
+ return userID;
+ }
+
+ /**
+ * Returns the date when this agent joined the chat.
+ *
+ * @return the date when this agent joined the chat.
+ */
+ public Date getDate() {
+ return date;
+ }
+
+ /**
+ * Returns the email address associated with the user.
+ *
+ * @return the email address associated with the user.
+ */
+ public String getEmail() {
+ return email;
+ }
+
+ /**
+ * Returns the username(nickname) associated with the user.
+ *
+ * @return the username associated with the user.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Returns the question the user asked.
+ *
+ * @return the question the user asked, if any.
+ */
+ public String getQuestion() {
+ return question;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<chat ");
+ if (sessionID != null) {
+ buf.append(" sessionID=\"").append(sessionID).append("\"");
+ }
+ if (userID != null) {
+ buf.append(" userID=\"").append(userID).append("\"");
+ }
+ if (date != null) {
+ buf.append(" startTime=\"").append(UTC_FORMAT.format(date)).append("\"");
+ }
+ if (email != null) {
+ buf.append(" email=\"").append(email).append("\"");
+ }
+ if (username != null) {
+ buf.append(" username=\"").append(username).append("\"");
+ }
+ if (question != null) {
+ buf.append(" question=\"").append(question).append("\"");
+ }
+ buf.append("/>");
+
+ return buf.toString();
+ }
+ }
+
+ /**
+ * Packet extension provider for AgentStatus packets.
+ */
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ AgentStatus agentStatus = new AgentStatus();
+
+ agentStatus.workgroupJID = parser.getAttributeValue("", "jid");
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+
+ if (eventType == XmlPullParser.START_TAG) {
+ if ("chat".equals(parser.getName())) {
+ agentStatus.currentChats.add(parseChatInfo(parser));
+ }
+ else if ("max-chats".equals(parser.getName())) {
+ agentStatus.maxChats = Integer.parseInt(parser.nextText());
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG &&
+ ELEMENT_NAME.equals(parser.getName())) {
+ done = true;
+ }
+ }
+ return agentStatus;
+ }
+
+ private ChatInfo parseChatInfo(XmlPullParser parser) {
+
+ String sessionID = parser.getAttributeValue("", "sessionID");
+ String userID = parser.getAttributeValue("", "userID");
+ Date date = null;
+ try {
+ date = UTC_FORMAT.parse(parser.getAttributeValue("", "startTime"));
+ }
+ catch (ParseException e) {
+ }
+
+ String email = parser.getAttributeValue("", "email");
+ String username = parser.getAttributeValue("", "username");
+ String question = parser.getAttributeValue("", "question");
+
+ return new ChatInfo(sessionID, userID, date, email, username, question);
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatusRequest.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatusRequest.java
index 48549d22d..db6626c77 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatusRequest.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentStatusRequest.java
@@ -1,163 +1,163 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-/**
- * Agent status request packet. This packet is used by agents to request the list of
- * agents in a workgroup. The response packet contains a list of packets. Presence
- * packets from individual agents follow.
- *
- * @author Matt Tucker
- */
-public class AgentStatusRequest extends IQ {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "agent-status-request";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
-
- private Set<Item> agents;
-
- public AgentStatusRequest() {
- agents = new HashSet<Item>();
- }
-
- public int getAgentCount() {
- return agents.size();
- }
-
- public Set<Item> getAgents() {
- return Collections.unmodifiableSet(agents);
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
- synchronized (agents) {
- for (Iterator<Item> i=agents.iterator(); i.hasNext(); ) {
- Item item = (Item) i.next();
- buf.append("<agent jid=\"").append(item.getJID()).append("\">");
- if (item.getName() != null) {
- buf.append("<name xmlns=\""+ AgentInfo.NAMESPACE + "\">");
- buf.append(item.getName());
- buf.append("</name>");
- }
- buf.append("</agent>");
- }
- }
- buf.append("</").append(this.getElementName()).append("> ");
- return buf.toString();
- }
-
- public static class Item {
-
- private String jid;
- private String type;
- private String name;
-
- public Item(String jid, String type, String name) {
- this.jid = jid;
- this.type = type;
- this.name = name;
- }
-
- public String getJID() {
- return jid;
- }
-
- public String getType() {
- return type;
- }
-
- public String getName() {
- return name;
- }
- }
-
- /**
- * Packet extension provider for AgentStatusRequest packets.
- */
- public static class Provider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- AgentStatusRequest statusRequest = new AgentStatusRequest();
-
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- throw new IllegalStateException("Parser not in proper position, or bad XML.");
- }
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("agent".equals(parser.getName()))) {
- statusRequest.agents.add(parseAgent(parser));
- }
- else if (eventType == XmlPullParser.END_TAG &&
- "agent-status-request".equals(parser.getName()))
- {
- done = true;
- }
- }
- return statusRequest;
- }
-
- private Item parseAgent(XmlPullParser parser) throws Exception {
-
- boolean done = false;
- String jid = parser.getAttributeValue("", "jid");
- String type = parser.getAttributeValue("", "type");
- String name = null;
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("name".equals(parser.getName()))) {
- name = parser.nextText();
- }
- else if (eventType == XmlPullParser.END_TAG &&
- "agent".equals(parser.getName()))
- {
- done = true;
- }
- }
- return new Item(jid, type, name);
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Agent status request packet. This packet is used by agents to request the list of
+ * agents in a workgroup. The response packet contains a list of packets. Presence
+ * packets from individual agents follow.
+ *
+ * @author Matt Tucker
+ */
+public class AgentStatusRequest extends IQ {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "agent-status-request";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
+
+ private Set<Item> agents;
+
+ public AgentStatusRequest() {
+ agents = new HashSet<Item>();
+ }
+
+ public int getAgentCount() {
+ return agents.size();
+ }
+
+ public Set<Item> getAgents() {
+ return Collections.unmodifiableSet(agents);
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+ synchronized (agents) {
+ for (Iterator<Item> i=agents.iterator(); i.hasNext(); ) {
+ Item item = (Item) i.next();
+ buf.append("<agent jid=\"").append(item.getJID()).append("\">");
+ if (item.getName() != null) {
+ buf.append("<name xmlns=\""+ AgentInfo.NAMESPACE + "\">");
+ buf.append(item.getName());
+ buf.append("</name>");
+ }
+ buf.append("</agent>");
+ }
+ }
+ buf.append("</").append(this.getElementName()).append("> ");
+ return buf.toString();
+ }
+
+ public static class Item {
+
+ private String jid;
+ private String type;
+ private String name;
+
+ public Item(String jid, String type, String name) {
+ this.jid = jid;
+ this.type = type;
+ this.name = name;
+ }
+
+ public String getJID() {
+ return jid;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ /**
+ * Packet extension provider for AgentStatusRequest packets.
+ */
+ public static class Provider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ AgentStatusRequest statusRequest = new AgentStatusRequest();
+
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("Parser not in proper position, or bad XML.");
+ }
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("agent".equals(parser.getName()))) {
+ statusRequest.agents.add(parseAgent(parser));
+ }
+ else if (eventType == XmlPullParser.END_TAG &&
+ "agent-status-request".equals(parser.getName()))
+ {
+ done = true;
+ }
+ }
+ return statusRequest;
+ }
+
+ private Item parseAgent(XmlPullParser parser) throws Exception {
+
+ boolean done = false;
+ String jid = parser.getAttributeValue("", "jid");
+ String type = parser.getAttributeValue("", "type");
+ String name = null;
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("name".equals(parser.getName()))) {
+ name = parser.nextText();
+ }
+ else if (eventType == XmlPullParser.END_TAG &&
+ "agent".equals(parser.getName()))
+ {
+ done = true;
+ }
+ }
+ return new Item(jid, type, name);
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentWorkgroups.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentWorkgroups.java
index 292a640d8..29fa09acf 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentWorkgroups.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/AgentWorkgroups.java
@@ -1,129 +1,129 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Represents a request for getting the jid of the workgroups where an agent can work or could
- * represent the result of such request which will contain the list of workgroups JIDs where the
- * agent can work.
- *
- * @author Gaston Dombiak
- */
-public class AgentWorkgroups extends IQ {
-
- private String agentJID;
- private List<String> workgroups;
-
- /**
- * Creates an AgentWorkgroups request for the given agent. This IQ will be sent and an answer
- * will be received with the jid of the workgroups where the agent can work.
- *
- * @param agentJID the id of the agent to get his workgroups.
- */
- public AgentWorkgroups(String agentJID) {
- this.agentJID = agentJID;
- this.workgroups = new ArrayList<String>();
- }
-
- /**
- * Creates an AgentWorkgroups which will contain the JIDs of the workgroups where an agent can
- * work.
- *
- * @param agentJID the id of the agent that can work in the list of workgroups.
- * @param workgroups the list of workgroup JIDs where the agent can work.
- */
- public AgentWorkgroups(String agentJID, List<String> workgroups) {
- this.agentJID = agentJID;
- this.workgroups = workgroups;
- }
-
- public String getAgentJID() {
- return agentJID;
- }
-
- /**
- * Returns a list of workgroup JIDs where the agent can work.
- *
- * @return a list of workgroup JIDs where the agent can work.
- */
- public List<String> getWorkgroups() {
- return Collections.unmodifiableList(workgroups);
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<workgroups xmlns=\"http://jabber.org/protocol/workgroup\" jid=\"")
- .append(agentJID)
- .append("\">");
-
- for (Iterator<String> it=workgroups.iterator(); it.hasNext();) {
- String workgroupJID = it.next();
- buf.append("<workgroup jid=\"" + workgroupJID + "\"/>");
- }
-
- buf.append("</workgroups>");
-
- return buf.toString();
- }
-
- /**
- * An IQProvider for AgentWorkgroups packets.
- *
- * @author Gaston Dombiak
- */
- public static class Provider implements IQProvider {
-
- public Provider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- String agentJID = parser.getAttributeValue("", "jid");
- List<String> workgroups = new ArrayList<String>();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("workgroup")) {
- workgroups.add(parser.getAttributeValue("", "jid"));
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("workgroups")) {
- done = true;
- }
- }
- }
-
- return new AgentWorkgroups(agentJID, workgroups);
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Represents a request for getting the jid of the workgroups where an agent can work or could
+ * represent the result of such request which will contain the list of workgroups JIDs where the
+ * agent can work.
+ *
+ * @author Gaston Dombiak
+ */
+public class AgentWorkgroups extends IQ {
+
+ private String agentJID;
+ private List<String> workgroups;
+
+ /**
+ * Creates an AgentWorkgroups request for the given agent. This IQ will be sent and an answer
+ * will be received with the jid of the workgroups where the agent can work.
+ *
+ * @param agentJID the id of the agent to get his workgroups.
+ */
+ public AgentWorkgroups(String agentJID) {
+ this.agentJID = agentJID;
+ this.workgroups = new ArrayList<String>();
+ }
+
+ /**
+ * Creates an AgentWorkgroups which will contain the JIDs of the workgroups where an agent can
+ * work.
+ *
+ * @param agentJID the id of the agent that can work in the list of workgroups.
+ * @param workgroups the list of workgroup JIDs where the agent can work.
+ */
+ public AgentWorkgroups(String agentJID, List<String> workgroups) {
+ this.agentJID = agentJID;
+ this.workgroups = workgroups;
+ }
+
+ public String getAgentJID() {
+ return agentJID;
+ }
+
+ /**
+ * Returns a list of workgroup JIDs where the agent can work.
+ *
+ * @return a list of workgroup JIDs where the agent can work.
+ */
+ public List<String> getWorkgroups() {
+ return Collections.unmodifiableList(workgroups);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<workgroups xmlns=\"http://jabber.org/protocol/workgroup\" jid=\"")
+ .append(agentJID)
+ .append("\">");
+
+ for (Iterator<String> it=workgroups.iterator(); it.hasNext();) {
+ String workgroupJID = it.next();
+ buf.append("<workgroup jid=\"" + workgroupJID + "\"/>");
+ }
+
+ buf.append("</workgroups>");
+
+ return buf.toString();
+ }
+
+ /**
+ * An IQProvider for AgentWorkgroups packets.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Provider implements IQProvider {
+
+ public Provider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ String agentJID = parser.getAttributeValue("", "jid");
+ List<String> workgroups = new ArrayList<String>();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("workgroup")) {
+ workgroups.add(parser.getAttributeValue("", "jid"));
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("workgroups")) {
+ done = true;
+ }
+ }
+ }
+
+ return new AgentWorkgroups(agentJID, workgroups);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/DepartQueuePacket.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/DepartQueuePacket.java
index 620291c49..d9db5e1dd 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/DepartQueuePacket.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/DepartQueuePacket.java
@@ -1,75 +1,75 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-
-/**
- * A IQ packet used to depart a workgroup queue. There are two cases for issuing a depart
- * queue request:<ul>
- * <li>The user wants to leave the queue. In this case, an instance of this class
- * should be created without passing in a user address.
- * <li>An administrator or the server removes wants to remove a user from the queue.
- * In that case, the address of the user to remove from the queue should be
- * used to create an instance of this class.</ul>
- *
- * @author loki der quaeler
- */
-public class DepartQueuePacket extends IQ {
-
- private String user;
-
- /**
- * Creates a depart queue request packet to the specified workgroup.
- *
- * @param workgroup the workgroup to depart.
- */
- public DepartQueuePacket(String workgroup) {
- this(workgroup, null);
- }
-
- /**
- * Creates a depart queue request to the specified workgroup and for the
- * specified user.
- *
- * @param workgroup the workgroup to depart.
- * @param user the user to make depart from the queue.
- */
- public DepartQueuePacket(String workgroup, String user) {
- this.user = user;
-
- setTo(workgroup);
- setType(IQ.Type.SET);
- setFrom(user);
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder("<depart-queue xmlns=\"http://jabber.org/protocol/workgroup\"");
-
- if (this.user != null) {
- buf.append("><jid>").append(this.user).append("</jid></depart-queue>");
- }
- else {
- buf.append("/>");
- }
-
- return buf.toString();
- }
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+
+/**
+ * A IQ packet used to depart a workgroup queue. There are two cases for issuing a depart
+ * queue request:<ul>
+ * <li>The user wants to leave the queue. In this case, an instance of this class
+ * should be created without passing in a user address.
+ * <li>An administrator or the server removes wants to remove a user from the queue.
+ * In that case, the address of the user to remove from the queue should be
+ * used to create an instance of this class.</ul>
+ *
+ * @author loki der quaeler
+ */
+public class DepartQueuePacket extends IQ {
+
+ private String user;
+
+ /**
+ * Creates a depart queue request packet to the specified workgroup.
+ *
+ * @param workgroup the workgroup to depart.
+ */
+ public DepartQueuePacket(String workgroup) {
+ this(workgroup, null);
+ }
+
+ /**
+ * Creates a depart queue request to the specified workgroup and for the
+ * specified user.
+ *
+ * @param workgroup the workgroup to depart.
+ * @param user the user to make depart from the queue.
+ */
+ public DepartQueuePacket(String workgroup, String user) {
+ this.user = user;
+
+ setTo(workgroup);
+ setType(IQ.Type.SET);
+ setFrom(user);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder("<depart-queue xmlns=\"http://jabber.org/protocol/workgroup\"");
+
+ if (this.user != null) {
+ buf.append("><jid>").append(this.user).append("</jid></depart-queue>");
+ }
+ else {
+ buf.append("/>");
+ }
+
+ return buf.toString();
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/MetaDataProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/MetaDataProvider.java
index af76986be..a3262123b 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/MetaDataProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/MetaDataProvider.java
@@ -1,49 +1,49 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smackx.workgroup.MetaData;
-import org.jivesoftware.smackx.workgroup.util.MetaDataUtils;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * This provider parses meta data if it's not contained already in a larger extension provider.
- *
- * @author loki der quaeler
- */
-public class MetaDataProvider implements PacketExtensionProvider {
-
- /**
- * PacketExtensionProvider implementation
- */
- public PacketExtension parseExtension (XmlPullParser parser)
- throws Exception {
- Map<String, List<String>> metaData = MetaDataUtils.parseMetaData(parser);
-
- return new MetaData(metaData);
- }
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jivesoftware.smackx.workgroup.MetaData;
+import org.jivesoftware.smackx.workgroup.util.MetaDataUtils;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * This provider parses meta data if it's not contained already in a larger extension provider.
+ *
+ * @author loki der quaeler
+ */
+public class MetaDataProvider implements PacketExtensionProvider {
+
+ /**
+ * PacketExtensionProvider implementation
+ */
+ public PacketExtension parseExtension (XmlPullParser parser)
+ throws Exception {
+ Map<String, List<String>> metaData = MetaDataUtils.parseMetaData(parser);
+
+ return new MetaData(metaData);
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OccupantsInfo.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OccupantsInfo.java
index 0f8086649..b577bab8c 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OccupantsInfo.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OccupantsInfo.java
@@ -1,173 +1,173 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.text.SimpleDateFormat;
-import java.util.*;
-
-/**
- * Packet used for requesting information about occupants of a room or for retrieving information
- * such information.
- *
- * @author Gaston Dombiak
- */
-public class OccupantsInfo extends IQ {
-
- private static final SimpleDateFormat UTC_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
-
- static {
- UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
- }
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "occupants-info";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- private String roomID;
- private final Set<OccupantInfo> occupants;
-
- public OccupantsInfo(String roomID) {
- this.roomID = roomID;
- this.occupants = new HashSet<OccupantInfo>();
- }
-
- public String getRoomID() {
- return roomID;
- }
-
- public int getOccupantsCount() {
- return occupants.size();
- }
-
- public Set<OccupantInfo> getOccupants() {
- return Collections.unmodifiableSet(occupants);
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE);
- buf.append("\" roomID=\"").append(roomID).append("\">");
- synchronized (occupants) {
- for (OccupantInfo occupant : occupants) {
- buf.append("<occupant>");
- // Add the occupant jid
- buf.append("<jid>");
- buf.append(occupant.getJID());
- buf.append("</jid>");
- // Add the occupant nickname
- buf.append("<name>");
- buf.append(occupant.getNickname());
- buf.append("</name>");
- // Add the date when the occupant joined the room
- buf.append("<joined>");
- buf.append(UTC_FORMAT.format(occupant.getJoined()));
- buf.append("</joined>");
- buf.append("</occupant>");
- }
- }
- buf.append("</").append(ELEMENT_NAME).append("> ");
- return buf.toString();
- }
-
- public static class OccupantInfo {
-
- private String jid;
- private String nickname;
- private Date joined;
-
- public OccupantInfo(String jid, String nickname, Date joined) {
- this.jid = jid;
- this.nickname = nickname;
- this.joined = joined;
- }
-
- public String getJID() {
- return jid;
- }
-
- public String getNickname() {
- return nickname;
- }
-
- public Date getJoined() {
- return joined;
- }
- }
-
- /**
- * Packet extension provider for AgentStatusRequest packets.
- */
- public static class Provider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- throw new IllegalStateException("Parser not in proper position, or bad XML.");
- }
- OccupantsInfo occupantsInfo = new OccupantsInfo(parser.getAttributeValue("", "roomID"));
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) &&
- ("occupant".equals(parser.getName()))) {
- occupantsInfo.occupants.add(parseOccupantInfo(parser));
- } else if (eventType == XmlPullParser.END_TAG &&
- ELEMENT_NAME.equals(parser.getName())) {
- done = true;
- }
- }
- return occupantsInfo;
- }
-
- private OccupantInfo parseOccupantInfo(XmlPullParser parser) throws Exception {
-
- boolean done = false;
- String jid = null;
- String nickname = null;
- Date joined = null;
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("jid".equals(parser.getName()))) {
- jid = parser.nextText();
- } else if ((eventType == XmlPullParser.START_TAG) &&
- ("nickname".equals(parser.getName()))) {
- nickname = parser.nextText();
- } else if ((eventType == XmlPullParser.START_TAG) &&
- ("joined".equals(parser.getName()))) {
- joined = UTC_FORMAT.parse(parser.nextText());
- } else if (eventType == XmlPullParser.END_TAG &&
- "occupant".equals(parser.getName())) {
- done = true;
- }
- }
- return new OccupantInfo(jid, nickname, joined);
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * Packet used for requesting information about occupants of a room or for retrieving information
+ * such information.
+ *
+ * @author Gaston Dombiak
+ */
+public class OccupantsInfo extends IQ {
+
+ private static final SimpleDateFormat UTC_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
+
+ static {
+ UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
+ }
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "occupants-info";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ private String roomID;
+ private final Set<OccupantInfo> occupants;
+
+ public OccupantsInfo(String roomID) {
+ this.roomID = roomID;
+ this.occupants = new HashSet<OccupantInfo>();
+ }
+
+ public String getRoomID() {
+ return roomID;
+ }
+
+ public int getOccupantsCount() {
+ return occupants.size();
+ }
+
+ public Set<OccupantInfo> getOccupants() {
+ return Collections.unmodifiableSet(occupants);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE);
+ buf.append("\" roomID=\"").append(roomID).append("\">");
+ synchronized (occupants) {
+ for (OccupantInfo occupant : occupants) {
+ buf.append("<occupant>");
+ // Add the occupant jid
+ buf.append("<jid>");
+ buf.append(occupant.getJID());
+ buf.append("</jid>");
+ // Add the occupant nickname
+ buf.append("<name>");
+ buf.append(occupant.getNickname());
+ buf.append("</name>");
+ // Add the date when the occupant joined the room
+ buf.append("<joined>");
+ buf.append(UTC_FORMAT.format(occupant.getJoined()));
+ buf.append("</joined>");
+ buf.append("</occupant>");
+ }
+ }
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+ return buf.toString();
+ }
+
+ public static class OccupantInfo {
+
+ private String jid;
+ private String nickname;
+ private Date joined;
+
+ public OccupantInfo(String jid, String nickname, Date joined) {
+ this.jid = jid;
+ this.nickname = nickname;
+ this.joined = joined;
+ }
+
+ public String getJID() {
+ return jid;
+ }
+
+ public String getNickname() {
+ return nickname;
+ }
+
+ public Date getJoined() {
+ return joined;
+ }
+ }
+
+ /**
+ * Packet extension provider for AgentStatusRequest packets.
+ */
+ public static class Provider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("Parser not in proper position, or bad XML.");
+ }
+ OccupantsInfo occupantsInfo = new OccupantsInfo(parser.getAttributeValue("", "roomID"));
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) &&
+ ("occupant".equals(parser.getName()))) {
+ occupantsInfo.occupants.add(parseOccupantInfo(parser));
+ } else if (eventType == XmlPullParser.END_TAG &&
+ ELEMENT_NAME.equals(parser.getName())) {
+ done = true;
+ }
+ }
+ return occupantsInfo;
+ }
+
+ private OccupantInfo parseOccupantInfo(XmlPullParser parser) throws Exception {
+
+ boolean done = false;
+ String jid = null;
+ String nickname = null;
+ Date joined = null;
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("jid".equals(parser.getName()))) {
+ jid = parser.nextText();
+ } else if ((eventType == XmlPullParser.START_TAG) &&
+ ("nickname".equals(parser.getName()))) {
+ nickname = parser.nextText();
+ } else if ((eventType == XmlPullParser.START_TAG) &&
+ ("joined".equals(parser.getName()))) {
+ joined = UTC_FORMAT.parse(parser.nextText());
+ } else if (eventType == XmlPullParser.END_TAG &&
+ "occupant".equals(parser.getName())) {
+ done = true;
+ }
+ }
+ return new OccupantInfo(jid, nickname, joined);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRequestProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRequestProvider.java
index 8f56b788a..c7d245a57 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRequestProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRequestProvider.java
@@ -1,211 +1,211 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smackx.workgroup.MetaData;
-import org.jivesoftware.smackx.workgroup.agent.InvitationRequest;
-import org.jivesoftware.smackx.workgroup.agent.OfferContent;
-import org.jivesoftware.smackx.workgroup.agent.TransferRequest;
-import org.jivesoftware.smackx.workgroup.agent.UserRequest;
-import org.jivesoftware.smackx.workgroup.util.MetaDataUtils;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * An IQProvider for agent offer requests.
- *
- * @author loki der quaeler
- */
-public class OfferRequestProvider implements IQProvider {
-
- public OfferRequestProvider() {
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- int eventType = parser.getEventType();
- String sessionID = null;
- int timeout = -1;
- OfferContent content = null;
- boolean done = false;
- Map<String, List<String>> metaData = new HashMap<String, List<String>>();
-
- if (eventType != XmlPullParser.START_TAG) {
- // throw exception
- }
-
- String userJID = parser.getAttributeValue("", "jid");
- // Default userID to the JID.
- String userID = userJID;
-
- while (!done) {
- eventType = parser.next();
-
- if (eventType == XmlPullParser.START_TAG) {
- String elemName = parser.getName();
-
- if ("timeout".equals(elemName)) {
- timeout = Integer.parseInt(parser.nextText());
- }
- else if (MetaData.ELEMENT_NAME.equals(elemName)) {
- metaData = MetaDataUtils.parseMetaData(parser);
- }
- else if (SessionID.ELEMENT_NAME.equals(elemName)) {
- sessionID = parser.getAttributeValue("", "id");
- }
- else if (UserID.ELEMENT_NAME.equals(elemName)) {
- userID = parser.getAttributeValue("", "id");
- }
- else if ("user-request".equals(elemName)) {
- content = UserRequest.getInstance();
- }
- else if (RoomInvitation.ELEMENT_NAME.equals(elemName)) {
- RoomInvitation invitation = (RoomInvitation) PacketParserUtils
- .parsePacketExtension(RoomInvitation.ELEMENT_NAME, RoomInvitation.NAMESPACE, parser);
- content = new InvitationRequest(invitation.getInviter(), invitation.getRoom(),
- invitation.getReason());
- }
- else if (RoomTransfer.ELEMENT_NAME.equals(elemName)) {
- RoomTransfer transfer = (RoomTransfer) PacketParserUtils
- .parsePacketExtension(RoomTransfer.ELEMENT_NAME, RoomTransfer.NAMESPACE, parser);
- content = new TransferRequest(transfer.getInviter(), transfer.getRoom(), transfer.getReason());
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if ("offer".equals(parser.getName())) {
- done = true;
- }
- }
- }
-
- OfferRequestPacket offerRequest =
- new OfferRequestPacket(userJID, userID, timeout, metaData, sessionID, content);
- offerRequest.setType(IQ.Type.SET);
-
- return offerRequest;
- }
-
- public static class OfferRequestPacket extends IQ {
-
- private int timeout;
- private String userID;
- private String userJID;
- private Map<String, List<String>> metaData;
- private String sessionID;
- private OfferContent content;
-
- public OfferRequestPacket(String userJID, String userID, int timeout, Map<String, List<String>> metaData,
- String sessionID, OfferContent content)
- {
- this.userJID = userJID;
- this.userID = userID;
- this.timeout = timeout;
- this.metaData = metaData;
- this.sessionID = sessionID;
- this.content = content;
- }
-
- /**
- * Returns the userID, which is either the same as the userJID or a special
- * value that the user provided as part of their "join queue" request.
- *
- * @return the user ID.
- */
- public String getUserID() {
- return userID;
- }
-
- /**
- * The JID of the user that made the "join queue" request.
- *
- * @return the user JID.
- */
- public String getUserJID() {
- return userJID;
- }
-
- /**
- * Returns the session ID associated with the request and ensuing chat. If the offer
- * does not contain a session ID, <tt>null</tt> will be returned.
- *
- * @return the session id associated with the request.
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Returns the number of seconds the agent has to accept the offer before
- * it times out.
- *
- * @return the offer timeout (in seconds).
- */
- public int getTimeout() {
- return this.timeout;
- }
-
- public OfferContent getContent() {
- return content;
- }
-
- /**
- * Returns any meta-data associated with the offer.
- *
- * @return meta-data associated with the offer.
- */
- public Map<String, List<String>> getMetaData() {
- return this.metaData;
- }
-
- public String getChildElementXML () {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<offer xmlns=\"http://jabber.org/protocol/workgroup\" jid=\"").append(userJID).append("\">");
- buf.append("<timeout>").append(timeout).append("</timeout>");
-
- if (sessionID != null) {
- buf.append('<').append(SessionID.ELEMENT_NAME);
- buf.append(" session=\"");
- buf.append(getSessionID()).append("\" xmlns=\"");
- buf.append(SessionID.NAMESPACE).append("\"/>");
- }
-
- if (metaData != null) {
- buf.append(MetaDataUtils.serializeMetaData(metaData));
- }
-
- if (userID != null) {
- buf.append('<').append(UserID.ELEMENT_NAME);
- buf.append(" id=\"");
- buf.append(userID).append("\" xmlns=\"");
- buf.append(UserID.NAMESPACE).append("\"/>");
- }
-
- buf.append("</offer>");
-
- return buf.toString();
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smackx.workgroup.MetaData;
+import org.jivesoftware.smackx.workgroup.agent.InvitationRequest;
+import org.jivesoftware.smackx.workgroup.agent.OfferContent;
+import org.jivesoftware.smackx.workgroup.agent.TransferRequest;
+import org.jivesoftware.smackx.workgroup.agent.UserRequest;
+import org.jivesoftware.smackx.workgroup.util.MetaDataUtils;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An IQProvider for agent offer requests.
+ *
+ * @author loki der quaeler
+ */
+public class OfferRequestProvider implements IQProvider {
+
+ public OfferRequestProvider() {
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ int eventType = parser.getEventType();
+ String sessionID = null;
+ int timeout = -1;
+ OfferContent content = null;
+ boolean done = false;
+ Map<String, List<String>> metaData = new HashMap<String, List<String>>();
+
+ if (eventType != XmlPullParser.START_TAG) {
+ // throw exception
+ }
+
+ String userJID = parser.getAttributeValue("", "jid");
+ // Default userID to the JID.
+ String userID = userJID;
+
+ while (!done) {
+ eventType = parser.next();
+
+ if (eventType == XmlPullParser.START_TAG) {
+ String elemName = parser.getName();
+
+ if ("timeout".equals(elemName)) {
+ timeout = Integer.parseInt(parser.nextText());
+ }
+ else if (MetaData.ELEMENT_NAME.equals(elemName)) {
+ metaData = MetaDataUtils.parseMetaData(parser);
+ }
+ else if (SessionID.ELEMENT_NAME.equals(elemName)) {
+ sessionID = parser.getAttributeValue("", "id");
+ }
+ else if (UserID.ELEMENT_NAME.equals(elemName)) {
+ userID = parser.getAttributeValue("", "id");
+ }
+ else if ("user-request".equals(elemName)) {
+ content = UserRequest.getInstance();
+ }
+ else if (RoomInvitation.ELEMENT_NAME.equals(elemName)) {
+ RoomInvitation invitation = (RoomInvitation) PacketParserUtils
+ .parsePacketExtension(RoomInvitation.ELEMENT_NAME, RoomInvitation.NAMESPACE, parser);
+ content = new InvitationRequest(invitation.getInviter(), invitation.getRoom(),
+ invitation.getReason());
+ }
+ else if (RoomTransfer.ELEMENT_NAME.equals(elemName)) {
+ RoomTransfer transfer = (RoomTransfer) PacketParserUtils
+ .parsePacketExtension(RoomTransfer.ELEMENT_NAME, RoomTransfer.NAMESPACE, parser);
+ content = new TransferRequest(transfer.getInviter(), transfer.getRoom(), transfer.getReason());
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if ("offer".equals(parser.getName())) {
+ done = true;
+ }
+ }
+ }
+
+ OfferRequestPacket offerRequest =
+ new OfferRequestPacket(userJID, userID, timeout, metaData, sessionID, content);
+ offerRequest.setType(IQ.Type.SET);
+
+ return offerRequest;
+ }
+
+ public static class OfferRequestPacket extends IQ {
+
+ private int timeout;
+ private String userID;
+ private String userJID;
+ private Map<String, List<String>> metaData;
+ private String sessionID;
+ private OfferContent content;
+
+ public OfferRequestPacket(String userJID, String userID, int timeout, Map<String, List<String>> metaData,
+ String sessionID, OfferContent content)
+ {
+ this.userJID = userJID;
+ this.userID = userID;
+ this.timeout = timeout;
+ this.metaData = metaData;
+ this.sessionID = sessionID;
+ this.content = content;
+ }
+
+ /**
+ * Returns the userID, which is either the same as the userJID or a special
+ * value that the user provided as part of their "join queue" request.
+ *
+ * @return the user ID.
+ */
+ public String getUserID() {
+ return userID;
+ }
+
+ /**
+ * The JID of the user that made the "join queue" request.
+ *
+ * @return the user JID.
+ */
+ public String getUserJID() {
+ return userJID;
+ }
+
+ /**
+ * Returns the session ID associated with the request and ensuing chat. If the offer
+ * does not contain a session ID, <tt>null</tt> will be returned.
+ *
+ * @return the session id associated with the request.
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Returns the number of seconds the agent has to accept the offer before
+ * it times out.
+ *
+ * @return the offer timeout (in seconds).
+ */
+ public int getTimeout() {
+ return this.timeout;
+ }
+
+ public OfferContent getContent() {
+ return content;
+ }
+
+ /**
+ * Returns any meta-data associated with the offer.
+ *
+ * @return meta-data associated with the offer.
+ */
+ public Map<String, List<String>> getMetaData() {
+ return this.metaData;
+ }
+
+ public String getChildElementXML () {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<offer xmlns=\"http://jabber.org/protocol/workgroup\" jid=\"").append(userJID).append("\">");
+ buf.append("<timeout>").append(timeout).append("</timeout>");
+
+ if (sessionID != null) {
+ buf.append('<').append(SessionID.ELEMENT_NAME);
+ buf.append(" session=\"");
+ buf.append(getSessionID()).append("\" xmlns=\"");
+ buf.append(SessionID.NAMESPACE).append("\"/>");
+ }
+
+ if (metaData != null) {
+ buf.append(MetaDataUtils.serializeMetaData(metaData));
+ }
+
+ if (userID != null) {
+ buf.append('<').append(UserID.ELEMENT_NAME);
+ buf.append(" id=\"");
+ buf.append(userID).append("\" xmlns=\"");
+ buf.append(UserID.NAMESPACE).append("\"/>");
+ }
+
+ buf.append("</offer>");
+
+ return buf.toString();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRevokeProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRevokeProvider.java
index 202824c21..b3974b492 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRevokeProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/OfferRevokeProvider.java
@@ -1,112 +1,112 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * An IQProvider class which has savvy about the offer-revoke tag.<br>
- *
- * @author loki der quaeler
- */
-public class OfferRevokeProvider implements IQProvider {
-
- public IQ parseIQ (XmlPullParser parser) throws Exception {
- // The parser will be positioned on the opening IQ tag, so get the JID attribute.
- String userJID = parser.getAttributeValue("", "jid");
- // Default the userID to the JID.
- String userID = userJID;
- String reason = null;
- String sessionID = null;
- boolean done = false;
-
- while (!done) {
- int eventType = parser.next();
-
- if ((eventType == XmlPullParser.START_TAG) && parser.getName().equals("reason")) {
- reason = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG)
- && parser.getName().equals(SessionID.ELEMENT_NAME)) {
- sessionID = parser.getAttributeValue("", "id");
- }
- else if ((eventType == XmlPullParser.START_TAG)
- && parser.getName().equals(UserID.ELEMENT_NAME)) {
- userID = parser.getAttributeValue("", "id");
- }
- else if ((eventType == XmlPullParser.END_TAG) && parser.getName().equals(
- "offer-revoke"))
- {
- done = true;
- }
- }
-
- return new OfferRevokePacket(userJID, userID, reason, sessionID);
- }
-
- public class OfferRevokePacket extends IQ {
-
- private String userJID;
- private String userID;
- private String sessionID;
- private String reason;
-
- public OfferRevokePacket (String userJID, String userID, String cause, String sessionID) {
- this.userJID = userJID;
- this.userID = userID;
- this.reason = cause;
- this.sessionID = sessionID;
- }
-
- public String getUserJID() {
- return userJID;
- }
-
- public String getUserID() {
- return this.userID;
- }
-
- public String getReason() {
- return this.reason;
- }
-
- public String getSessionID() {
- return this.sessionID;
- }
-
- public String getChildElementXML () {
- StringBuilder buf = new StringBuilder();
- buf.append("<offer-revoke xmlns=\"http://jabber.org/protocol/workgroup\" jid=\"").append(userID).append("\">");
- if (reason != null) {
- buf.append("<reason>").append(reason).append("</reason>");
- }
- if (sessionID != null) {
- buf.append(new SessionID(sessionID).toXML());
- }
- if (userID != null) {
- buf.append(new UserID(userID).toXML());
- }
- buf.append("</offer-revoke>");
- return buf.toString();
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * An IQProvider class which has savvy about the offer-revoke tag.<br>
+ *
+ * @author loki der quaeler
+ */
+public class OfferRevokeProvider implements IQProvider {
+
+ public IQ parseIQ (XmlPullParser parser) throws Exception {
+ // The parser will be positioned on the opening IQ tag, so get the JID attribute.
+ String userJID = parser.getAttributeValue("", "jid");
+ // Default the userID to the JID.
+ String userID = userJID;
+ String reason = null;
+ String sessionID = null;
+ boolean done = false;
+
+ while (!done) {
+ int eventType = parser.next();
+
+ if ((eventType == XmlPullParser.START_TAG) && parser.getName().equals("reason")) {
+ reason = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG)
+ && parser.getName().equals(SessionID.ELEMENT_NAME)) {
+ sessionID = parser.getAttributeValue("", "id");
+ }
+ else if ((eventType == XmlPullParser.START_TAG)
+ && parser.getName().equals(UserID.ELEMENT_NAME)) {
+ userID = parser.getAttributeValue("", "id");
+ }
+ else if ((eventType == XmlPullParser.END_TAG) && parser.getName().equals(
+ "offer-revoke"))
+ {
+ done = true;
+ }
+ }
+
+ return new OfferRevokePacket(userJID, userID, reason, sessionID);
+ }
+
+ public class OfferRevokePacket extends IQ {
+
+ private String userJID;
+ private String userID;
+ private String sessionID;
+ private String reason;
+
+ public OfferRevokePacket (String userJID, String userID, String cause, String sessionID) {
+ this.userJID = userJID;
+ this.userID = userID;
+ this.reason = cause;
+ this.sessionID = sessionID;
+ }
+
+ public String getUserJID() {
+ return userJID;
+ }
+
+ public String getUserID() {
+ return this.userID;
+ }
+
+ public String getReason() {
+ return this.reason;
+ }
+
+ public String getSessionID() {
+ return this.sessionID;
+ }
+
+ public String getChildElementXML () {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<offer-revoke xmlns=\"http://jabber.org/protocol/workgroup\" jid=\"").append(userID).append("\">");
+ if (reason != null) {
+ buf.append("<reason>").append(reason).append("</reason>");
+ }
+ if (sessionID != null) {
+ buf.append(new SessionID(sessionID).toXML());
+ }
+ if (userID != null) {
+ buf.append(new UserID(userID).toXML());
+ }
+ buf.append("</offer-revoke>");
+ return buf.toString();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java
index 86b3673e8..2a7fe3bdc 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java
@@ -1,199 +1,199 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smackx.workgroup.QueueUser;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-/**
- * Queue details packet extension, which contains details about the users
- * currently in a queue.
- */
-public class QueueDetails implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "notify-queue-details";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
-
- private static final String DATE_FORMAT = "yyyyMMdd'T'HH:mm:ss";
-
- private SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
- /**
- * The list of users in the queue.
- */
- private Set<QueueUser> users;
-
- /**
- * Creates a new QueueDetails packet
- */
- private QueueDetails() {
- users = new HashSet<QueueUser>();
- }
-
- /**
- * Returns the number of users currently in the queue that are waiting to
- * be routed to an agent.
- *
- * @return the number of users in the queue.
- */
- public int getUserCount() {
- return users.size();
- }
-
- /**
- * Returns the set of users in the queue that are waiting to
- * be routed to an agent (as QueueUser objects).
- *
- * @return a Set for the users waiting in a queue.
- */
- public Set<QueueUser> getUsers() {
- synchronized (users) {
- return users;
- }
- }
-
- /**
- * Adds a user to the packet.
- *
- * @param user the user.
- */
- private void addUser(QueueUser user) {
- synchronized (users) {
- users.add(user);
- }
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
-
- synchronized (users) {
- for (Iterator<QueueUser> i=users.iterator(); i.hasNext(); ) {
- QueueUser user = (QueueUser)i.next();
- int position = user.getQueuePosition();
- int timeRemaining = user.getEstimatedRemainingTime();
- Date timestamp = user.getQueueJoinTimestamp();
-
- buf.append("<user jid=\"").append(user.getUserID()).append("\">");
-
- if (position != -1) {
- buf.append("<position>").append(position).append("</position>");
- }
-
- if (timeRemaining != -1) {
- buf.append("<time>").append(timeRemaining).append("</time>");
- }
-
- if (timestamp != null) {
- buf.append("<join-time>");
- buf.append(dateFormat.format(timestamp));
- buf.append("</join-time>");
- }
-
- buf.append("</user>");
- }
- }
- buf.append("</").append(ELEMENT_NAME).append(">");
- return buf.toString();
- }
-
- /**
- * Provider class for QueueDetails packet extensions.
- */
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
-
- SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
- QueueDetails queueDetails = new QueueDetails();
-
- int eventType = parser.getEventType();
- while (eventType != XmlPullParser.END_TAG &&
- "notify-queue-details".equals(parser.getName()))
- {
- eventType = parser.next();
- while ((eventType == XmlPullParser.START_TAG) && "user".equals(parser.getName())) {
- String uid = null;
- int position = -1;
- int time = -1;
- Date joinTime = null;
-
- uid = parser.getAttributeValue("", "jid");
-
- if (uid == null) {
- // throw exception
- }
-
- eventType = parser.next();
- while ((eventType != XmlPullParser.END_TAG)
- || (! "user".equals(parser.getName())))
- {
- if ("position".equals(parser.getName())) {
- position = Integer.parseInt(parser.nextText());
- }
- else if ("time".equals(parser.getName())) {
- time = Integer.parseInt(parser.nextText());
- }
- else if ("join-time".equals(parser.getName())) {
- joinTime = dateFormat.parse(parser.nextText());
- }
- else if( parser.getName().equals( "waitTime" ) ) {
- Date wait = dateFormat.parse(parser.nextText());
- System.out.println( wait );
- }
-
- eventType = parser.next();
-
- if (eventType != XmlPullParser.END_TAG) {
- // throw exception
- }
- }
-
- queueDetails.addUser(new QueueUser(uid, position, time, joinTime));
-
- eventType = parser.next();
- }
- }
- return queueDetails;
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smackx.workgroup.QueueUser;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Queue details packet extension, which contains details about the users
+ * currently in a queue.
+ */
+public class QueueDetails implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "notify-queue-details";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
+
+ private static final String DATE_FORMAT = "yyyyMMdd'T'HH:mm:ss";
+
+ private SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+ /**
+ * The list of users in the queue.
+ */
+ private Set<QueueUser> users;
+
+ /**
+ * Creates a new QueueDetails packet
+ */
+ private QueueDetails() {
+ users = new HashSet<QueueUser>();
+ }
+
+ /**
+ * Returns the number of users currently in the queue that are waiting to
+ * be routed to an agent.
+ *
+ * @return the number of users in the queue.
+ */
+ public int getUserCount() {
+ return users.size();
+ }
+
+ /**
+ * Returns the set of users in the queue that are waiting to
+ * be routed to an agent (as QueueUser objects).
+ *
+ * @return a Set for the users waiting in a queue.
+ */
+ public Set<QueueUser> getUsers() {
+ synchronized (users) {
+ return users;
+ }
+ }
+
+ /**
+ * Adds a user to the packet.
+ *
+ * @param user the user.
+ */
+ private void addUser(QueueUser user) {
+ synchronized (users) {
+ users.add(user);
+ }
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+
+ synchronized (users) {
+ for (Iterator<QueueUser> i=users.iterator(); i.hasNext(); ) {
+ QueueUser user = (QueueUser)i.next();
+ int position = user.getQueuePosition();
+ int timeRemaining = user.getEstimatedRemainingTime();
+ Date timestamp = user.getQueueJoinTimestamp();
+
+ buf.append("<user jid=\"").append(user.getUserID()).append("\">");
+
+ if (position != -1) {
+ buf.append("<position>").append(position).append("</position>");
+ }
+
+ if (timeRemaining != -1) {
+ buf.append("<time>").append(timeRemaining).append("</time>");
+ }
+
+ if (timestamp != null) {
+ buf.append("<join-time>");
+ buf.append(dateFormat.format(timestamp));
+ buf.append("</join-time>");
+ }
+
+ buf.append("</user>");
+ }
+ }
+ buf.append("</").append(ELEMENT_NAME).append(">");
+ return buf.toString();
+ }
+
+ /**
+ * Provider class for QueueDetails packet extensions.
+ */
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+
+ SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+ QueueDetails queueDetails = new QueueDetails();
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_TAG &&
+ "notify-queue-details".equals(parser.getName()))
+ {
+ eventType = parser.next();
+ while ((eventType == XmlPullParser.START_TAG) && "user".equals(parser.getName())) {
+ String uid = null;
+ int position = -1;
+ int time = -1;
+ Date joinTime = null;
+
+ uid = parser.getAttributeValue("", "jid");
+
+ if (uid == null) {
+ // throw exception
+ }
+
+ eventType = parser.next();
+ while ((eventType != XmlPullParser.END_TAG)
+ || (! "user".equals(parser.getName())))
+ {
+ if ("position".equals(parser.getName())) {
+ position = Integer.parseInt(parser.nextText());
+ }
+ else if ("time".equals(parser.getName())) {
+ time = Integer.parseInt(parser.nextText());
+ }
+ else if ("join-time".equals(parser.getName())) {
+ joinTime = dateFormat.parse(parser.nextText());
+ }
+ else if( parser.getName().equals( "waitTime" ) ) {
+ Date wait = dateFormat.parse(parser.nextText());
+ System.out.println( wait );
+ }
+
+ eventType = parser.next();
+
+ if (eventType != XmlPullParser.END_TAG) {
+ // throw exception
+ }
+ }
+
+ queueDetails.addUser(new QueueUser(uid, position, time, joinTime));
+
+ eventType = parser.next();
+ }
+ }
+ return queueDetails;
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java
index a559579b4..c97473c54 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java
@@ -1,160 +1,160 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smackx.workgroup.agent.WorkgroupQueue;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public class QueueOverview implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static String ELEMENT_NAME = "notify-queue";
-
- /**
- * Namespace of the packet extension.
- */
- public static String NAMESPACE = "http://jabber.org/protocol/workgroup";
-
- private static final String DATE_FORMAT = "yyyyMMdd'T'HH:mm:ss";
- private SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
-
- private int averageWaitTime;
- private Date oldestEntry;
- private int userCount;
- private WorkgroupQueue.Status status;
-
- QueueOverview() {
- this.averageWaitTime = -1;
- this.oldestEntry = null;
- this.userCount = -1;
- this.status = null;
- }
-
- void setAverageWaitTime(int averageWaitTime) {
- this.averageWaitTime = averageWaitTime;
- }
-
- public int getAverageWaitTime () {
- return averageWaitTime;
- }
-
- void setOldestEntry(Date oldestEntry) {
- this.oldestEntry = oldestEntry;
- }
-
- public Date getOldestEntry() {
- return oldestEntry;
- }
-
- void setUserCount(int userCount) {
- this.userCount = userCount;
- }
-
- public int getUserCount() {
- return userCount;
- }
-
- public WorkgroupQueue.Status getStatus() {
- return status;
- }
-
- void setStatus(WorkgroupQueue.Status status) {
- this.status = status;
- }
-
- public String getElementName () {
- return ELEMENT_NAME;
- }
-
- public String getNamespace () {
- return NAMESPACE;
- }
-
- public String toXML () {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
-
- if (userCount != -1) {
- buf.append("<count>").append(userCount).append("</count>");
- }
- if (oldestEntry != null) {
- buf.append("<oldest>").append(dateFormat.format(oldestEntry)).append("</oldest>");
- }
- if (averageWaitTime != -1) {
- buf.append("<time>").append(averageWaitTime).append("</time>");
- }
- if (status != null) {
- buf.append("<status>").append(status).append("</status>");
- }
- buf.append("</").append(ELEMENT_NAME).append(">");
-
- return buf.toString();
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension (XmlPullParser parser) throws Exception {
- int eventType = parser.getEventType();
- QueueOverview queueOverview = new QueueOverview();
- SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
-
- if (eventType != XmlPullParser.START_TAG) {
- // throw exception
- }
-
- eventType = parser.next();
- while ((eventType != XmlPullParser.END_TAG)
- || (!ELEMENT_NAME.equals(parser.getName())))
- {
- if ("count".equals(parser.getName())) {
- queueOverview.setUserCount(Integer.parseInt(parser.nextText()));
- }
- else if ("time".equals(parser.getName())) {
- queueOverview.setAverageWaitTime(Integer.parseInt(parser.nextText()));
- }
- else if ("oldest".equals(parser.getName())) {
- queueOverview.setOldestEntry((dateFormat.parse(parser.nextText())));
- }
- else if ("status".equals(parser.getName())) {
- queueOverview.setStatus(WorkgroupQueue.Status.fromString(parser.nextText()));
- }
-
- eventType = parser.next();
-
- if (eventType != XmlPullParser.END_TAG) {
- // throw exception
- }
- }
-
- if (eventType != XmlPullParser.END_TAG) {
- // throw exception
- }
-
- return queueOverview;
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smackx.workgroup.agent.WorkgroupQueue;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class QueueOverview implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static String ELEMENT_NAME = "notify-queue";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static String NAMESPACE = "http://jabber.org/protocol/workgroup";
+
+ private static final String DATE_FORMAT = "yyyyMMdd'T'HH:mm:ss";
+ private SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+
+ private int averageWaitTime;
+ private Date oldestEntry;
+ private int userCount;
+ private WorkgroupQueue.Status status;
+
+ QueueOverview() {
+ this.averageWaitTime = -1;
+ this.oldestEntry = null;
+ this.userCount = -1;
+ this.status = null;
+ }
+
+ void setAverageWaitTime(int averageWaitTime) {
+ this.averageWaitTime = averageWaitTime;
+ }
+
+ public int getAverageWaitTime () {
+ return averageWaitTime;
+ }
+
+ void setOldestEntry(Date oldestEntry) {
+ this.oldestEntry = oldestEntry;
+ }
+
+ public Date getOldestEntry() {
+ return oldestEntry;
+ }
+
+ void setUserCount(int userCount) {
+ this.userCount = userCount;
+ }
+
+ public int getUserCount() {
+ return userCount;
+ }
+
+ public WorkgroupQueue.Status getStatus() {
+ return status;
+ }
+
+ void setStatus(WorkgroupQueue.Status status) {
+ this.status = status;
+ }
+
+ public String getElementName () {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace () {
+ return NAMESPACE;
+ }
+
+ public String toXML () {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+
+ if (userCount != -1) {
+ buf.append("<count>").append(userCount).append("</count>");
+ }
+ if (oldestEntry != null) {
+ buf.append("<oldest>").append(dateFormat.format(oldestEntry)).append("</oldest>");
+ }
+ if (averageWaitTime != -1) {
+ buf.append("<time>").append(averageWaitTime).append("</time>");
+ }
+ if (status != null) {
+ buf.append("<status>").append(status).append("</status>");
+ }
+ buf.append("</").append(ELEMENT_NAME).append(">");
+
+ return buf.toString();
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension (XmlPullParser parser) throws Exception {
+ int eventType = parser.getEventType();
+ QueueOverview queueOverview = new QueueOverview();
+ SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+
+ if (eventType != XmlPullParser.START_TAG) {
+ // throw exception
+ }
+
+ eventType = parser.next();
+ while ((eventType != XmlPullParser.END_TAG)
+ || (!ELEMENT_NAME.equals(parser.getName())))
+ {
+ if ("count".equals(parser.getName())) {
+ queueOverview.setUserCount(Integer.parseInt(parser.nextText()));
+ }
+ else if ("time".equals(parser.getName())) {
+ queueOverview.setAverageWaitTime(Integer.parseInt(parser.nextText()));
+ }
+ else if ("oldest".equals(parser.getName())) {
+ queueOverview.setOldestEntry((dateFormat.parse(parser.nextText())));
+ }
+ else if ("status".equals(parser.getName())) {
+ queueOverview.setStatus(WorkgroupQueue.Status.fromString(parser.nextText()));
+ }
+
+ eventType = parser.next();
+
+ if (eventType != XmlPullParser.END_TAG) {
+ // throw exception
+ }
+ }
+
+ if (eventType != XmlPullParser.END_TAG) {
+ // throw exception
+ }
+
+ return queueOverview;
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueUpdate.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueUpdate.java
index c326a570c..828f6bb78 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueUpdate.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/QueueUpdate.java
@@ -1,122 +1,122 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * An IQ packet that encapsulates both types of workgroup queue
- * status notifications -- position updates, and estimated time
- * left in the queue updates.
- */
-public class QueueUpdate implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "queue-status";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
-
- private int position;
- private int remainingTime;
-
- public QueueUpdate(int position, int remainingTime) {
- this.position = position;
- this.remainingTime = remainingTime;
- }
-
- /**
- * Returns the user's position in the workgroup queue, or -1 if the
- * value isn't set on this packet.
- *
- * @return the position in the workgroup queue.
- */
- public int getPosition() {
- return this.position;
- }
-
- /**
- * Returns the user's estimated time left in the workgroup queue, or
- * -1 if the value isn't set on this packet.
- *
- * @return the estimated time left in the workgroup queue.
- */
- public int getRemaingTime() {
- return remainingTime;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<queue-status xmlns=\"http://jabber.org/protocol/workgroup\">");
- if (position != -1) {
- buf.append("<position>").append(position).append("</position>");
- }
- if (remainingTime != -1) {
- buf.append("<time>").append(remainingTime).append("</time>");
- }
- buf.append("</queue-status>");
- return buf.toString();
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- boolean done = false;
- int position = -1;
- int timeRemaining = -1;
- while (!done) {
- parser.next();
- String elementName = parser.getName();
- if (parser.getEventType() == XmlPullParser.START_TAG && "position".equals(elementName)) {
- try {
- position = Integer.parseInt(parser.nextText());
- }
- catch (NumberFormatException nfe) {
- }
- }
- else if (parser.getEventType() == XmlPullParser.START_TAG && "time".equals(elementName)) {
- try {
- timeRemaining = Integer.parseInt(parser.nextText());
- }
- catch (NumberFormatException nfe) {
- }
- }
- else if (parser.getEventType() == XmlPullParser.END_TAG && "queue-status".equals(elementName)) {
- done = true;
- }
- }
- return new QueueUpdate(position, timeRemaining);
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * An IQ packet that encapsulates both types of workgroup queue
+ * status notifications -- position updates, and estimated time
+ * left in the queue updates.
+ */
+public class QueueUpdate implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "queue-status";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
+
+ private int position;
+ private int remainingTime;
+
+ public QueueUpdate(int position, int remainingTime) {
+ this.position = position;
+ this.remainingTime = remainingTime;
+ }
+
+ /**
+ * Returns the user's position in the workgroup queue, or -1 if the
+ * value isn't set on this packet.
+ *
+ * @return the position in the workgroup queue.
+ */
+ public int getPosition() {
+ return this.position;
+ }
+
+ /**
+ * Returns the user's estimated time left in the workgroup queue, or
+ * -1 if the value isn't set on this packet.
+ *
+ * @return the estimated time left in the workgroup queue.
+ */
+ public int getRemaingTime() {
+ return remainingTime;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<queue-status xmlns=\"http://jabber.org/protocol/workgroup\">");
+ if (position != -1) {
+ buf.append("<position>").append(position).append("</position>");
+ }
+ if (remainingTime != -1) {
+ buf.append("<time>").append(remainingTime).append("</time>");
+ }
+ buf.append("</queue-status>");
+ return buf.toString();
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ boolean done = false;
+ int position = -1;
+ int timeRemaining = -1;
+ while (!done) {
+ parser.next();
+ String elementName = parser.getName();
+ if (parser.getEventType() == XmlPullParser.START_TAG && "position".equals(elementName)) {
+ try {
+ position = Integer.parseInt(parser.nextText());
+ }
+ catch (NumberFormatException nfe) {
+ }
+ }
+ else if (parser.getEventType() == XmlPullParser.START_TAG && "time".equals(elementName)) {
+ try {
+ timeRemaining = Integer.parseInt(parser.nextText());
+ }
+ catch (NumberFormatException nfe) {
+ }
+ }
+ else if (parser.getEventType() == XmlPullParser.END_TAG && "queue-status".equals(elementName)) {
+ done = true;
+ }
+ }
+ return new QueueUpdate(position, timeRemaining);
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomInvitation.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomInvitation.java
index 34555dec7..1a6ec9cc7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomInvitation.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomInvitation.java
@@ -1,177 +1,177 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Packet extension for {@link org.jivesoftware.smackx.workgroup.agent.InvitationRequest}.
- *
- * @author Gaston Dombiak
- */
-public class RoomInvitation implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "invite";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
-
- /**
- * Type of entity being invited to a groupchat support session.
- */
- private Type type;
- /**
- * JID of the entity being invited. The entity could be another agent, user , a queue or a workgroup. In
- * the case of a queue or a workgroup the server will select the best agent to invite.
- */
- private String invitee;
- /**
- * Full JID of the user that sent the invitation.
- */
- private String inviter;
- /**
- * ID of the session that originated the initial user request.
- */
- private String sessionID;
- /**
- * JID of the room to join if offer is accepted.
- */
- private String room;
- /**
- * Text provided by the inviter explaining the reason why the invitee is invited.
- */
- private String reason;
-
- public RoomInvitation(Type type, String invitee, String sessionID, String reason) {
- this.type = type;
- this.invitee = invitee;
- this.sessionID = sessionID;
- this.reason = reason;
- }
-
- private RoomInvitation() {
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String getInviter() {
- return inviter;
- }
-
- public String getRoom() {
- return room;
- }
-
- public String getReason() {
- return reason;
- }
-
- public String getSessionID() {
- return sessionID;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE);
- buf.append("\" type=\"").append(type).append("\">");
- buf.append("<session xmlns=\"http://jivesoftware.com/protocol/workgroup\" id=\"").append(sessionID).append("\"></session>");
- if (invitee != null) {
- buf.append("<invitee>").append(invitee).append("</invitee>");
- }
- if (inviter != null) {
- buf.append("<inviter>").append(inviter).append("</inviter>");
- }
- if (reason != null) {
- buf.append("<reason>").append(reason).append("</reason>");
- }
- // Add packet extensions, if any are defined.
- buf.append("</").append(ELEMENT_NAME).append("> ");
-
- return buf.toString();
- }
-
- /**
- * Type of entity being invited to a groupchat support session.
- */
- public static enum Type {
- /**
- * A user is being invited to a groupchat support session. The user could be another agent
- * or just a regular XMPP user.
- */
- user,
- /**
- * Some agent of the specified queue will be invited to the groupchat support session.
- */
- queue,
- /**
- * Some agent of the specified workgroup will be invited to the groupchat support session.
- */
- workgroup
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- final RoomInvitation invitation = new RoomInvitation();
- invitation.type = Type.valueOf(parser.getAttributeValue("", "type"));
-
- boolean done = false;
- while (!done) {
- parser.next();
- String elementName = parser.getName();
- if (parser.getEventType() == XmlPullParser.START_TAG) {
- if ("session".equals(elementName)) {
- invitation.sessionID = parser.getAttributeValue("", "id");
- }
- else if ("invitee".equals(elementName)) {
- invitation.invitee = parser.nextText();
- }
- else if ("inviter".equals(elementName)) {
- invitation.inviter = parser.nextText();
- }
- else if ("reason".equals(elementName)) {
- invitation.reason = parser.nextText();
- }
- else if ("room".equals(elementName)) {
- invitation.room = parser.nextText();
- }
- }
- else if (parser.getEventType() == XmlPullParser.END_TAG && ELEMENT_NAME.equals(elementName)) {
- done = true;
- }
- }
- return invitation;
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Packet extension for {@link org.jivesoftware.smackx.workgroup.agent.InvitationRequest}.
+ *
+ * @author Gaston Dombiak
+ */
+public class RoomInvitation implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "invite";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
+
+ /**
+ * Type of entity being invited to a groupchat support session.
+ */
+ private Type type;
+ /**
+ * JID of the entity being invited. The entity could be another agent, user , a queue or a workgroup. In
+ * the case of a queue or a workgroup the server will select the best agent to invite.
+ */
+ private String invitee;
+ /**
+ * Full JID of the user that sent the invitation.
+ */
+ private String inviter;
+ /**
+ * ID of the session that originated the initial user request.
+ */
+ private String sessionID;
+ /**
+ * JID of the room to join if offer is accepted.
+ */
+ private String room;
+ /**
+ * Text provided by the inviter explaining the reason why the invitee is invited.
+ */
+ private String reason;
+
+ public RoomInvitation(Type type, String invitee, String sessionID, String reason) {
+ this.type = type;
+ this.invitee = invitee;
+ this.sessionID = sessionID;
+ this.reason = reason;
+ }
+
+ private RoomInvitation() {
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getInviter() {
+ return inviter;
+ }
+
+ public String getRoom() {
+ return room;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE);
+ buf.append("\" type=\"").append(type).append("\">");
+ buf.append("<session xmlns=\"http://jivesoftware.com/protocol/workgroup\" id=\"").append(sessionID).append("\"></session>");
+ if (invitee != null) {
+ buf.append("<invitee>").append(invitee).append("</invitee>");
+ }
+ if (inviter != null) {
+ buf.append("<inviter>").append(inviter).append("</inviter>");
+ }
+ if (reason != null) {
+ buf.append("<reason>").append(reason).append("</reason>");
+ }
+ // Add packet extensions, if any are defined.
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * Type of entity being invited to a groupchat support session.
+ */
+ public static enum Type {
+ /**
+ * A user is being invited to a groupchat support session. The user could be another agent
+ * or just a regular XMPP user.
+ */
+ user,
+ /**
+ * Some agent of the specified queue will be invited to the groupchat support session.
+ */
+ queue,
+ /**
+ * Some agent of the specified workgroup will be invited to the groupchat support session.
+ */
+ workgroup
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ final RoomInvitation invitation = new RoomInvitation();
+ invitation.type = Type.valueOf(parser.getAttributeValue("", "type"));
+
+ boolean done = false;
+ while (!done) {
+ parser.next();
+ String elementName = parser.getName();
+ if (parser.getEventType() == XmlPullParser.START_TAG) {
+ if ("session".equals(elementName)) {
+ invitation.sessionID = parser.getAttributeValue("", "id");
+ }
+ else if ("invitee".equals(elementName)) {
+ invitation.invitee = parser.nextText();
+ }
+ else if ("inviter".equals(elementName)) {
+ invitation.inviter = parser.nextText();
+ }
+ else if ("reason".equals(elementName)) {
+ invitation.reason = parser.nextText();
+ }
+ else if ("room".equals(elementName)) {
+ invitation.room = parser.nextText();
+ }
+ }
+ else if (parser.getEventType() == XmlPullParser.END_TAG && ELEMENT_NAME.equals(elementName)) {
+ done = true;
+ }
+ }
+ return invitation;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomTransfer.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomTransfer.java
index d1e83e24f..54362e406 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomTransfer.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/RoomTransfer.java
@@ -1,177 +1,177 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Packet extension for {@link org.jivesoftware.smackx.workgroup.agent.TransferRequest}.
- *
- * @author Gaston Dombiak
- */
-public class RoomTransfer implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "transfer";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
-
- /**
- * Type of entity being invited to a groupchat support session.
- */
- private RoomTransfer.Type type;
- /**
- * JID of the entity being invited. The entity could be another agent, user , a queue or a workgroup. In
- * the case of a queue or a workgroup the server will select the best agent to invite.
- */
- private String invitee;
- /**
- * Full JID of the user that sent the invitation.
- */
- private String inviter;
- /**
- * ID of the session that originated the initial user request.
- */
- private String sessionID;
- /**
- * JID of the room to join if offer is accepted.
- */
- private String room;
- /**
- * Text provided by the inviter explaining the reason why the invitee is invited.
- */
- private String reason;
-
- public RoomTransfer(RoomTransfer.Type type, String invitee, String sessionID, String reason) {
- this.type = type;
- this.invitee = invitee;
- this.sessionID = sessionID;
- this.reason = reason;
- }
-
- private RoomTransfer() {
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String getInviter() {
- return inviter;
- }
-
- public String getRoom() {
- return room;
- }
-
- public String getReason() {
- return reason;
- }
-
- public String getSessionID() {
- return sessionID;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE);
- buf.append("\" type=\"").append(type).append("\">");
- buf.append("<session xmlns=\"http://jivesoftware.com/protocol/workgroup\" id=\"").append(sessionID).append("\"></session>");
- if (invitee != null) {
- buf.append("<invitee>").append(invitee).append("</invitee>");
- }
- if (inviter != null) {
- buf.append("<inviter>").append(inviter).append("</inviter>");
- }
- if (reason != null) {
- buf.append("<reason>").append(reason).append("</reason>");
- }
- // Add packet extensions, if any are defined.
- buf.append("</").append(ELEMENT_NAME).append("> ");
-
- return buf.toString();
- }
-
- /**
- * Type of entity being invited to a groupchat support session.
- */
- public static enum Type {
- /**
- * A user is being invited to a groupchat support session. The user could be another agent
- * or just a regular XMPP user.
- */
- user,
- /**
- * Some agent of the specified queue will be invited to the groupchat support session.
- */
- queue,
- /**
- * Some agent of the specified workgroup will be invited to the groupchat support session.
- */
- workgroup
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- final RoomTransfer invitation = new RoomTransfer();
- invitation.type = RoomTransfer.Type.valueOf(parser.getAttributeValue("", "type"));
-
- boolean done = false;
- while (!done) {
- parser.next();
- String elementName = parser.getName();
- if (parser.getEventType() == XmlPullParser.START_TAG) {
- if ("session".equals(elementName)) {
- invitation.sessionID = parser.getAttributeValue("", "id");
- }
- else if ("invitee".equals(elementName)) {
- invitation.invitee = parser.nextText();
- }
- else if ("inviter".equals(elementName)) {
- invitation.inviter = parser.nextText();
- }
- else if ("reason".equals(elementName)) {
- invitation.reason = parser.nextText();
- }
- else if ("room".equals(elementName)) {
- invitation.room = parser.nextText();
- }
- }
- else if (parser.getEventType() == XmlPullParser.END_TAG && ELEMENT_NAME.equals(elementName)) {
- done = true;
- }
- }
- return invitation;
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Packet extension for {@link org.jivesoftware.smackx.workgroup.agent.TransferRequest}.
+ *
+ * @author Gaston Dombiak
+ */
+public class RoomTransfer implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "transfer";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
+
+ /**
+ * Type of entity being invited to a groupchat support session.
+ */
+ private RoomTransfer.Type type;
+ /**
+ * JID of the entity being invited. The entity could be another agent, user , a queue or a workgroup. In
+ * the case of a queue or a workgroup the server will select the best agent to invite.
+ */
+ private String invitee;
+ /**
+ * Full JID of the user that sent the invitation.
+ */
+ private String inviter;
+ /**
+ * ID of the session that originated the initial user request.
+ */
+ private String sessionID;
+ /**
+ * JID of the room to join if offer is accepted.
+ */
+ private String room;
+ /**
+ * Text provided by the inviter explaining the reason why the invitee is invited.
+ */
+ private String reason;
+
+ public RoomTransfer(RoomTransfer.Type type, String invitee, String sessionID, String reason) {
+ this.type = type;
+ this.invitee = invitee;
+ this.sessionID = sessionID;
+ this.reason = reason;
+ }
+
+ private RoomTransfer() {
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getInviter() {
+ return inviter;
+ }
+
+ public String getRoom() {
+ return room;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE);
+ buf.append("\" type=\"").append(type).append("\">");
+ buf.append("<session xmlns=\"http://jivesoftware.com/protocol/workgroup\" id=\"").append(sessionID).append("\"></session>");
+ if (invitee != null) {
+ buf.append("<invitee>").append(invitee).append("</invitee>");
+ }
+ if (inviter != null) {
+ buf.append("<inviter>").append(inviter).append("</inviter>");
+ }
+ if (reason != null) {
+ buf.append("<reason>").append(reason).append("</reason>");
+ }
+ // Add packet extensions, if any are defined.
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * Type of entity being invited to a groupchat support session.
+ */
+ public static enum Type {
+ /**
+ * A user is being invited to a groupchat support session. The user could be another agent
+ * or just a regular XMPP user.
+ */
+ user,
+ /**
+ * Some agent of the specified queue will be invited to the groupchat support session.
+ */
+ queue,
+ /**
+ * Some agent of the specified workgroup will be invited to the groupchat support session.
+ */
+ workgroup
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ final RoomTransfer invitation = new RoomTransfer();
+ invitation.type = RoomTransfer.Type.valueOf(parser.getAttributeValue("", "type"));
+
+ boolean done = false;
+ while (!done) {
+ parser.next();
+ String elementName = parser.getName();
+ if (parser.getEventType() == XmlPullParser.START_TAG) {
+ if ("session".equals(elementName)) {
+ invitation.sessionID = parser.getAttributeValue("", "id");
+ }
+ else if ("invitee".equals(elementName)) {
+ invitation.invitee = parser.nextText();
+ }
+ else if ("inviter".equals(elementName)) {
+ invitation.inviter = parser.nextText();
+ }
+ else if ("reason".equals(elementName)) {
+ invitation.reason = parser.nextText();
+ }
+ else if ("room".equals(elementName)) {
+ invitation.room = parser.nextText();
+ }
+ }
+ else if (parser.getEventType() == XmlPullParser.END_TAG && ELEMENT_NAME.equals(elementName)) {
+ done = true;
+ }
+ }
+ return invitation;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/SessionID.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/SessionID.java
index bfd7cfd72..1930532c9 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/SessionID.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/SessionID.java
@@ -1,77 +1,77 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-public class SessionID implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "session";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- private String sessionID;
-
- public SessionID(String sessionID) {
- this.sessionID = sessionID;
- }
-
- public String getSessionID() {
- return this.sessionID;
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\" ");
- buf.append("id=\"").append(this.getSessionID());
- buf.append("\"/>");
-
- return buf.toString();
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- String sessionID = parser.getAttributeValue("", "id");
-
- // Advance to end of extension.
- parser.next();
-
- return new SessionID(sessionID);
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+public class SessionID implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "session";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ private String sessionID;
+
+ public SessionID(String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+ public String getSessionID() {
+ return this.sessionID;
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\" ");
+ buf.append("id=\"").append(this.getSessionID());
+ buf.append("\"/>");
+
+ return buf.toString();
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ String sessionID = parser.getAttributeValue("", "id");
+
+ // Advance to end of extension.
+ parser.next();
+
+ return new SessionID(sessionID);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcript.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcript.java
index 7f8f29e58..6ccd740cc 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcript.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcript.java
@@ -1,98 +1,98 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Represents the conversation transcript that occured in a group chat room between an Agent
- * and a user that requested assistance. The transcript contains all the Messages that were sent
- * to the room as well as the sent presences.
- *
- * @author Gaston Dombiak
- */
-public class Transcript extends IQ {
- private String sessionID;
- private List<Packet> packets;
-
- /**
- * Creates a transcript request for the given sessionID.
- *
- * @param sessionID the id of the session to get the conversation transcript.
- */
- public Transcript(String sessionID) {
- this.sessionID = sessionID;
- this.packets = new ArrayList<Packet>();
- }
-
- /**
- * Creates a new transcript for the given sessionID and list of packets. The list of packets
- * may include Messages and/or Presences.
- *
- * @param sessionID the id of the session that generated this conversation transcript.
- * @param packets the list of messages and presences send to the room.
- */
- public Transcript(String sessionID, List<Packet> packets) {
- this.sessionID = sessionID;
- this.packets = packets;
- }
-
- /**
- * Returns id of the session that generated this conversation transcript. The sessionID is a
- * value generated by the server when a new request is received.
- *
- * @return id of the session that generated this conversation transcript.
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Returns the list of Messages and Presences that were sent to the room.
- *
- * @return the list of Messages and Presences that were sent to the room.
- */
- public List<Packet> getPackets() {
- return Collections.unmodifiableList(packets);
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<transcript xmlns=\"http://jivesoftware.com/protocol/workgroup\" sessionID=\"")
- .append(sessionID)
- .append("\">");
-
- for (Iterator<Packet> it=packets.iterator(); it.hasNext();) {
- Packet packet = it.next();
- buf.append(packet.toXML());
- }
-
- buf.append("</transcript>");
-
- return buf.toString();
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Represents the conversation transcript that occured in a group chat room between an Agent
+ * and a user that requested assistance. The transcript contains all the Messages that were sent
+ * to the room as well as the sent presences.
+ *
+ * @author Gaston Dombiak
+ */
+public class Transcript extends IQ {
+ private String sessionID;
+ private List<Packet> packets;
+
+ /**
+ * Creates a transcript request for the given sessionID.
+ *
+ * @param sessionID the id of the session to get the conversation transcript.
+ */
+ public Transcript(String sessionID) {
+ this.sessionID = sessionID;
+ this.packets = new ArrayList<Packet>();
+ }
+
+ /**
+ * Creates a new transcript for the given sessionID and list of packets. The list of packets
+ * may include Messages and/or Presences.
+ *
+ * @param sessionID the id of the session that generated this conversation transcript.
+ * @param packets the list of messages and presences send to the room.
+ */
+ public Transcript(String sessionID, List<Packet> packets) {
+ this.sessionID = sessionID;
+ this.packets = packets;
+ }
+
+ /**
+ * Returns id of the session that generated this conversation transcript. The sessionID is a
+ * value generated by the server when a new request is received.
+ *
+ * @return id of the session that generated this conversation transcript.
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Returns the list of Messages and Presences that were sent to the room.
+ *
+ * @return the list of Messages and Presences that were sent to the room.
+ */
+ public List<Packet> getPackets() {
+ return Collections.unmodifiableList(packets);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<transcript xmlns=\"http://jivesoftware.com/protocol/workgroup\" sessionID=\"")
+ .append(sessionID)
+ .append("\">");
+
+ for (Iterator<Packet> it=packets.iterator(); it.hasNext();) {
+ Packet packet = it.next();
+ buf.append(packet.toXML());
+ }
+
+ buf.append("</transcript>");
+
+ return buf.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptProvider.java
index 791b06ef2..0e292caa7 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptProvider.java
@@ -1,66 +1,66 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * An IQProvider for transcripts.
- *
- * @author Gaston Dombiak
- */
-public class TranscriptProvider implements IQProvider {
-
- public TranscriptProvider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- String sessionID = parser.getAttributeValue("", "sessionID");
- List<Packet> packets = new ArrayList<Packet>();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("message")) {
- packets.add(PacketParserUtils.parseMessage(parser));
- }
- else if (parser.getName().equals("presence")) {
- packets.add(PacketParserUtils.parsePresence(parser));
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("transcript")) {
- done = true;
- }
- }
- }
-
- return new Transcript(sessionID, packets);
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An IQProvider for transcripts.
+ *
+ * @author Gaston Dombiak
+ */
+public class TranscriptProvider implements IQProvider {
+
+ public TranscriptProvider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ String sessionID = parser.getAttributeValue("", "sessionID");
+ List<Packet> packets = new ArrayList<Packet>();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("message")) {
+ packets.add(PacketParserUtils.parseMessage(parser));
+ }
+ else if (parser.getName().equals("presence")) {
+ packets.add(PacketParserUtils.parsePresence(parser));
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("transcript")) {
+ done = true;
+ }
+ }
+ }
+
+ return new Transcript(sessionID, packets);
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptSearch.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptSearch.java
index 72693c494..d7a3db649 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptSearch.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptSearch.java
@@ -1,87 +1,87 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * IQ packet for retrieving the transcript search form, submiting the completed search form
- * or retrieving the answer of a transcript search.
- *
- * @author Gaston Dombiak
- */
-public class TranscriptSearch extends IQ {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "transcript-search";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
- // Add packet extensions, if any are defined.
- buf.append(getExtensionsXML());
- buf.append("</").append(ELEMENT_NAME).append("> ");
-
- return buf.toString();
- }
-
- /**
- * An IQProvider for TranscriptSearch packets.
- *
- * @author Gaston Dombiak
- */
- public static class Provider implements IQProvider {
-
- public Provider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- TranscriptSearch answer = new TranscriptSearch();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- // Parse the packet extension
- answer.addExtension(PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser));
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(ELEMENT_NAME)) {
- done = true;
- }
- }
- }
-
- return answer;
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * IQ packet for retrieving the transcript search form, submiting the completed search form
+ * or retrieving the answer of a transcript search.
+ *
+ * @author Gaston Dombiak
+ */
+public class TranscriptSearch extends IQ {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "transcript-search";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\">");
+ // Add packet extensions, if any are defined.
+ buf.append(getExtensionsXML());
+ buf.append("</").append(ELEMENT_NAME).append("> ");
+
+ return buf.toString();
+ }
+
+ /**
+ * An IQProvider for TranscriptSearch packets.
+ *
+ * @author Gaston Dombiak
+ */
+ public static class Provider implements IQProvider {
+
+ public Provider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ TranscriptSearch answer = new TranscriptSearch();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ // Parse the packet extension
+ answer.addExtension(PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser));
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals(ELEMENT_NAME)) {
+ done = true;
+ }
+ }
+ }
+
+ return answer;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcripts.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcripts.java
index 66ddaad7e..86311c90c 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcripts.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/Transcripts.java
@@ -1,247 +1,247 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-
-import java.text.SimpleDateFormat;
-import java.util.*;
-
-/**
- * Represents a list of conversation transcripts that a user had in all his history. Each
- * transcript summary includes the sessionID which may be used for getting more detailed
- * information about the conversation. {@link org.jivesoftware.smackx.workgroup.packet.Transcript}
- *
- * @author Gaston Dombiak
- */
-public class Transcripts extends IQ {
-
- private static final SimpleDateFormat UTC_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
- static {
- UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
- }
-
- private String userID;
- private List<Transcripts.TranscriptSummary> summaries;
-
-
- /**
- * Creates a transcripts request for the given userID.
- *
- * @param userID the id of the user to get his conversations transcripts.
- */
- public Transcripts(String userID) {
- this.userID = userID;
- this.summaries = new ArrayList<Transcripts.TranscriptSummary>();
- }
-
- /**
- * Creates a Transcripts which will contain the transcript summaries of the given user.
- *
- * @param userID the id of the user. Could be a real JID or a unique String that identifies
- * anonymous users.
- * @param summaries the list of TranscriptSummaries.
- */
- public Transcripts(String userID, List<Transcripts.TranscriptSummary> summaries) {
- this.userID = userID;
- this.summaries = summaries;
- }
-
- /**
- * Returns the id of the user that was involved in the conversations. The userID could be a
- * real JID if the connected user was not anonymous. Otherwise, the userID will be a String
- * that was provided by the anonymous user as a way to idenitify the user across many user
- * sessions.
- *
- * @return the id of the user that was involved in the conversations.
- */
- public String getUserID() {
- return userID;
- }
-
- /**
- * Returns a list of TranscriptSummary. A TranscriptSummary does not contain the conversation
- * transcript but some summary information like the sessionID and the time when the
- * conversation started and finished. Once you have the sessionID it is possible to get the
- * full conversation transcript.
- *
- * @return a list of TranscriptSummary.
- */
- public List<Transcripts.TranscriptSummary> getSummaries() {
- return Collections.unmodifiableList(summaries);
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<transcripts xmlns=\"http://jivesoftware.com/protocol/workgroup\" userID=\"")
- .append(userID)
- .append("\">");
-
- for (TranscriptSummary transcriptSummary : summaries) {
- buf.append(transcriptSummary.toXML());
- }
-
- buf.append("</transcripts>");
-
- return buf.toString();
- }
-
- /**
- * A TranscriptSummary contains some information about a conversation such as the ID of the
- * session or the date when the conversation started and finished. You will need to use the
- * sessionID to get the full conversation transcript.
- */
- public static class TranscriptSummary {
- private String sessionID;
- private Date joinTime;
- private Date leftTime;
- private List<AgentDetail> agentDetails;
-
- public TranscriptSummary(String sessionID, Date joinTime, Date leftTime, List<AgentDetail> agentDetails) {
- this.sessionID = sessionID;
- this.joinTime = joinTime;
- this.leftTime = leftTime;
- this.agentDetails = agentDetails;
- }
-
- /**
- * Returns the ID of the session that is related to this conversation transcript. The
- * sessionID could be used for getting the full conversation transcript.
- *
- * @return the ID of the session that is related to this conversation transcript.
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Returns the Date when the conversation started.
- *
- * @return the Date when the conversation started.
- */
- public Date getJoinTime() {
- return joinTime;
- }
-
- /**
- * Returns the Date when the conversation finished.
- *
- * @return the Date when the conversation finished.
- */
- public Date getLeftTime() {
- return leftTime;
- }
-
- /**
- * Returns a list of AgentDetails. For each Agent that was involved in the conversation
- * the list will include an AgentDetail. An AgentDetail contains the JID of the agent
- * as well as the time when the Agent joined and left the conversation.
- *
- * @return a list of AgentDetails.
- */
- public List<AgentDetail> getAgentDetails() {
- return agentDetails;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<transcript sessionID=\"")
- .append(sessionID)
- .append("\">");
-
- if (joinTime != null) {
- buf.append("<joinTime>").append(UTC_FORMAT.format(joinTime)).append("</joinTime>");
- }
- if (leftTime != null) {
- buf.append("<leftTime>").append(UTC_FORMAT.format(leftTime)).append("</leftTime>");
- }
- buf.append("<agents>");
- for (AgentDetail agentDetail : agentDetails) {
- buf.append(agentDetail.toXML());
- }
- buf.append("</agents></transcript>");
-
- return buf.toString();
- }
- }
-
- /**
- * An AgentDetail contains information of an Agent that was involved in a conversation.
- */
- public static class AgentDetail {
- private String agentJID;
- private Date joinTime;
- private Date leftTime;
-
- public AgentDetail(String agentJID, Date joinTime, Date leftTime) {
- this.agentJID = agentJID;
- this.joinTime = joinTime;
- this.leftTime = leftTime;
- }
-
- /**
- * Returns the bare JID of the Agent that was involved in the conversation.
- *
- * @return the bared JID of the Agent that was involved in the conversation.
- */
- public String getAgentJID() {
- return agentJID;
- }
-
- /**
- * Returns the Date when the Agent joined the conversation.
- *
- * @return the Date when the Agent joined the conversation.
- */
- public Date getJoinTime() {
- return joinTime;
- }
-
- /**
- * Returns the Date when the Agent left the conversation.
- *
- * @return the Date when the Agent left the conversation.
- */
- public Date getLeftTime() {
- return leftTime;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<agent>");
-
- if (agentJID != null) {
- buf.append("<agentJID>").append(agentJID).append("</agentJID>");
- }
- if (joinTime != null) {
- buf.append("<joinTime>").append(UTC_FORMAT.format(joinTime)).append("</joinTime>");
- }
- if (leftTime != null) {
- buf.append("<leftTime>").append(UTC_FORMAT.format(leftTime)).append("</leftTime>");
- }
- buf.append("</agent>");
-
- return buf.toString();
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * Represents a list of conversation transcripts that a user had in all his history. Each
+ * transcript summary includes the sessionID which may be used for getting more detailed
+ * information about the conversation. {@link org.jivesoftware.smackx.workgroup.packet.Transcript}
+ *
+ * @author Gaston Dombiak
+ */
+public class Transcripts extends IQ {
+
+ private static final SimpleDateFormat UTC_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
+ static {
+ UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
+ }
+
+ private String userID;
+ private List<Transcripts.TranscriptSummary> summaries;
+
+
+ /**
+ * Creates a transcripts request for the given userID.
+ *
+ * @param userID the id of the user to get his conversations transcripts.
+ */
+ public Transcripts(String userID) {
+ this.userID = userID;
+ this.summaries = new ArrayList<Transcripts.TranscriptSummary>();
+ }
+
+ /**
+ * Creates a Transcripts which will contain the transcript summaries of the given user.
+ *
+ * @param userID the id of the user. Could be a real JID or a unique String that identifies
+ * anonymous users.
+ * @param summaries the list of TranscriptSummaries.
+ */
+ public Transcripts(String userID, List<Transcripts.TranscriptSummary> summaries) {
+ this.userID = userID;
+ this.summaries = summaries;
+ }
+
+ /**
+ * Returns the id of the user that was involved in the conversations. The userID could be a
+ * real JID if the connected user was not anonymous. Otherwise, the userID will be a String
+ * that was provided by the anonymous user as a way to idenitify the user across many user
+ * sessions.
+ *
+ * @return the id of the user that was involved in the conversations.
+ */
+ public String getUserID() {
+ return userID;
+ }
+
+ /**
+ * Returns a list of TranscriptSummary. A TranscriptSummary does not contain the conversation
+ * transcript but some summary information like the sessionID and the time when the
+ * conversation started and finished. Once you have the sessionID it is possible to get the
+ * full conversation transcript.
+ *
+ * @return a list of TranscriptSummary.
+ */
+ public List<Transcripts.TranscriptSummary> getSummaries() {
+ return Collections.unmodifiableList(summaries);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<transcripts xmlns=\"http://jivesoftware.com/protocol/workgroup\" userID=\"")
+ .append(userID)
+ .append("\">");
+
+ for (TranscriptSummary transcriptSummary : summaries) {
+ buf.append(transcriptSummary.toXML());
+ }
+
+ buf.append("</transcripts>");
+
+ return buf.toString();
+ }
+
+ /**
+ * A TranscriptSummary contains some information about a conversation such as the ID of the
+ * session or the date when the conversation started and finished. You will need to use the
+ * sessionID to get the full conversation transcript.
+ */
+ public static class TranscriptSummary {
+ private String sessionID;
+ private Date joinTime;
+ private Date leftTime;
+ private List<AgentDetail> agentDetails;
+
+ public TranscriptSummary(String sessionID, Date joinTime, Date leftTime, List<AgentDetail> agentDetails) {
+ this.sessionID = sessionID;
+ this.joinTime = joinTime;
+ this.leftTime = leftTime;
+ this.agentDetails = agentDetails;
+ }
+
+ /**
+ * Returns the ID of the session that is related to this conversation transcript. The
+ * sessionID could be used for getting the full conversation transcript.
+ *
+ * @return the ID of the session that is related to this conversation transcript.
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Returns the Date when the conversation started.
+ *
+ * @return the Date when the conversation started.
+ */
+ public Date getJoinTime() {
+ return joinTime;
+ }
+
+ /**
+ * Returns the Date when the conversation finished.
+ *
+ * @return the Date when the conversation finished.
+ */
+ public Date getLeftTime() {
+ return leftTime;
+ }
+
+ /**
+ * Returns a list of AgentDetails. For each Agent that was involved in the conversation
+ * the list will include an AgentDetail. An AgentDetail contains the JID of the agent
+ * as well as the time when the Agent joined and left the conversation.
+ *
+ * @return a list of AgentDetails.
+ */
+ public List<AgentDetail> getAgentDetails() {
+ return agentDetails;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<transcript sessionID=\"")
+ .append(sessionID)
+ .append("\">");
+
+ if (joinTime != null) {
+ buf.append("<joinTime>").append(UTC_FORMAT.format(joinTime)).append("</joinTime>");
+ }
+ if (leftTime != null) {
+ buf.append("<leftTime>").append(UTC_FORMAT.format(leftTime)).append("</leftTime>");
+ }
+ buf.append("<agents>");
+ for (AgentDetail agentDetail : agentDetails) {
+ buf.append(agentDetail.toXML());
+ }
+ buf.append("</agents></transcript>");
+
+ return buf.toString();
+ }
+ }
+
+ /**
+ * An AgentDetail contains information of an Agent that was involved in a conversation.
+ */
+ public static class AgentDetail {
+ private String agentJID;
+ private Date joinTime;
+ private Date leftTime;
+
+ public AgentDetail(String agentJID, Date joinTime, Date leftTime) {
+ this.agentJID = agentJID;
+ this.joinTime = joinTime;
+ this.leftTime = leftTime;
+ }
+
+ /**
+ * Returns the bare JID of the Agent that was involved in the conversation.
+ *
+ * @return the bared JID of the Agent that was involved in the conversation.
+ */
+ public String getAgentJID() {
+ return agentJID;
+ }
+
+ /**
+ * Returns the Date when the Agent joined the conversation.
+ *
+ * @return the Date when the Agent joined the conversation.
+ */
+ public Date getJoinTime() {
+ return joinTime;
+ }
+
+ /**
+ * Returns the Date when the Agent left the conversation.
+ *
+ * @return the Date when the Agent left the conversation.
+ */
+ public Date getLeftTime() {
+ return leftTime;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<agent>");
+
+ if (agentJID != null) {
+ buf.append("<agentJID>").append(agentJID).append("</agentJID>");
+ }
+ if (joinTime != null) {
+ buf.append("<joinTime>").append(UTC_FORMAT.format(joinTime)).append("</joinTime>");
+ }
+ if (leftTime != null) {
+ buf.append("<leftTime>").append(UTC_FORMAT.format(leftTime)).append("</leftTime>");
+ }
+ buf.append("</agent>");
+
+ return buf.toString();
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptsProvider.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptsProvider.java
index cb8f42979..c0ef7a814 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptsProvider.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/TranscriptsProvider.java
@@ -1,148 +1,148 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.TimeZone;
-
-/**
- * An IQProvider for transcripts summaries.
- *
- * @author Gaston Dombiak
- */
-public class TranscriptsProvider implements IQProvider {
-
- private static final SimpleDateFormat UTC_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
- static {
- UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
- }
-
- public TranscriptsProvider() {
- super();
- }
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- String userID = parser.getAttributeValue("", "userID");
- List<Transcripts.TranscriptSummary> summaries = new ArrayList<Transcripts.TranscriptSummary>();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("transcript")) {
- summaries.add(parseSummary(parser));
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("transcripts")) {
- done = true;
- }
- }
- }
-
- return new Transcripts(userID, summaries);
- }
-
- private Transcripts.TranscriptSummary parseSummary(XmlPullParser parser) throws IOException,
- XmlPullParserException {
- String sessionID = parser.getAttributeValue("", "sessionID");
- Date joinTime = null;
- Date leftTime = null;
- List<Transcripts.AgentDetail> agents = new ArrayList<Transcripts.AgentDetail>();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("joinTime")) {
- try {
- joinTime = UTC_FORMAT.parse(parser.nextText());
- } catch (ParseException e) {}
- }
- else if (parser.getName().equals("leftTime")) {
- try {
- leftTime = UTC_FORMAT.parse(parser.nextText());
- } catch (ParseException e) {}
- }
- else if (parser.getName().equals("agents")) {
- agents = parseAgents(parser);
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("transcript")) {
- done = true;
- }
- }
- }
-
- return new Transcripts.TranscriptSummary(sessionID, joinTime, leftTime, agents);
- }
-
- private List<Transcripts.AgentDetail> parseAgents(XmlPullParser parser) throws IOException, XmlPullParserException {
- List<Transcripts.AgentDetail> agents = new ArrayList<Transcripts.AgentDetail>();
- String agentJID = null;
- Date joinTime = null;
- Date leftTime = null;
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("agentJID")) {
- agentJID = parser.nextText();
- }
- else if (parser.getName().equals("joinTime")) {
- try {
- joinTime = UTC_FORMAT.parse(parser.nextText());
- } catch (ParseException e) {}
- }
- else if (parser.getName().equals("leftTime")) {
- try {
- leftTime = UTC_FORMAT.parse(parser.nextText());
- } catch (ParseException e) {}
- }
- else if (parser.getName().equals("agent")) {
- agentJID = null;
- joinTime = null;
- leftTime = null;
- }
- }
- else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("agents")) {
- done = true;
- }
- else if (parser.getName().equals("agent")) {
- agents.add(new Transcripts.AgentDetail(agentJID, joinTime, leftTime));
- }
- }
- }
- return agents;
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * An IQProvider for transcripts summaries.
+ *
+ * @author Gaston Dombiak
+ */
+public class TranscriptsProvider implements IQProvider {
+
+ private static final SimpleDateFormat UTC_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
+ static {
+ UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
+ }
+
+ public TranscriptsProvider() {
+ super();
+ }
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ String userID = parser.getAttributeValue("", "userID");
+ List<Transcripts.TranscriptSummary> summaries = new ArrayList<Transcripts.TranscriptSummary>();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("transcript")) {
+ summaries.add(parseSummary(parser));
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("transcripts")) {
+ done = true;
+ }
+ }
+ }
+
+ return new Transcripts(userID, summaries);
+ }
+
+ private Transcripts.TranscriptSummary parseSummary(XmlPullParser parser) throws IOException,
+ XmlPullParserException {
+ String sessionID = parser.getAttributeValue("", "sessionID");
+ Date joinTime = null;
+ Date leftTime = null;
+ List<Transcripts.AgentDetail> agents = new ArrayList<Transcripts.AgentDetail>();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("joinTime")) {
+ try {
+ joinTime = UTC_FORMAT.parse(parser.nextText());
+ } catch (ParseException e) {}
+ }
+ else if (parser.getName().equals("leftTime")) {
+ try {
+ leftTime = UTC_FORMAT.parse(parser.nextText());
+ } catch (ParseException e) {}
+ }
+ else if (parser.getName().equals("agents")) {
+ agents = parseAgents(parser);
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("transcript")) {
+ done = true;
+ }
+ }
+ }
+
+ return new Transcripts.TranscriptSummary(sessionID, joinTime, leftTime, agents);
+ }
+
+ private List<Transcripts.AgentDetail> parseAgents(XmlPullParser parser) throws IOException, XmlPullParserException {
+ List<Transcripts.AgentDetail> agents = new ArrayList<Transcripts.AgentDetail>();
+ String agentJID = null;
+ Date joinTime = null;
+ Date leftTime = null;
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals("agentJID")) {
+ agentJID = parser.nextText();
+ }
+ else if (parser.getName().equals("joinTime")) {
+ try {
+ joinTime = UTC_FORMAT.parse(parser.nextText());
+ } catch (ParseException e) {}
+ }
+ else if (parser.getName().equals("leftTime")) {
+ try {
+ leftTime = UTC_FORMAT.parse(parser.nextText());
+ } catch (ParseException e) {}
+ }
+ else if (parser.getName().equals("agent")) {
+ agentJID = null;
+ joinTime = null;
+ leftTime = null;
+ }
+ }
+ else if (eventType == XmlPullParser.END_TAG) {
+ if (parser.getName().equals("agents")) {
+ done = true;
+ }
+ else if (parser.getName().equals("agent")) {
+ agents.add(new Transcripts.AgentDetail(agentJID, joinTime, leftTime));
+ }
+ }
+ }
+ return agents;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/UserID.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/UserID.java
index 8bf458905..4d50abf9a 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/UserID.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/UserID.java
@@ -1,77 +1,77 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-public class UserID implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "user";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- private String userID;
-
- public UserID(String userID) {
- this.userID = userID;
- }
-
- public String getUserID() {
- return this.userID;
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\" ");
- buf.append("id=\"").append(this.getUserID());
- buf.append("\"/>");
-
- return buf.toString();
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- String userID = parser.getAttributeValue("", "id");
-
- // Advance to end of extension.
- parser.next();
-
- return new UserID(userID);
- }
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+public class UserID implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "user";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ private String userID;
+
+ public UserID(String userID) {
+ this.userID = userID;
+ }
+
+ public String getUserID() {
+ return this.userID;
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=\"").append(NAMESPACE).append("\" ");
+ buf.append("id=\"").append(this.getUserID());
+ buf.append("\"/>");
+
+ return buf.toString();
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ String userID = parser.getAttributeValue("", "id");
+
+ // Advance to end of extension.
+ parser.next();
+
+ return new UserID(userID);
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/WorkgroupInformation.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/WorkgroupInformation.java
index b0ea447a4..87086bd65 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/WorkgroupInformation.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/packet/WorkgroupInformation.java
@@ -1,86 +1,86 @@
-/**
- * $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
- *
- * 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.workgroup.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * A packet extension that contains information about the user and agent in a
- * workgroup chat. The packet extension is attached to group chat invitations.
- */
-public class WorkgroupInformation implements PacketExtension {
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "workgroup";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
-
- private String workgroupJID;
-
- public WorkgroupInformation(String workgroupJID){
- this.workgroupJID = workgroupJID;
- }
-
- public String getWorkgroupJID() {
- return workgroupJID;
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return NAMESPACE;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append('<').append(ELEMENT_NAME);
- buf.append(" jid=\"").append(getWorkgroupJID()).append("\"");
- buf.append(" xmlns=\"").append(NAMESPACE).append("\" />");
-
- return buf.toString();
- }
-
- public static class Provider implements PacketExtensionProvider {
-
- /**
- * PacketExtensionProvider implementation
- */
- public PacketExtension parseExtension (XmlPullParser parser)
- throws Exception {
- String workgroupJID = parser.getAttributeValue("", "jid");
-
- // since this is a start and end tag, and we arrive on the start, this should guarantee
- // we leave on the end
- parser.next();
-
- return new WorkgroupInformation(workgroupJID);
- }
- }
+/**
+ * $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
+ *
+ * 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.workgroup.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * A packet extension that contains information about the user and agent in a
+ * workgroup chat. The packet extension is attached to group chat invitations.
+ */
+public class WorkgroupInformation implements PacketExtension {
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "workgroup";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/workgroup";
+
+ private String workgroupJID;
+
+ public WorkgroupInformation(String workgroupJID){
+ this.workgroupJID = workgroupJID;
+ }
+
+ public String getWorkgroupJID() {
+ return workgroupJID;
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append('<').append(ELEMENT_NAME);
+ buf.append(" jid=\"").append(getWorkgroupJID()).append("\"");
+ buf.append(" xmlns=\"").append(NAMESPACE).append("\" />");
+
+ return buf.toString();
+ }
+
+ public static class Provider implements PacketExtensionProvider {
+
+ /**
+ * PacketExtensionProvider implementation
+ */
+ public PacketExtension parseExtension (XmlPullParser parser)
+ throws Exception {
+ String workgroupJID = parser.getAttributeValue("", "jid");
+
+ // since this is a start and end tag, and we arrive on the start, this should guarantee
+ // we leave on the end
+ parser.next();
+
+ return new WorkgroupInformation(workgroupJID);
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSetting.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSetting.java
index 921134ace..30674a1a3 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSetting.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSetting.java
@@ -1,56 +1,56 @@
-/**
- * $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
- *
- * 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.workgroup.settings;
-
-public class ChatSetting {
- private String key;
- private String value;
- private int type;
-
- public ChatSetting(String key, String value, int type){
- setKey(key);
- setValue(value);
- setType(type);
- }
-
- public String getKey() {
- return key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public String getValue() {
- return value;
- }
-
- public void setValue(String value) {
- this.value = value;
- }
-
- public int getType() {
- return type;
- }
-
- public void setType(int type) {
- this.type = type;
- }
-}
+/**
+ * $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
+ *
+ * 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.workgroup.settings;
+
+public class ChatSetting {
+ private String key;
+ private String value;
+ private int type;
+
+ public ChatSetting(String key, String value, int type){
+ setKey(key);
+ setValue(value);
+ setType(type);
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSettings.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSettings.java
index ccc7a4003..eec588451 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSettings.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/ChatSettings.java
@@ -1,179 +1,179 @@
-/**
- * $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
- *
- * 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.workgroup.settings;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-public class ChatSettings extends IQ {
-
- /**
- * Defined as image type.
- */
- public static final int IMAGE_SETTINGS = 0;
-
- /**
- * Defined as Text settings type.
- */
- public static final int TEXT_SETTINGS = 1;
-
- /**
- * Defined as Bot settings type.
- */
- public static final int BOT_SETTINGS = 2;
-
- private List<ChatSetting> settings;
- private String key;
- private int type = -1;
-
- public ChatSettings() {
- settings = new ArrayList<ChatSetting>();
- }
-
- public ChatSettings(String key) {
- setKey(key);
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public void setType(int type) {
- this.type = type;
- }
-
- public void addSetting(ChatSetting setting) {
- settings.add(setting);
- }
-
- public Collection<ChatSetting> getSettings() {
- return settings;
- }
-
- public ChatSetting getChatSetting(String key) {
- Collection<ChatSetting> col = getSettings();
- if (col != null) {
- Iterator<ChatSetting> iter = col.iterator();
- while (iter.hasNext()) {
- ChatSetting chatSetting = iter.next();
- if (chatSetting.getKey().equals(key)) {
- return chatSetting;
- }
- }
- }
- return null;
- }
-
- public ChatSetting getFirstEntry() {
- if (settings.size() > 0) {
- return (ChatSetting)settings.get(0);
- }
- return null;
- }
-
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "chat-settings";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=");
- buf.append('"');
- buf.append(NAMESPACE);
- buf.append('"');
- if (key != null) {
- buf.append(" key=\"" + key + "\"");
- }
-
- if (type != -1) {
- buf.append(" type=\"" + type + "\"");
- }
-
- buf.append("></").append(ELEMENT_NAME).append("> ");
- return buf.toString();
- }
-
- /**
- * Packet extension provider for AgentStatusRequest packets.
- */
- public static class InternalProvider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- throw new IllegalStateException("Parser not in proper position, or bad XML.");
- }
-
- ChatSettings chatSettings = new ChatSettings();
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("chat-setting".equals(parser.getName()))) {
- chatSettings.addSetting(parseChatSetting(parser));
-
- }
- else if (eventType == XmlPullParser.END_TAG && ELEMENT_NAME.equals(parser.getName())) {
- done = true;
- }
- }
- return chatSettings;
- }
-
- private ChatSetting parseChatSetting(XmlPullParser parser) throws Exception {
-
- boolean done = false;
- String key = null;
- String value = null;
- int type = 0;
-
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("key".equals(parser.getName()))) {
- key = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("value".equals(parser.getName()))) {
- value = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("type".equals(parser.getName()))) {
- type = Integer.parseInt(parser.nextText());
- }
- else if (eventType == XmlPullParser.END_TAG && "chat-setting".equals(parser.getName())) {
- done = true;
- }
- }
- return new ChatSetting(key, value, type);
- }
- }
-}
-
+/**
+ * $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
+ *
+ * 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.workgroup.settings;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+public class ChatSettings extends IQ {
+
+ /**
+ * Defined as image type.
+ */
+ public static final int IMAGE_SETTINGS = 0;
+
+ /**
+ * Defined as Text settings type.
+ */
+ public static final int TEXT_SETTINGS = 1;
+
+ /**
+ * Defined as Bot settings type.
+ */
+ public static final int BOT_SETTINGS = 2;
+
+ private List<ChatSetting> settings;
+ private String key;
+ private int type = -1;
+
+ public ChatSettings() {
+ settings = new ArrayList<ChatSetting>();
+ }
+
+ public ChatSettings(String key) {
+ setKey(key);
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public void addSetting(ChatSetting setting) {
+ settings.add(setting);
+ }
+
+ public Collection<ChatSetting> getSettings() {
+ return settings;
+ }
+
+ public ChatSetting getChatSetting(String key) {
+ Collection<ChatSetting> col = getSettings();
+ if (col != null) {
+ Iterator<ChatSetting> iter = col.iterator();
+ while (iter.hasNext()) {
+ ChatSetting chatSetting = iter.next();
+ if (chatSetting.getKey().equals(key)) {
+ return chatSetting;
+ }
+ }
+ }
+ return null;
+ }
+
+ public ChatSetting getFirstEntry() {
+ if (settings.size() > 0) {
+ return (ChatSetting)settings.get(0);
+ }
+ return null;
+ }
+
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "chat-settings";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=");
+ buf.append('"');
+ buf.append(NAMESPACE);
+ buf.append('"');
+ if (key != null) {
+ buf.append(" key=\"" + key + "\"");
+ }
+
+ if (type != -1) {
+ buf.append(" type=\"" + type + "\"");
+ }
+
+ buf.append("></").append(ELEMENT_NAME).append("> ");
+ return buf.toString();
+ }
+
+ /**
+ * Packet extension provider for AgentStatusRequest packets.
+ */
+ public static class InternalProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("Parser not in proper position, or bad XML.");
+ }
+
+ ChatSettings chatSettings = new ChatSettings();
+
+ boolean done = false;
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("chat-setting".equals(parser.getName()))) {
+ chatSettings.addSetting(parseChatSetting(parser));
+
+ }
+ else if (eventType == XmlPullParser.END_TAG && ELEMENT_NAME.equals(parser.getName())) {
+ done = true;
+ }
+ }
+ return chatSettings;
+ }
+
+ private ChatSetting parseChatSetting(XmlPullParser parser) throws Exception {
+
+ boolean done = false;
+ String key = null;
+ String value = null;
+ int type = 0;
+
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("key".equals(parser.getName()))) {
+ key = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("value".equals(parser.getName()))) {
+ value = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("type".equals(parser.getName()))) {
+ type = Integer.parseInt(parser.nextText());
+ }
+ else if (eventType == XmlPullParser.END_TAG && "chat-setting".equals(parser.getName())) {
+ done = true;
+ }
+ }
+ return new ChatSetting(key, value, type);
+ }
+ }
+}
+
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/OfflineSettings.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/OfflineSettings.java
index 15136fd12..14102af32 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/OfflineSettings.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/OfflineSettings.java
@@ -1,155 +1,155 @@
-/**
- * $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
- *
- * 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.workgroup.settings;
-
-import org.jivesoftware.smackx.workgroup.util.ModelUtil;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-public class OfflineSettings extends IQ {
- private String redirectURL;
-
- private String offlineText;
- private String emailAddress;
- private String subject;
-
- public String getRedirectURL() {
- if (!ModelUtil.hasLength(redirectURL)) {
- return "";
- }
- return redirectURL;
- }
-
- public void setRedirectURL(String redirectURL) {
- this.redirectURL = redirectURL;
- }
-
- public String getOfflineText() {
- if (!ModelUtil.hasLength(offlineText)) {
- return "";
- }
- return offlineText;
- }
-
- public void setOfflineText(String offlineText) {
- this.offlineText = offlineText;
- }
-
- public String getEmailAddress() {
- if (!ModelUtil.hasLength(emailAddress)) {
- return "";
- }
- return emailAddress;
- }
-
- public void setEmailAddress(String emailAddress) {
- this.emailAddress = emailAddress;
- }
-
- public String getSubject() {
- if (!ModelUtil.hasLength(subject)) {
- return "";
- }
- return subject;
- }
-
- public void setSubject(String subject) {
- this.subject = subject;
- }
-
- public boolean redirects() {
- return (ModelUtil.hasLength(getRedirectURL()));
- }
-
- public boolean isConfigured(){
- return ModelUtil.hasLength(getEmailAddress()) &&
- ModelUtil.hasLength(getSubject()) &&
- ModelUtil.hasLength(getOfflineText());
- }
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "offline-settings";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=");
- buf.append('"');
- buf.append(NAMESPACE);
- buf.append('"');
- buf.append("></").append(ELEMENT_NAME).append("> ");
- return buf.toString();
- }
-
-
- /**
- * Packet extension provider for AgentStatusRequest packets.
- */
- public static class InternalProvider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- throw new IllegalStateException("Parser not in proper position, or bad XML.");
- }
-
- OfflineSettings offlineSettings = new OfflineSettings();
-
- boolean done = false;
- String redirectPage = null;
- String subject = null;
- String offlineText = null;
- String emailAddress = null;
-
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("redirectPage".equals(parser.getName()))) {
- redirectPage = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("subject".equals(parser.getName()))) {
- subject = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("offlineText".equals(parser.getName()))) {
- offlineText = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("emailAddress".equals(parser.getName()))) {
- emailAddress = parser.nextText();
- }
- else if (eventType == XmlPullParser.END_TAG && "offline-settings".equals(parser.getName())) {
- done = true;
- }
- }
-
- offlineSettings.setEmailAddress(emailAddress);
- offlineSettings.setRedirectURL(redirectPage);
- offlineSettings.setSubject(subject);
- offlineSettings.setOfflineText(offlineText);
- return offlineSettings;
- }
- }
-}
-
+/**
+ * $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
+ *
+ * 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.workgroup.settings;
+
+import org.jivesoftware.smackx.workgroup.util.ModelUtil;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+public class OfflineSettings extends IQ {
+ private String redirectURL;
+
+ private String offlineText;
+ private String emailAddress;
+ private String subject;
+
+ public String getRedirectURL() {
+ if (!ModelUtil.hasLength(redirectURL)) {
+ return "";
+ }
+ return redirectURL;
+ }
+
+ public void setRedirectURL(String redirectURL) {
+ this.redirectURL = redirectURL;
+ }
+
+ public String getOfflineText() {
+ if (!ModelUtil.hasLength(offlineText)) {
+ return "";
+ }
+ return offlineText;
+ }
+
+ public void setOfflineText(String offlineText) {
+ this.offlineText = offlineText;
+ }
+
+ public String getEmailAddress() {
+ if (!ModelUtil.hasLength(emailAddress)) {
+ return "";
+ }
+ return emailAddress;
+ }
+
+ public void setEmailAddress(String emailAddress) {
+ this.emailAddress = emailAddress;
+ }
+
+ public String getSubject() {
+ if (!ModelUtil.hasLength(subject)) {
+ return "";
+ }
+ return subject;
+ }
+
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ public boolean redirects() {
+ return (ModelUtil.hasLength(getRedirectURL()));
+ }
+
+ public boolean isConfigured(){
+ return ModelUtil.hasLength(getEmailAddress()) &&
+ ModelUtil.hasLength(getSubject()) &&
+ ModelUtil.hasLength(getOfflineText());
+ }
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "offline-settings";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=");
+ buf.append('"');
+ buf.append(NAMESPACE);
+ buf.append('"');
+ buf.append("></").append(ELEMENT_NAME).append("> ");
+ return buf.toString();
+ }
+
+
+ /**
+ * Packet extension provider for AgentStatusRequest packets.
+ */
+ public static class InternalProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("Parser not in proper position, or bad XML.");
+ }
+
+ OfflineSettings offlineSettings = new OfflineSettings();
+
+ boolean done = false;
+ String redirectPage = null;
+ String subject = null;
+ String offlineText = null;
+ String emailAddress = null;
+
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("redirectPage".equals(parser.getName()))) {
+ redirectPage = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("subject".equals(parser.getName()))) {
+ subject = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("offlineText".equals(parser.getName()))) {
+ offlineText = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("emailAddress".equals(parser.getName()))) {
+ emailAddress = parser.nextText();
+ }
+ else if (eventType == XmlPullParser.END_TAG && "offline-settings".equals(parser.getName())) {
+ done = true;
+ }
+ }
+
+ offlineSettings.setEmailAddress(emailAddress);
+ offlineSettings.setRedirectURL(redirectPage);
+ offlineSettings.setSubject(subject);
+ offlineSettings.setOfflineText(offlineText);
+ return offlineSettings;
+ }
+ }
+}
+
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/SearchSettings.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/SearchSettings.java
index 98d59fc1e..037af78bd 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/SearchSettings.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/settings/SearchSettings.java
@@ -1,112 +1,112 @@
-/**
- * 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
- *
- * 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.workgroup.settings;
-
-import org.jivesoftware.smackx.workgroup.util.ModelUtil;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.provider.IQProvider;
-import org.xmlpull.v1.XmlPullParser;
-
-public class SearchSettings extends IQ {
- private String forumsLocation;
- private String kbLocation;
-
- public boolean isSearchEnabled() {
- return ModelUtil.hasLength(getForumsLocation()) && ModelUtil.hasLength(getKbLocation());
- }
-
- public String getForumsLocation() {
- return forumsLocation;
- }
-
- public void setForumsLocation(String forumsLocation) {
- this.forumsLocation = forumsLocation;
- }
-
- public String getKbLocation() {
- return kbLocation;
- }
-
- public void setKbLocation(String kbLocation) {
- this.kbLocation = kbLocation;
- }
-
- public boolean hasKB(){
- return ModelUtil.hasLength(getKbLocation());
- }
-
- public boolean hasForums(){
- return ModelUtil.hasLength(getForumsLocation());
- }
-
-
- /**
- * Element name of the packet extension.
- */
- public static final String ELEMENT_NAME = "search-settings";
-
- /**
- * Namespace of the packet extension.
- */
- public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<").append(ELEMENT_NAME).append(" xmlns=");
- buf.append('"');
- buf.append(NAMESPACE);
- buf.append('"');
- buf.append("></").append(ELEMENT_NAME).append("> ");
- return buf.toString();
- }
-
-
- /**
- * Packet extension provider for AgentStatusRequest packets.
- */
- public static class InternalProvider implements IQProvider {
-
- public IQ parseIQ(XmlPullParser parser) throws Exception {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- throw new IllegalStateException("Parser not in proper position, or bad XML.");
- }
-
- SearchSettings settings = new SearchSettings();
-
- boolean done = false;
- String kb = null;
- String forums = null;
-
- while (!done) {
- int eventType = parser.next();
- if ((eventType == XmlPullParser.START_TAG) && ("forums".equals(parser.getName()))) {
- forums = parser.nextText();
- }
- else if ((eventType == XmlPullParser.START_TAG) && ("kb".equals(parser.getName()))) {
- kb = parser.nextText();
- }
- else if (eventType == XmlPullParser.END_TAG && "search-settings".equals(parser.getName())) {
- done = true;
- }
- }
-
- settings.setForumsLocation(forums);
- settings.setKbLocation(kb);
- return settings;
- }
- }
-}
+/**
+ * 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
+ *
+ * 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.workgroup.settings;
+
+import org.jivesoftware.smackx.workgroup.util.ModelUtil;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.provider.IQProvider;
+import org.xmlpull.v1.XmlPullParser;
+
+public class SearchSettings extends IQ {
+ private String forumsLocation;
+ private String kbLocation;
+
+ public boolean isSearchEnabled() {
+ return ModelUtil.hasLength(getForumsLocation()) && ModelUtil.hasLength(getKbLocation());
+ }
+
+ public String getForumsLocation() {
+ return forumsLocation;
+ }
+
+ public void setForumsLocation(String forumsLocation) {
+ this.forumsLocation = forumsLocation;
+ }
+
+ public String getKbLocation() {
+ return kbLocation;
+ }
+
+ public void setKbLocation(String kbLocation) {
+ this.kbLocation = kbLocation;
+ }
+
+ public boolean hasKB(){
+ return ModelUtil.hasLength(getKbLocation());
+ }
+
+ public boolean hasForums(){
+ return ModelUtil.hasLength(getForumsLocation());
+ }
+
+
+ /**
+ * Element name of the packet extension.
+ */
+ public static final String ELEMENT_NAME = "search-settings";
+
+ /**
+ * Namespace of the packet extension.
+ */
+ public static final String NAMESPACE = "http://jivesoftware.com/protocol/workgroup";
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(ELEMENT_NAME).append(" xmlns=");
+ buf.append('"');
+ buf.append(NAMESPACE);
+ buf.append('"');
+ buf.append("></").append(ELEMENT_NAME).append("> ");
+ return buf.toString();
+ }
+
+
+ /**
+ * Packet extension provider for AgentStatusRequest packets.
+ */
+ public static class InternalProvider implements IQProvider {
+
+ public IQ parseIQ(XmlPullParser parser) throws Exception {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("Parser not in proper position, or bad XML.");
+ }
+
+ SearchSettings settings = new SearchSettings();
+
+ boolean done = false;
+ String kb = null;
+ String forums = null;
+
+ while (!done) {
+ int eventType = parser.next();
+ if ((eventType == XmlPullParser.START_TAG) && ("forums".equals(parser.getName()))) {
+ forums = parser.nextText();
+ }
+ else if ((eventType == XmlPullParser.START_TAG) && ("kb".equals(parser.getName()))) {
+ kb = parser.nextText();
+ }
+ else if (eventType == XmlPullParser.END_TAG && "search-settings".equals(parser.getName())) {
+ done = true;
+ }
+ }
+
+ settings.setForumsLocation(forums);
+ settings.setKbLocation(kb);
+ return settings;
+ }
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/QueueListener.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/QueueListener.java
index fa3e6a6cf..734897f17 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/QueueListener.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/QueueListener.java
@@ -1,55 +1,55 @@
-/**
- * $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
- *
- * 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.workgroup.user;
-
-/**
- * Listener interface for those that wish to be notified of workgroup queue events.
- *
- * @see Workgroup#addQueueListener(QueueListener)
- * @author loki der quaeler
- */
-public interface QueueListener {
-
- /**
- * The user joined the workgroup queue.
- */
- public void joinedQueue();
-
- /**
- * The user departed the workgroup queue.
- */
- public void departedQueue();
-
- /**
- * The user's queue position has been updated to a new value.
- *
- * @param currentPosition the user's current position in the queue.
- */
- public void queuePositionUpdated(int currentPosition);
-
- /**
- * The user's estimated remaining wait time in the queue has been updated.
- *
- * @param secondsRemaining the estimated number of seconds remaining until the
- * the user is routed to the agent.
- */
- public void queueWaitTimeUpdated(int secondsRemaining);
-
-}
+/**
+ * $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
+ *
+ * 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.workgroup.user;
+
+/**
+ * Listener interface for those that wish to be notified of workgroup queue events.
+ *
+ * @see Workgroup#addQueueListener(QueueListener)
+ * @author loki der quaeler
+ */
+public interface QueueListener {
+
+ /**
+ * The user joined the workgroup queue.
+ */
+ public void joinedQueue();
+
+ /**
+ * The user departed the workgroup queue.
+ */
+ public void departedQueue();
+
+ /**
+ * The user's queue position has been updated to a new value.
+ *
+ * @param currentPosition the user's current position in the queue.
+ */
+ public void queuePositionUpdated(int currentPosition);
+
+ /**
+ * The user's estimated remaining wait time in the queue has been updated.
+ *
+ * @param secondsRemaining the estimated number of seconds remaining until the
+ * the user is routed to the agent.
+ */
+ public void queueWaitTimeUpdated(int secondsRemaining);
+
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/Workgroup.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/Workgroup.java
index 237337f00..4ccd034e1 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/Workgroup.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/user/Workgroup.java
@@ -1,868 +1,868 @@
-/**
- * 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
- *
- * 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.workgroup.user;
-
-import org.jivesoftware.smackx.workgroup.MetaData;
-import org.jivesoftware.smackx.workgroup.WorkgroupInvitation;
-import org.jivesoftware.smackx.workgroup.WorkgroupInvitationListener;
-import org.jivesoftware.smackx.workgroup.ext.forms.WorkgroupForm;
-import org.jivesoftware.smackx.workgroup.packet.DepartQueuePacket;
-import org.jivesoftware.smackx.workgroup.packet.QueueUpdate;
-import org.jivesoftware.smackx.workgroup.packet.SessionID;
-import org.jivesoftware.smackx.workgroup.packet.UserID;
-import org.jivesoftware.smackx.workgroup.settings.*;
-import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.filter.*;
-import org.jivesoftware.smack.packet.*;
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smackx.Form;
-import org.jivesoftware.smackx.FormField;
-import org.jivesoftware.smackx.ServiceDiscoveryManager;
-import org.jivesoftware.smackx.muc.MultiUserChat;
-import org.jivesoftware.smackx.packet.DataForm;
-import org.jivesoftware.smackx.packet.DiscoverInfo;
-import org.jivesoftware.smackx.packet.MUCUser;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Provides workgroup services for users. Users can join the workgroup queue, depart the
- * queue, find status information about their placement in the queue, and register to
- * be notified when they are routed to an agent.<p>
- * <p/>
- * This class only provides a users perspective into a workgroup and is not intended
- * for use by agents.
- *
- * @author Matt Tucker
- * @author Derek DeMoro
- */
-public class Workgroup {
-
- private String workgroupJID;
- private Connection connection;
- private boolean inQueue;
- private List<WorkgroupInvitationListener> invitationListeners;
- private List<QueueListener> queueListeners;
-
- private int queuePosition = -1;
- private int queueRemainingTime = -1;
-
- /**
- * Creates a new workgroup instance using the specified workgroup JID
- * (eg support@workgroup.example.com) and XMPP connection. The connection must have
- * undergone a successful login before being used to construct an instance of
- * this class.
- *
- * @param workgroupJID the JID of the workgroup.
- * @param connection an XMPP connection which must have already undergone a
- * successful login.
- */
- public Workgroup(String workgroupJID, Connection connection) {
- // Login must have been done before passing in connection.
- if (!connection.isAuthenticated()) {
- throw new IllegalStateException("Must login to server before creating workgroup.");
- }
-
- this.workgroupJID = workgroupJID;
- this.connection = connection;
- inQueue = false;
- invitationListeners = new ArrayList<WorkgroupInvitationListener>();
- queueListeners = new ArrayList<QueueListener>();
-
- // Register as a queue listener for internal usage by this instance.
- addQueueListener(new QueueListener() {
- public void joinedQueue() {
- inQueue = true;
- }
-
- public void departedQueue() {
- inQueue = false;
- queuePosition = -1;
- queueRemainingTime = -1;
- }
-
- public void queuePositionUpdated(int currentPosition) {
- queuePosition = currentPosition;
- }
-
- public void queueWaitTimeUpdated(int secondsRemaining) {
- queueRemainingTime = secondsRemaining;
- }
- });
-
- /**
- * Internal handling of an invitation.Recieving an invitation removes the user from the queue.
- */
- MultiUserChat.addInvitationListener(connection,
- new org.jivesoftware.smackx.muc.InvitationListener() {
- public void invitationReceived(Connection conn, String room, String inviter,
- String reason, String password, Message message) {
- inQueue = false;
- queuePosition = -1;
- queueRemainingTime = -1;
- }
- });
-
- // Register a packet listener for all the messages sent to this client.
- PacketFilter typeFilter = new PacketTypeFilter(Message.class);
-
- connection.addPacketListener(new PacketListener() {
- public void processPacket(Packet packet) {
- handlePacket(packet);
- }
- }, typeFilter);
- }
-
- /**
- * Returns the name of this workgroup (eg support@example.com).
- *
- * @return the name of the workgroup.
- */
- public String getWorkgroupJID() {
- return workgroupJID;
- }
-
- /**
- * Returns true if the user is currently waiting in the workgroup queue.
- *
- * @return true if currently waiting in the queue.
- */
- public boolean isInQueue() {
- return inQueue;
- }
-
- /**
- * Returns true if the workgroup is available for receiving new requests. The workgroup will be
- * available only when agents are available for this workgroup.
- *
- * @return true if the workgroup is available for receiving new requests.
- */
- public boolean isAvailable() {
- Presence directedPresence = new Presence(Presence.Type.available);
- directedPresence.setTo(workgroupJID);
- PacketFilter typeFilter = new PacketTypeFilter(Presence.class);
- PacketFilter fromFilter = new FromContainsFilter(workgroupJID);
- PacketCollector collector = connection.createPacketCollector(new AndFilter(fromFilter,
- typeFilter));
-
- connection.sendPacket(directedPresence);
-
- Presence response = (Presence)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- return false;
- }
- else if (response.getError() != null) {
- return false;
- }
- else {
- return Presence.Type.available == response.getType();
- }
- }
-
- /**
- * Returns the users current position in the workgroup queue. A value of 0 means
- * the user is next in line to be routed; therefore, if the queue position
- * is being displayed to the end user it is usually a good idea to add 1 to
- * the value this method returns before display. If the user is not currently
- * waiting in the workgroup, or no queue position information is available, -1
- * will be returned.
- *
- * @return the user's current position in the workgroup queue, or -1 if the
- * position isn't available or if the user isn't in the queue.
- */
- public int getQueuePosition() {
- return queuePosition;
- }
-
- /**
- * Returns the estimated time (in seconds) that the user has to left wait in
- * the workgroup queue before being routed. If the user is not currently waiting
- * int he workgroup, or no queue time information is available, -1 will be
- * returned.
- *
- * @return the estimated time remaining (in seconds) that the user has to
- * wait inthe workgroupu queue, or -1 if time information isn't available
- * or if the user isn't int the queue.
- */
- public int getQueueRemainingTime() {
- return queueRemainingTime;
- }
-
- /**
- * Joins the workgroup queue to wait to be routed to an agent. After joining
- * the queue, queue status events will be sent to indicate the user's position and
- * estimated time left in the queue. Once joining the queue, there are three ways
- * the user can leave the queue: <ul>
- * <p/>
- * <li>The user is routed to an agent, which triggers a GroupChat invitation.
- * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
- * <li>A server error occurs, or an administrator explicitly removes the user
- * from the queue.
- * </ul>
- * <p/>
- * A user cannot request to join the queue again if already in the queue. Therefore,
- * this method will throw an IllegalStateException if the user is already in the queue.<p>
- * <p/>
- * Some servers may be configured to require certain meta-data in order to
- * join the queue. In that case, the {@link #joinQueue(Form)} method should be
- * used instead of this method so that meta-data may be passed in.<p>
- * <p/>
- * The server tracks the conversations that a user has with agents over time. By
- * default, that tracking is done using the user's JID. However, this is not always
- * possible. For example, when the user is logged in anonymously using a web client.
- * In that case the user ID might be a randomly generated value put into a persistent
- * cookie or a username obtained via the session. A userID can be explicitly
- * passed in by using the {@link #joinQueue(Form, String)} method. When specified,
- * that userID will be used instead of the user's JID to track conversations. The
- * server will ignore a manually specified userID if the user's connection to the server
- * is not anonymous.
- *
- * @throws XMPPException if an error occured joining the queue. An error may indicate
- * that a connection failure occured or that the server explicitly rejected the
- * request to join the queue.
- */
- public void joinQueue() throws XMPPException {
- joinQueue(null);
- }
-
- /**
- * Joins the workgroup queue to wait to be routed to an agent. After joining
- * the queue, queue status events will be sent to indicate the user's position and
- * estimated time left in the queue. Once joining the queue, there are three ways
- * the user can leave the queue: <ul>
- * <p/>
- * <li>The user is routed to an agent, which triggers a GroupChat invitation.
- * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
- * <li>A server error occurs, or an administrator explicitly removes the user
- * from the queue.
- * </ul>
- * <p/>
- * A user cannot request to join the queue again if already in the queue. Therefore,
- * this method will throw an IllegalStateException if the user is already in the queue.<p>
- * <p/>
- * Some servers may be configured to require certain meta-data in order to
- * join the queue.<p>
- * <p/>
- * The server tracks the conversations that a user has with agents over time. By
- * default, that tracking is done using the user's JID. However, this is not always
- * possible. For example, when the user is logged in anonymously using a web client.
- * In that case the user ID might be a randomly generated value put into a persistent
- * cookie or a username obtained via the session. A userID can be explicitly
- * passed in by using the {@link #joinQueue(Form, String)} method. When specified,
- * that userID will be used instead of the user's JID to track conversations. The
- * server will ignore a manually specified userID if the user's connection to the server
- * is not anonymous.
- *
- * @param answerForm the completed form the send for the join request.
- * @throws XMPPException if an error occured joining the queue. An error may indicate
- * that a connection failure occured or that the server explicitly rejected the
- * request to join the queue.
- */
- public void joinQueue(Form answerForm) throws XMPPException {
- joinQueue(answerForm, null);
- }
-
- /**
- * <p>Joins the workgroup queue to wait to be routed to an agent. After joining
- * the queue, queue status events will be sent to indicate the user's position and
- * estimated time left in the queue. Once joining the queue, there are three ways
- * the user can leave the queue: <ul>
- * <p/>
- * <li>The user is routed to an agent, which triggers a GroupChat invitation.
- * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
- * <li>A server error occurs, or an administrator explicitly removes the user
- * from the queue.
- * </ul>
- * <p/>
- * A user cannot request to join the queue again if already in the queue. Therefore,
- * this method will throw an IllegalStateException if the user is already in the queue.<p>
- * <p/>
- * Some servers may be configured to require certain meta-data in order to
- * join the queue.<p>
- * <p/>
- * The server tracks the conversations that a user has with agents over time. By
- * default, that tracking is done using the user's JID. However, this is not always
- * possible. For example, when the user is logged in anonymously using a web client.
- * In that case the user ID might be a randomly generated value put into a persistent
- * cookie or a username obtained via the session. When specified, that userID will
- * be used instead of the user's JID to track conversations. The server will ignore a
- * manually specified userID if the user's connection to the server is not anonymous.
- *
- * @param answerForm the completed form associated with the join reqest.
- * @param userID String that represents the ID of the user when using anonymous sessions
- * or <tt>null</tt> if a userID should not be used.
- * @throws XMPPException if an error occured joining the queue. An error may indicate
- * that a connection failure occured or that the server explicitly rejected the
- * request to join the queue.
- */
- public void joinQueue(Form answerForm, String userID) throws XMPPException {
- // If already in the queue ignore the join request.
- if (inQueue) {
- throw new IllegalStateException("Already in queue " + workgroupJID);
- }
-
- JoinQueuePacket joinPacket = new JoinQueuePacket(workgroupJID, answerForm, userID);
-
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(joinPacket.getPacketID()));
-
- this.connection.sendPacket(joinPacket);
-
- IQ response = (IQ)collector.nextResult(10000);
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from the server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
-
- // Notify listeners that we've joined the queue.
- fireQueueJoinedEvent();
- }
-
- /**
- * <p>Joins the workgroup queue to wait to be routed to an agent. After joining
- * the queue, queue status events will be sent to indicate the user's position and
- * estimated time left in the queue. Once joining the queue, there are three ways
- * the user can leave the queue: <ul>
- * <p/>
- * <li>The user is routed to an agent, which triggers a GroupChat invitation.
- * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
- * <li>A server error occurs, or an administrator explicitly removes the user
- * from the queue.
- * </ul>
- * <p/>
- * A user cannot request to join the queue again if already in the queue. Therefore,
- * this method will throw an IllegalStateException if the user is already in the queue.<p>
- * <p/>
- * Some servers may be configured to require certain meta-data in order to
- * join the queue.<p>
- * <p/>
- * The server tracks the conversations that a user has with agents over time. By
- * default, that tracking is done using the user's JID. However, this is not always
- * possible. For example, when the user is logged in anonymously using a web client.
- * In that case the user ID might be a randomly generated value put into a persistent
- * cookie or a username obtained via the session. When specified, that userID will
- * be used instead of the user's JID to track conversations. The server will ignore a
- * manually specified userID if the user's connection to the server is not anonymous.
- *
- * @param metadata metadata to create a dataform from.
- * @param userID String that represents the ID of the user when using anonymous sessions
- * or <tt>null</tt> if a userID should not be used.
- * @throws XMPPException if an error occured joining the queue. An error may indicate
- * that a connection failure occured or that the server explicitly rejected the
- * request to join the queue.
- */
- public void joinQueue(Map<String,Object> metadata, String userID) throws XMPPException {
- // If already in the queue ignore the join request.
- if (inQueue) {
- throw new IllegalStateException("Already in queue " + workgroupJID);
- }
-
- // Build dataform from metadata
- Form form = new Form(Form.TYPE_SUBMIT);
- Iterator<String> iter = metadata.keySet().iterator();
- while (iter.hasNext()) {
- String name = iter.next();
- String value = metadata.get(name).toString();
-
- String escapedName = StringUtils.escapeForXML(name);
- String escapedValue = StringUtils.escapeForXML(value);
-
- FormField field = new FormField(escapedName);
- field.setType(FormField.TYPE_TEXT_SINGLE);
- form.addField(field);
- form.setAnswer(escapedName, escapedValue);
- }
- joinQueue(form, userID);
- }
-
- /**
- * Departs the workgroup queue. If the user is not currently in the queue, this
- * method will do nothing.<p>
- * <p/>
- * Normally, the user would not manually leave the queue. However, they may wish to
- * under certain circumstances -- for example, if they no longer wish to be routed
- * to an agent because they've been waiting too long.
- *
- * @throws XMPPException if an error occured trying to send the depart queue
- * request to the server.
- */
- public void departQueue() throws XMPPException {
- // If not in the queue ignore the depart request.
- if (!inQueue) {
- return;
- }
-
- DepartQueuePacket departPacket = new DepartQueuePacket(this.workgroupJID);
- PacketCollector collector = this.connection.createPacketCollector(new PacketIDFilter(departPacket.getPacketID()));
-
- connection.sendPacket(departPacket);
-
- IQ response = (IQ)collector.nextResult(5000);
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from the server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
-
- // Notify listeners that we're no longer in the queue.
- fireQueueDepartedEvent();
- }
-
- /**
- * Adds a queue listener that will be notified of queue events for the user
- * that created this Workgroup instance.
- *
- * @param queueListener the queue listener.
- */
- public void addQueueListener(QueueListener queueListener) {
- synchronized (queueListeners) {
- if (!queueListeners.contains(queueListener)) {
- queueListeners.add(queueListener);
- }
- }
- }
-
- /**
- * Removes a queue listener.
- *
- * @param queueListener the queue listener.
- */
- public void removeQueueListener(QueueListener queueListener) {
- synchronized (queueListeners) {
- queueListeners.remove(queueListener);
- }
- }
-
- /**
- * Adds an invitation listener that will be notified of groupchat invitations
- * from the workgroup for the the user that created this Workgroup instance.
- *
- * @param invitationListener the invitation listener.
- */
- public void addInvitationListener(WorkgroupInvitationListener invitationListener) {
- synchronized (invitationListeners) {
- if (!invitationListeners.contains(invitationListener)) {
- invitationListeners.add(invitationListener);
- }
- }
- }
-
- /**
- * Removes an invitation listener.
- *
- * @param invitationListener the invitation listener.
- */
- public void removeQueueListener(WorkgroupInvitationListener invitationListener) {
- synchronized (invitationListeners) {
- invitationListeners.remove(invitationListener);
- }
- }
-
- private void fireInvitationEvent(WorkgroupInvitation invitation) {
- synchronized (invitationListeners) {
- for (Iterator<WorkgroupInvitationListener> i = invitationListeners.iterator(); i.hasNext();) {
- WorkgroupInvitationListener listener = i.next();
- listener.invitationReceived(invitation);
- }
- }
- }
-
- private void fireQueueJoinedEvent() {
- synchronized (queueListeners) {
- for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
- QueueListener listener = i.next();
- listener.joinedQueue();
- }
- }
- }
-
- private void fireQueueDepartedEvent() {
- synchronized (queueListeners) {
- for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
- QueueListener listener = i.next();
- listener.departedQueue();
- }
- }
- }
-
- private void fireQueuePositionEvent(int currentPosition) {
- synchronized (queueListeners) {
- for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
- QueueListener listener = i.next();
- listener.queuePositionUpdated(currentPosition);
- }
- }
- }
-
- private void fireQueueTimeEvent(int secondsRemaining) {
- synchronized (queueListeners) {
- for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
- QueueListener listener = i.next();
- listener.queueWaitTimeUpdated(secondsRemaining);
- }
- }
- }
-
- // PacketListener Implementation.
-
- private void handlePacket(Packet packet) {
- if (packet instanceof Message) {
- Message msg = (Message)packet;
- // Check to see if the user left the queue.
- PacketExtension pe = msg.getExtension("depart-queue", "http://jabber.org/protocol/workgroup");
- PacketExtension queueStatus = msg.getExtension("queue-status", "http://jabber.org/protocol/workgroup");
-
- if (pe != null) {
- fireQueueDepartedEvent();
- }
- else if (queueStatus != null) {
- QueueUpdate queueUpdate = (QueueUpdate)queueStatus;
- if (queueUpdate.getPosition() != -1) {
- fireQueuePositionEvent(queueUpdate.getPosition());
- }
- if (queueUpdate.getRemaingTime() != -1) {
- fireQueueTimeEvent(queueUpdate.getRemaingTime());
- }
- }
-
- else {
- // Check if a room invitation was sent and if the sender is the workgroup
- MUCUser mucUser = (MUCUser)msg.getExtension("x", "http://jabber.org/protocol/muc#user");
- MUCUser.Invite invite = mucUser != null ? mucUser.getInvite() : null;
- if (invite != null && workgroupJID.equals(invite.getFrom())) {
- String sessionID = null;
- Map<String, List<String>> metaData = null;
-
- pe = msg.getExtension(SessionID.ELEMENT_NAME,
- SessionID.NAMESPACE);
- if (pe != null) {
- sessionID = ((SessionID)pe).getSessionID();
- }
-
- pe = msg.getExtension(MetaData.ELEMENT_NAME,
- MetaData.NAMESPACE);
- if (pe != null) {
- metaData = ((MetaData)pe).getMetaData();
- }
-
- WorkgroupInvitation inv = new WorkgroupInvitation(connection.getUser(), msg.getFrom(),
- workgroupJID, sessionID, msg.getBody(),
- msg.getFrom(), metaData);
-
- fireInvitationEvent(inv);
- }
- }
- }
- }
-
- /**
- * IQ packet to request joining the workgroup queue.
- */
- private class JoinQueuePacket extends IQ {
-
- private String userID = null;
- private DataForm form;
-
- public JoinQueuePacket(String workgroup, Form answerForm, String userID) {
- this.userID = userID;
-
- setTo(workgroup);
- setType(IQ.Type.SET);
-
- form = answerForm.getDataFormToSend();
- addExtension(form);
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
-
- buf.append("<join-queue xmlns=\"http://jabber.org/protocol/workgroup\">");
- buf.append("<queue-notifications/>");
- // Add the user unique identification if the session is anonymous
- if (connection.isAnonymous()) {
- buf.append(new UserID(userID).toXML());
- }
-
- // Append data form text
- buf.append(form.toXML());
-
- buf.append("</join-queue>");
-
- return buf.toString();
- }
- }
-
- /**
- * Returns a single chat setting based on it's identified key.
- *
- * @param key the key to find.
- * @return the ChatSetting if found, otherwise false.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public ChatSetting getChatSetting(String key) throws XMPPException {
- ChatSettings chatSettings = getChatSettings(key, -1);
- return chatSettings.getFirstEntry();
- }
-
- /**
- * Returns ChatSettings based on type.
- *
- * @param type the type of ChatSettings to return.
- * @return the ChatSettings of given type, otherwise null.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public ChatSettings getChatSettings(int type) throws XMPPException {
- return getChatSettings(null, type);
- }
-
- /**
- * Returns all ChatSettings.
- *
- * @return all ChatSettings of a given workgroup.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public ChatSettings getChatSettings() throws XMPPException {
- return getChatSettings(null, -1);
- }
-
-
- /**
- * Asks the workgroup for it's Chat Settings.
- *
- * @return key specify a key to retrieve only that settings. Otherwise for all settings, key should be null.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- private ChatSettings getChatSettings(String key, int type) throws XMPPException {
- ChatSettings request = new ChatSettings();
- if (key != null) {
- request.setKey(key);
- }
- if (type != -1) {
- request.setType(type);
- }
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- ChatSettings response = (ChatSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * The workgroup service may be configured to send email. This queries the Workgroup Service
- * to see if the email service has been configured and is available.
- *
- * @return true if the email service is available, otherwise return false.
- */
- public boolean isEmailAvailable() {
- ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
-
- try {
- String workgroupService = StringUtils.parseServer(workgroupJID);
- DiscoverInfo infoResult = discoManager.discoverInfo(workgroupService);
- return infoResult.containsFeature("jive:email:provider");
- }
- catch (XMPPException e) {
- return false;
- }
- }
-
- /**
- * Asks the workgroup for it's Offline Settings.
- *
- * @return offlineSettings the offline settings for this workgroup.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public OfflineSettings getOfflineSettings() throws XMPPException {
- OfflineSettings request = new OfflineSettings();
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- OfflineSettings response = (OfflineSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * Asks the workgroup for it's Sound Settings.
- *
- * @return soundSettings the sound settings for the specified workgroup.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public SoundSettings getSoundSettings() throws XMPPException {
- SoundSettings request = new SoundSettings();
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- SoundSettings response = (SoundSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * Asks the workgroup for it's Properties
- *
- * @return the WorkgroupProperties for the specified workgroup.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public WorkgroupProperties getWorkgroupProperties() throws XMPPException {
- WorkgroupProperties request = new WorkgroupProperties();
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- WorkgroupProperties response = (WorkgroupProperties)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
- /**
- * Asks the workgroup for it's Properties
- *
- * @param jid the jid of the user who's information you would like the workgroup to retreive.
- * @return the WorkgroupProperties for the specified workgroup.
- * @throws XMPPException if an error occurs while getting information from the server.
- */
- public WorkgroupProperties getWorkgroupProperties(String jid) throws XMPPException {
- WorkgroupProperties request = new WorkgroupProperties();
- request.setJid(jid);
- request.setType(IQ.Type.GET);
- request.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
- connection.sendPacket(request);
-
-
- WorkgroupProperties response = (WorkgroupProperties)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return response;
- }
-
-
- /**
- * Returns the Form to use for all clients of a workgroup. It is unlikely that the server
- * will change the form (without a restart) so it is safe to keep the returned form
- * for future submissions.
- *
- * @return the Form to use for searching transcripts.
- * @throws XMPPException if an error occurs while sending the request to the server.
- */
- public Form getWorkgroupForm() throws XMPPException {
- WorkgroupForm workgroupForm = new WorkgroupForm();
- workgroupForm.setType(IQ.Type.GET);
- workgroupForm.setTo(workgroupJID);
-
- PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(workgroupForm.getPacketID()));
- connection.sendPacket(workgroupForm);
-
- WorkgroupForm response = (WorkgroupForm)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
-
- // Cancel the collector.
- collector.cancel();
- if (response == null) {
- throw new XMPPException("No response from server on status set.");
- }
- if (response.getError() != null) {
- throw new XMPPException(response.getError());
- }
- return Form.getFormFrom(response);
- }
-
- /*
- public static void main(String args[]) throws Exception {
- Connection con = new XMPPConnection("anteros");
- con.connect();
- con.loginAnonymously();
-
- Workgroup workgroup = new Workgroup("demo@workgroup.anteros", con);
- WorkgroupProperties props = workgroup.getWorkgroupProperties("derek@anteros.com");
-
- System.out.print(props);
- con.disconnect();
- }
- */
-
-
+/**
+ * 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
+ *
+ * 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.workgroup.user;
+
+import org.jivesoftware.smackx.workgroup.MetaData;
+import org.jivesoftware.smackx.workgroup.WorkgroupInvitation;
+import org.jivesoftware.smackx.workgroup.WorkgroupInvitationListener;
+import org.jivesoftware.smackx.workgroup.ext.forms.WorkgroupForm;
+import org.jivesoftware.smackx.workgroup.packet.DepartQueuePacket;
+import org.jivesoftware.smackx.workgroup.packet.QueueUpdate;
+import org.jivesoftware.smackx.workgroup.packet.SessionID;
+import org.jivesoftware.smackx.workgroup.packet.UserID;
+import org.jivesoftware.smackx.workgroup.settings.*;
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.Form;
+import org.jivesoftware.smackx.FormField;
+import org.jivesoftware.smackx.ServiceDiscoveryManager;
+import org.jivesoftware.smackx.muc.MultiUserChat;
+import org.jivesoftware.smackx.packet.DataForm;
+import org.jivesoftware.smackx.packet.DiscoverInfo;
+import org.jivesoftware.smackx.packet.MUCUser;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides workgroup services for users. Users can join the workgroup queue, depart the
+ * queue, find status information about their placement in the queue, and register to
+ * be notified when they are routed to an agent.<p>
+ * <p/>
+ * This class only provides a users perspective into a workgroup and is not intended
+ * for use by agents.
+ *
+ * @author Matt Tucker
+ * @author Derek DeMoro
+ */
+public class Workgroup {
+
+ private String workgroupJID;
+ private Connection connection;
+ private boolean inQueue;
+ private List<WorkgroupInvitationListener> invitationListeners;
+ private List<QueueListener> queueListeners;
+
+ private int queuePosition = -1;
+ private int queueRemainingTime = -1;
+
+ /**
+ * Creates a new workgroup instance using the specified workgroup JID
+ * (eg support@workgroup.example.com) and XMPP connection. The connection must have
+ * undergone a successful login before being used to construct an instance of
+ * this class.
+ *
+ * @param workgroupJID the JID of the workgroup.
+ * @param connection an XMPP connection which must have already undergone a
+ * successful login.
+ */
+ public Workgroup(String workgroupJID, Connection connection) {
+ // Login must have been done before passing in connection.
+ if (!connection.isAuthenticated()) {
+ throw new IllegalStateException("Must login to server before creating workgroup.");
+ }
+
+ this.workgroupJID = workgroupJID;
+ this.connection = connection;
+ inQueue = false;
+ invitationListeners = new ArrayList<WorkgroupInvitationListener>();
+ queueListeners = new ArrayList<QueueListener>();
+
+ // Register as a queue listener for internal usage by this instance.
+ addQueueListener(new QueueListener() {
+ public void joinedQueue() {
+ inQueue = true;
+ }
+
+ public void departedQueue() {
+ inQueue = false;
+ queuePosition = -1;
+ queueRemainingTime = -1;
+ }
+
+ public void queuePositionUpdated(int currentPosition) {
+ queuePosition = currentPosition;
+ }
+
+ public void queueWaitTimeUpdated(int secondsRemaining) {
+ queueRemainingTime = secondsRemaining;
+ }
+ });
+
+ /**
+ * Internal handling of an invitation.Recieving an invitation removes the user from the queue.
+ */
+ MultiUserChat.addInvitationListener(connection,
+ new org.jivesoftware.smackx.muc.InvitationListener() {
+ public void invitationReceived(Connection conn, String room, String inviter,
+ String reason, String password, Message message) {
+ inQueue = false;
+ queuePosition = -1;
+ queueRemainingTime = -1;
+ }
+ });
+
+ // Register a packet listener for all the messages sent to this client.
+ PacketFilter typeFilter = new PacketTypeFilter(Message.class);
+
+ connection.addPacketListener(new PacketListener() {
+ public void processPacket(Packet packet) {
+ handlePacket(packet);
+ }
+ }, typeFilter);
+ }
+
+ /**
+ * Returns the name of this workgroup (eg support@example.com).
+ *
+ * @return the name of the workgroup.
+ */
+ public String getWorkgroupJID() {
+ return workgroupJID;
+ }
+
+ /**
+ * Returns true if the user is currently waiting in the workgroup queue.
+ *
+ * @return true if currently waiting in the queue.
+ */
+ public boolean isInQueue() {
+ return inQueue;
+ }
+
+ /**
+ * Returns true if the workgroup is available for receiving new requests. The workgroup will be
+ * available only when agents are available for this workgroup.
+ *
+ * @return true if the workgroup is available for receiving new requests.
+ */
+ public boolean isAvailable() {
+ Presence directedPresence = new Presence(Presence.Type.available);
+ directedPresence.setTo(workgroupJID);
+ PacketFilter typeFilter = new PacketTypeFilter(Presence.class);
+ PacketFilter fromFilter = new FromContainsFilter(workgroupJID);
+ PacketCollector collector = connection.createPacketCollector(new AndFilter(fromFilter,
+ typeFilter));
+
+ connection.sendPacket(directedPresence);
+
+ Presence response = (Presence)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ return false;
+ }
+ else if (response.getError() != null) {
+ return false;
+ }
+ else {
+ return Presence.Type.available == response.getType();
+ }
+ }
+
+ /**
+ * Returns the users current position in the workgroup queue. A value of 0 means
+ * the user is next in line to be routed; therefore, if the queue position
+ * is being displayed to the end user it is usually a good idea to add 1 to
+ * the value this method returns before display. If the user is not currently
+ * waiting in the workgroup, or no queue position information is available, -1
+ * will be returned.
+ *
+ * @return the user's current position in the workgroup queue, or -1 if the
+ * position isn't available or if the user isn't in the queue.
+ */
+ public int getQueuePosition() {
+ return queuePosition;
+ }
+
+ /**
+ * Returns the estimated time (in seconds) that the user has to left wait in
+ * the workgroup queue before being routed. If the user is not currently waiting
+ * int he workgroup, or no queue time information is available, -1 will be
+ * returned.
+ *
+ * @return the estimated time remaining (in seconds) that the user has to
+ * wait inthe workgroupu queue, or -1 if time information isn't available
+ * or if the user isn't int the queue.
+ */
+ public int getQueueRemainingTime() {
+ return queueRemainingTime;
+ }
+
+ /**
+ * Joins the workgroup queue to wait to be routed to an agent. After joining
+ * the queue, queue status events will be sent to indicate the user's position and
+ * estimated time left in the queue. Once joining the queue, there are three ways
+ * the user can leave the queue: <ul>
+ * <p/>
+ * <li>The user is routed to an agent, which triggers a GroupChat invitation.
+ * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
+ * <li>A server error occurs, or an administrator explicitly removes the user
+ * from the queue.
+ * </ul>
+ * <p/>
+ * A user cannot request to join the queue again if already in the queue. Therefore,
+ * this method will throw an IllegalStateException if the user is already in the queue.<p>
+ * <p/>
+ * Some servers may be configured to require certain meta-data in order to
+ * join the queue. In that case, the {@link #joinQueue(Form)} method should be
+ * used instead of this method so that meta-data may be passed in.<p>
+ * <p/>
+ * The server tracks the conversations that a user has with agents over time. By
+ * default, that tracking is done using the user's JID. However, this is not always
+ * possible. For example, when the user is logged in anonymously using a web client.
+ * In that case the user ID might be a randomly generated value put into a persistent
+ * cookie or a username obtained via the session. A userID can be explicitly
+ * passed in by using the {@link #joinQueue(Form, String)} method. When specified,
+ * that userID will be used instead of the user's JID to track conversations. The
+ * server will ignore a manually specified userID if the user's connection to the server
+ * is not anonymous.
+ *
+ * @throws XMPPException if an error occured joining the queue. An error may indicate
+ * that a connection failure occured or that the server explicitly rejected the
+ * request to join the queue.
+ */
+ public void joinQueue() throws XMPPException {
+ joinQueue(null);
+ }
+
+ /**
+ * Joins the workgroup queue to wait to be routed to an agent. After joining
+ * the queue, queue status events will be sent to indicate the user's position and
+ * estimated time left in the queue. Once joining the queue, there are three ways
+ * the user can leave the queue: <ul>
+ * <p/>
+ * <li>The user is routed to an agent, which triggers a GroupChat invitation.
+ * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
+ * <li>A server error occurs, or an administrator explicitly removes the user
+ * from the queue.
+ * </ul>
+ * <p/>
+ * A user cannot request to join the queue again if already in the queue. Therefore,
+ * this method will throw an IllegalStateException if the user is already in the queue.<p>
+ * <p/>
+ * Some servers may be configured to require certain meta-data in order to
+ * join the queue.<p>
+ * <p/>
+ * The server tracks the conversations that a user has with agents over time. By
+ * default, that tracking is done using the user's JID. However, this is not always
+ * possible. For example, when the user is logged in anonymously using a web client.
+ * In that case the user ID might be a randomly generated value put into a persistent
+ * cookie or a username obtained via the session. A userID can be explicitly
+ * passed in by using the {@link #joinQueue(Form, String)} method. When specified,
+ * that userID will be used instead of the user's JID to track conversations. The
+ * server will ignore a manually specified userID if the user's connection to the server
+ * is not anonymous.
+ *
+ * @param answerForm the completed form the send for the join request.
+ * @throws XMPPException if an error occured joining the queue. An error may indicate
+ * that a connection failure occured or that the server explicitly rejected the
+ * request to join the queue.
+ */
+ public void joinQueue(Form answerForm) throws XMPPException {
+ joinQueue(answerForm, null);
+ }
+
+ /**
+ * <p>Joins the workgroup queue to wait to be routed to an agent. After joining
+ * the queue, queue status events will be sent to indicate the user's position and
+ * estimated time left in the queue. Once joining the queue, there are three ways
+ * the user can leave the queue: <ul>
+ * <p/>
+ * <li>The user is routed to an agent, which triggers a GroupChat invitation.
+ * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
+ * <li>A server error occurs, or an administrator explicitly removes the user
+ * from the queue.
+ * </ul>
+ * <p/>
+ * A user cannot request to join the queue again if already in the queue. Therefore,
+ * this method will throw an IllegalStateException if the user is already in the queue.<p>
+ * <p/>
+ * Some servers may be configured to require certain meta-data in order to
+ * join the queue.<p>
+ * <p/>
+ * The server tracks the conversations that a user has with agents over time. By
+ * default, that tracking is done using the user's JID. However, this is not always
+ * possible. For example, when the user is logged in anonymously using a web client.
+ * In that case the user ID might be a randomly generated value put into a persistent
+ * cookie or a username obtained via the session. When specified, that userID will
+ * be used instead of the user's JID to track conversations. The server will ignore a
+ * manually specified userID if the user's connection to the server is not anonymous.
+ *
+ * @param answerForm the completed form associated with the join reqest.
+ * @param userID String that represents the ID of the user when using anonymous sessions
+ * or <tt>null</tt> if a userID should not be used.
+ * @throws XMPPException if an error occured joining the queue. An error may indicate
+ * that a connection failure occured or that the server explicitly rejected the
+ * request to join the queue.
+ */
+ public void joinQueue(Form answerForm, String userID) throws XMPPException {
+ // If already in the queue ignore the join request.
+ if (inQueue) {
+ throw new IllegalStateException("Already in queue " + workgroupJID);
+ }
+
+ JoinQueuePacket joinPacket = new JoinQueuePacket(workgroupJID, answerForm, userID);
+
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(joinPacket.getPacketID()));
+
+ this.connection.sendPacket(joinPacket);
+
+ IQ response = (IQ)collector.nextResult(10000);
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from the server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+
+ // Notify listeners that we've joined the queue.
+ fireQueueJoinedEvent();
+ }
+
+ /**
+ * <p>Joins the workgroup queue to wait to be routed to an agent. After joining
+ * the queue, queue status events will be sent to indicate the user's position and
+ * estimated time left in the queue. Once joining the queue, there are three ways
+ * the user can leave the queue: <ul>
+ * <p/>
+ * <li>The user is routed to an agent, which triggers a GroupChat invitation.
+ * <li>The user asks to leave the queue by calling the {@link #departQueue} method.
+ * <li>A server error occurs, or an administrator explicitly removes the user
+ * from the queue.
+ * </ul>
+ * <p/>
+ * A user cannot request to join the queue again if already in the queue. Therefore,
+ * this method will throw an IllegalStateException if the user is already in the queue.<p>
+ * <p/>
+ * Some servers may be configured to require certain meta-data in order to
+ * join the queue.<p>
+ * <p/>
+ * The server tracks the conversations that a user has with agents over time. By
+ * default, that tracking is done using the user's JID. However, this is not always
+ * possible. For example, when the user is logged in anonymously using a web client.
+ * In that case the user ID might be a randomly generated value put into a persistent
+ * cookie or a username obtained via the session. When specified, that userID will
+ * be used instead of the user's JID to track conversations. The server will ignore a
+ * manually specified userID if the user's connection to the server is not anonymous.
+ *
+ * @param metadata metadata to create a dataform from.
+ * @param userID String that represents the ID of the user when using anonymous sessions
+ * or <tt>null</tt> if a userID should not be used.
+ * @throws XMPPException if an error occured joining the queue. An error may indicate
+ * that a connection failure occured or that the server explicitly rejected the
+ * request to join the queue.
+ */
+ public void joinQueue(Map<String,Object> metadata, String userID) throws XMPPException {
+ // If already in the queue ignore the join request.
+ if (inQueue) {
+ throw new IllegalStateException("Already in queue " + workgroupJID);
+ }
+
+ // Build dataform from metadata
+ Form form = new Form(Form.TYPE_SUBMIT);
+ Iterator<String> iter = metadata.keySet().iterator();
+ while (iter.hasNext()) {
+ String name = iter.next();
+ String value = metadata.get(name).toString();
+
+ String escapedName = StringUtils.escapeForXML(name);
+ String escapedValue = StringUtils.escapeForXML(value);
+
+ FormField field = new FormField(escapedName);
+ field.setType(FormField.TYPE_TEXT_SINGLE);
+ form.addField(field);
+ form.setAnswer(escapedName, escapedValue);
+ }
+ joinQueue(form, userID);
+ }
+
+ /**
+ * Departs the workgroup queue. If the user is not currently in the queue, this
+ * method will do nothing.<p>
+ * <p/>
+ * Normally, the user would not manually leave the queue. However, they may wish to
+ * under certain circumstances -- for example, if they no longer wish to be routed
+ * to an agent because they've been waiting too long.
+ *
+ * @throws XMPPException if an error occured trying to send the depart queue
+ * request to the server.
+ */
+ public void departQueue() throws XMPPException {
+ // If not in the queue ignore the depart request.
+ if (!inQueue) {
+ return;
+ }
+
+ DepartQueuePacket departPacket = new DepartQueuePacket(this.workgroupJID);
+ PacketCollector collector = this.connection.createPacketCollector(new PacketIDFilter(departPacket.getPacketID()));
+
+ connection.sendPacket(departPacket);
+
+ IQ response = (IQ)collector.nextResult(5000);
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from the server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+
+ // Notify listeners that we're no longer in the queue.
+ fireQueueDepartedEvent();
+ }
+
+ /**
+ * Adds a queue listener that will be notified of queue events for the user
+ * that created this Workgroup instance.
+ *
+ * @param queueListener the queue listener.
+ */
+ public void addQueueListener(QueueListener queueListener) {
+ synchronized (queueListeners) {
+ if (!queueListeners.contains(queueListener)) {
+ queueListeners.add(queueListener);
+ }
+ }
+ }
+
+ /**
+ * Removes a queue listener.
+ *
+ * @param queueListener the queue listener.
+ */
+ public void removeQueueListener(QueueListener queueListener) {
+ synchronized (queueListeners) {
+ queueListeners.remove(queueListener);
+ }
+ }
+
+ /**
+ * Adds an invitation listener that will be notified of groupchat invitations
+ * from the workgroup for the the user that created this Workgroup instance.
+ *
+ * @param invitationListener the invitation listener.
+ */
+ public void addInvitationListener(WorkgroupInvitationListener invitationListener) {
+ synchronized (invitationListeners) {
+ if (!invitationListeners.contains(invitationListener)) {
+ invitationListeners.add(invitationListener);
+ }
+ }
+ }
+
+ /**
+ * Removes an invitation listener.
+ *
+ * @param invitationListener the invitation listener.
+ */
+ public void removeQueueListener(WorkgroupInvitationListener invitationListener) {
+ synchronized (invitationListeners) {
+ invitationListeners.remove(invitationListener);
+ }
+ }
+
+ private void fireInvitationEvent(WorkgroupInvitation invitation) {
+ synchronized (invitationListeners) {
+ for (Iterator<WorkgroupInvitationListener> i = invitationListeners.iterator(); i.hasNext();) {
+ WorkgroupInvitationListener listener = i.next();
+ listener.invitationReceived(invitation);
+ }
+ }
+ }
+
+ private void fireQueueJoinedEvent() {
+ synchronized (queueListeners) {
+ for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
+ QueueListener listener = i.next();
+ listener.joinedQueue();
+ }
+ }
+ }
+
+ private void fireQueueDepartedEvent() {
+ synchronized (queueListeners) {
+ for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
+ QueueListener listener = i.next();
+ listener.departedQueue();
+ }
+ }
+ }
+
+ private void fireQueuePositionEvent(int currentPosition) {
+ synchronized (queueListeners) {
+ for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
+ QueueListener listener = i.next();
+ listener.queuePositionUpdated(currentPosition);
+ }
+ }
+ }
+
+ private void fireQueueTimeEvent(int secondsRemaining) {
+ synchronized (queueListeners) {
+ for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) {
+ QueueListener listener = i.next();
+ listener.queueWaitTimeUpdated(secondsRemaining);
+ }
+ }
+ }
+
+ // PacketListener Implementation.
+
+ private void handlePacket(Packet packet) {
+ if (packet instanceof Message) {
+ Message msg = (Message)packet;
+ // Check to see if the user left the queue.
+ PacketExtension pe = msg.getExtension("depart-queue", "http://jabber.org/protocol/workgroup");
+ PacketExtension queueStatus = msg.getExtension("queue-status", "http://jabber.org/protocol/workgroup");
+
+ if (pe != null) {
+ fireQueueDepartedEvent();
+ }
+ else if (queueStatus != null) {
+ QueueUpdate queueUpdate = (QueueUpdate)queueStatus;
+ if (queueUpdate.getPosition() != -1) {
+ fireQueuePositionEvent(queueUpdate.getPosition());
+ }
+ if (queueUpdate.getRemaingTime() != -1) {
+ fireQueueTimeEvent(queueUpdate.getRemaingTime());
+ }
+ }
+
+ else {
+ // Check if a room invitation was sent and if the sender is the workgroup
+ MUCUser mucUser = (MUCUser)msg.getExtension("x", "http://jabber.org/protocol/muc#user");
+ MUCUser.Invite invite = mucUser != null ? mucUser.getInvite() : null;
+ if (invite != null && workgroupJID.equals(invite.getFrom())) {
+ String sessionID = null;
+ Map<String, List<String>> metaData = null;
+
+ pe = msg.getExtension(SessionID.ELEMENT_NAME,
+ SessionID.NAMESPACE);
+ if (pe != null) {
+ sessionID = ((SessionID)pe).getSessionID();
+ }
+
+ pe = msg.getExtension(MetaData.ELEMENT_NAME,
+ MetaData.NAMESPACE);
+ if (pe != null) {
+ metaData = ((MetaData)pe).getMetaData();
+ }
+
+ WorkgroupInvitation inv = new WorkgroupInvitation(connection.getUser(), msg.getFrom(),
+ workgroupJID, sessionID, msg.getBody(),
+ msg.getFrom(), metaData);
+
+ fireInvitationEvent(inv);
+ }
+ }
+ }
+ }
+
+ /**
+ * IQ packet to request joining the workgroup queue.
+ */
+ private class JoinQueuePacket extends IQ {
+
+ private String userID = null;
+ private DataForm form;
+
+ public JoinQueuePacket(String workgroup, Form answerForm, String userID) {
+ this.userID = userID;
+
+ setTo(workgroup);
+ setType(IQ.Type.SET);
+
+ form = answerForm.getDataFormToSend();
+ addExtension(form);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<join-queue xmlns=\"http://jabber.org/protocol/workgroup\">");
+ buf.append("<queue-notifications/>");
+ // Add the user unique identification if the session is anonymous
+ if (connection.isAnonymous()) {
+ buf.append(new UserID(userID).toXML());
+ }
+
+ // Append data form text
+ buf.append(form.toXML());
+
+ buf.append("</join-queue>");
+
+ return buf.toString();
+ }
+ }
+
+ /**
+ * Returns a single chat setting based on it's identified key.
+ *
+ * @param key the key to find.
+ * @return the ChatSetting if found, otherwise false.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public ChatSetting getChatSetting(String key) throws XMPPException {
+ ChatSettings chatSettings = getChatSettings(key, -1);
+ return chatSettings.getFirstEntry();
+ }
+
+ /**
+ * Returns ChatSettings based on type.
+ *
+ * @param type the type of ChatSettings to return.
+ * @return the ChatSettings of given type, otherwise null.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public ChatSettings getChatSettings(int type) throws XMPPException {
+ return getChatSettings(null, type);
+ }
+
+ /**
+ * Returns all ChatSettings.
+ *
+ * @return all ChatSettings of a given workgroup.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public ChatSettings getChatSettings() throws XMPPException {
+ return getChatSettings(null, -1);
+ }
+
+
+ /**
+ * Asks the workgroup for it's Chat Settings.
+ *
+ * @return key specify a key to retrieve only that settings. Otherwise for all settings, key should be null.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ private ChatSettings getChatSettings(String key, int type) throws XMPPException {
+ ChatSettings request = new ChatSettings();
+ if (key != null) {
+ request.setKey(key);
+ }
+ if (type != -1) {
+ request.setType(type);
+ }
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ ChatSettings response = (ChatSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * The workgroup service may be configured to send email. This queries the Workgroup Service
+ * to see if the email service has been configured and is available.
+ *
+ * @return true if the email service is available, otherwise return false.
+ */
+ public boolean isEmailAvailable() {
+ ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
+
+ try {
+ String workgroupService = StringUtils.parseServer(workgroupJID);
+ DiscoverInfo infoResult = discoManager.discoverInfo(workgroupService);
+ return infoResult.containsFeature("jive:email:provider");
+ }
+ catch (XMPPException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Asks the workgroup for it's Offline Settings.
+ *
+ * @return offlineSettings the offline settings for this workgroup.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public OfflineSettings getOfflineSettings() throws XMPPException {
+ OfflineSettings request = new OfflineSettings();
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ OfflineSettings response = (OfflineSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * Asks the workgroup for it's Sound Settings.
+ *
+ * @return soundSettings the sound settings for the specified workgroup.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public SoundSettings getSoundSettings() throws XMPPException {
+ SoundSettings request = new SoundSettings();
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ SoundSettings response = (SoundSettings)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * Asks the workgroup for it's Properties
+ *
+ * @return the WorkgroupProperties for the specified workgroup.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public WorkgroupProperties getWorkgroupProperties() throws XMPPException {
+ WorkgroupProperties request = new WorkgroupProperties();
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ WorkgroupProperties response = (WorkgroupProperties)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+ /**
+ * Asks the workgroup for it's Properties
+ *
+ * @param jid the jid of the user who's information you would like the workgroup to retreive.
+ * @return the WorkgroupProperties for the specified workgroup.
+ * @throws XMPPException if an error occurs while getting information from the server.
+ */
+ public WorkgroupProperties getWorkgroupProperties(String jid) throws XMPPException {
+ WorkgroupProperties request = new WorkgroupProperties();
+ request.setJid(jid);
+ request.setType(IQ.Type.GET);
+ request.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
+ connection.sendPacket(request);
+
+
+ WorkgroupProperties response = (WorkgroupProperties)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return response;
+ }
+
+
+ /**
+ * Returns the Form to use for all clients of a workgroup. It is unlikely that the server
+ * will change the form (without a restart) so it is safe to keep the returned form
+ * for future submissions.
+ *
+ * @return the Form to use for searching transcripts.
+ * @throws XMPPException if an error occurs while sending the request to the server.
+ */
+ public Form getWorkgroupForm() throws XMPPException {
+ WorkgroupForm workgroupForm = new WorkgroupForm();
+ workgroupForm.setType(IQ.Type.GET);
+ workgroupForm.setTo(workgroupJID);
+
+ PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(workgroupForm.getPacketID()));
+ connection.sendPacket(workgroupForm);
+
+ WorkgroupForm response = (WorkgroupForm)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
+
+ // Cancel the collector.
+ collector.cancel();
+ if (response == null) {
+ throw new XMPPException("No response from server on status set.");
+ }
+ if (response.getError() != null) {
+ throw new XMPPException(response.getError());
+ }
+ return Form.getFormFrom(response);
+ }
+
+ /*
+ public static void main(String args[]) throws Exception {
+ Connection con = new XMPPConnection("anteros");
+ con.connect();
+ con.loginAnonymously();
+
+ Workgroup workgroup = new Workgroup("demo@workgroup.anteros", con);
+ WorkgroupProperties props = workgroup.getWorkgroupProperties("derek@anteros.com");
+
+ System.out.print(props);
+ con.disconnect();
+ }
+ */
+
+
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ListenerEventDispatcher.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ListenerEventDispatcher.java
index 533b9a132..23767015f 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ListenerEventDispatcher.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ListenerEventDispatcher.java
@@ -1,132 +1,132 @@
-/**
- * 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
- *
- * 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.workgroup.util;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.ListIterator;
-
-/**
- * This class is a very flexible event dispatcher which implements Runnable so that it can
- * dispatch easily from a newly created thread. The usage of this in code is more or less:
- * create a new instance of this class, use addListenerTriplet to add as many listeners
- * as desired to be messaged, create a new Thread using the instance of this class created
- * as the argument to the constructor, start the new Thread instance.<p>
- *
- * Also, this is intended to be used to message methods that either return void, or have
- * a return which the developer using this class is uninterested in receiving.
- *
- * @author loki der quaeler
- */
-public class ListenerEventDispatcher
- implements Runnable {
-
- protected transient ArrayList<TripletContainer> triplets;
-
- protected transient boolean hasFinishedDispatching;
- protected transient boolean isRunning;
-
- public ListenerEventDispatcher () {
- super();
-
- this.triplets = new ArrayList<TripletContainer>();
-
- this.hasFinishedDispatching = false;
- this.isRunning = false;
- }
-
- /**
- * Add a listener triplet - the instance of the listener to be messaged, the Method on which
- * the listener should be messaged, and the Object array of arguments to be supplied to the
- * Method. No attempts are made to determine whether this triplet was already added.<br>
- *
- * Messages are dispatched in the order in which they're added via this method; so if triplet
- * X is added after triplet Z, then triplet Z will undergo messaging prior to triplet X.<br>
- *
- * This method should not be called once the owning Thread instance has been started; if it
- * is called, the triplet will not be added to the messaging queue.<br>
- *
- * @param listenerInstance the instance of the listener to receive the associated notification
- * @param listenerMethod the Method instance representing the method through which notification
- * will occur
- * @param methodArguments the arguments supplied to the notification method
- */
- public void addListenerTriplet(Object listenerInstance, Method listenerMethod,
- Object[] methodArguments)
- {
- if (!this.isRunning) {
- this.triplets.add(new TripletContainer(listenerInstance, listenerMethod,
- methodArguments));
- }
- }
-
- /**
- * @return whether this instance has finished dispatching its messages
- */
- public boolean hasFinished() {
- return this.hasFinishedDispatching;
- }
-
- public void run() {
- ListIterator<TripletContainer> li = null;
-
- this.isRunning = true;
-
- li = this.triplets.listIterator();
- while (li.hasNext()) {
- TripletContainer tc = li.next();
-
- try {
- tc.getListenerMethod().invoke(tc.getListenerInstance(), tc.getMethodArguments());
- } catch (Exception e) {
- System.err.println("Exception dispatching an event: " + e);
-
- e.printStackTrace();
- }
- }
-
- this.hasFinishedDispatching = true;
- }
-
-
- protected class TripletContainer {
-
- protected Object listenerInstance;
- protected Method listenerMethod;
- protected Object[] methodArguments;
-
- protected TripletContainer (Object inst, Method meth, Object[] args) {
- super();
-
- this.listenerInstance = inst;
- this.listenerMethod = meth;
- this.methodArguments = args;
- }
-
- protected Object getListenerInstance() {
- return this.listenerInstance;
- }
-
- protected Method getListenerMethod() {
- return this.listenerMethod;
- }
-
- protected Object[] getMethodArguments() {
- return this.methodArguments;
- }
- }
+/**
+ * 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
+ *
+ * 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.workgroup.util;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.ListIterator;
+
+/**
+ * This class is a very flexible event dispatcher which implements Runnable so that it can
+ * dispatch easily from a newly created thread. The usage of this in code is more or less:
+ * create a new instance of this class, use addListenerTriplet to add as many listeners
+ * as desired to be messaged, create a new Thread using the instance of this class created
+ * as the argument to the constructor, start the new Thread instance.<p>
+ *
+ * Also, this is intended to be used to message methods that either return void, or have
+ * a return which the developer using this class is uninterested in receiving.
+ *
+ * @author loki der quaeler
+ */
+public class ListenerEventDispatcher
+ implements Runnable {
+
+ protected transient ArrayList<TripletContainer> triplets;
+
+ protected transient boolean hasFinishedDispatching;
+ protected transient boolean isRunning;
+
+ public ListenerEventDispatcher () {
+ super();
+
+ this.triplets = new ArrayList<TripletContainer>();
+
+ this.hasFinishedDispatching = false;
+ this.isRunning = false;
+ }
+
+ /**
+ * Add a listener triplet - the instance of the listener to be messaged, the Method on which
+ * the listener should be messaged, and the Object array of arguments to be supplied to the
+ * Method. No attempts are made to determine whether this triplet was already added.<br>
+ *
+ * Messages are dispatched in the order in which they're added via this method; so if triplet
+ * X is added after triplet Z, then triplet Z will undergo messaging prior to triplet X.<br>
+ *
+ * This method should not be called once the owning Thread instance has been started; if it
+ * is called, the triplet will not be added to the messaging queue.<br>
+ *
+ * @param listenerInstance the instance of the listener to receive the associated notification
+ * @param listenerMethod the Method instance representing the method through which notification
+ * will occur
+ * @param methodArguments the arguments supplied to the notification method
+ */
+ public void addListenerTriplet(Object listenerInstance, Method listenerMethod,
+ Object[] methodArguments)
+ {
+ if (!this.isRunning) {
+ this.triplets.add(new TripletContainer(listenerInstance, listenerMethod,
+ methodArguments));
+ }
+ }
+
+ /**
+ * @return whether this instance has finished dispatching its messages
+ */
+ public boolean hasFinished() {
+ return this.hasFinishedDispatching;
+ }
+
+ public void run() {
+ ListIterator<TripletContainer> li = null;
+
+ this.isRunning = true;
+
+ li = this.triplets.listIterator();
+ while (li.hasNext()) {
+ TripletContainer tc = li.next();
+
+ try {
+ tc.getListenerMethod().invoke(tc.getListenerInstance(), tc.getMethodArguments());
+ } catch (Exception e) {
+ System.err.println("Exception dispatching an event: " + e);
+
+ e.printStackTrace();
+ }
+ }
+
+ this.hasFinishedDispatching = true;
+ }
+
+
+ protected class TripletContainer {
+
+ protected Object listenerInstance;
+ protected Method listenerMethod;
+ protected Object[] methodArguments;
+
+ protected TripletContainer (Object inst, Method meth, Object[] args) {
+ super();
+
+ this.listenerInstance = inst;
+ this.listenerMethod = meth;
+ this.methodArguments = args;
+ }
+
+ protected Object getListenerInstance() {
+ return this.listenerInstance;
+ }
+
+ protected Method getListenerMethod() {
+ return this.listenerMethod;
+ }
+
+ protected Object[] getMethodArguments() {
+ return this.methodArguments;
+ }
+ }
} \ No newline at end of file
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java
index 5be1c1a42..7f8df0d78 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/MetaDataUtils.java
@@ -1,103 +1,103 @@
-/**
- * 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
- *
- * 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.workgroup.util;
-
-import org.jivesoftware.smackx.workgroup.MetaData;
-import org.jivesoftware.smack.util.StringUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.*;
-
-/**
- * Utility class for meta-data parsing and writing.
- *
- * @author Matt Tucker
- */
-public class MetaDataUtils {
-
- /**
- * Parses any available meta-data and returns it as a Map of String name/value pairs. The
- * parser must be positioned at an opening meta-data tag, or the an empty map will be returned.
- *
- * @param parser the XML parser positioned at an opening meta-data tag.
- * @return the meta-data.
- * @throws XmlPullParserException if an error occurs while parsing the XML.
- * @throws IOException if an error occurs while parsing the XML.
- */
- public static Map<String, List<String>> parseMetaData(XmlPullParser parser) throws XmlPullParserException, IOException {
- int eventType = parser.getEventType();
-
- // If correctly positioned on an opening meta-data tag, parse meta-data.
- if ((eventType == XmlPullParser.START_TAG)
- && parser.getName().equals(MetaData.ELEMENT_NAME)
- && parser.getNamespace().equals(MetaData.NAMESPACE)) {
- Map<String, List<String>> metaData = new Hashtable<String, List<String>>();
-
- eventType = parser.nextTag();
-
- // Keep parsing until we've gotten to end of meta-data.
- while ((eventType != XmlPullParser.END_TAG)
- || (!parser.getName().equals(MetaData.ELEMENT_NAME))) {
- String name = parser.getAttributeValue(0);
- String value = parser.nextText();
-
- if (metaData.containsKey(name)) {
- List<String> values = metaData.get(name);
- values.add(value);
- }
- else {
- List<String> values = new ArrayList<String>();
- values.add(value);
- metaData.put(name, values);
- }
-
- eventType = parser.nextTag();
- }
-
- return metaData;
- }
-
- return Collections.emptyMap();
- }
-
- /**
- * Serializes a Map of String name/value pairs into the meta-data XML format.
- *
- * @param metaData the Map of meta-data as Map&lt;String,List&lt;String>>
- * @return the meta-data values in XML form.
- */
- public static String serializeMetaData(Map<String, List<String>> metaData) {
- StringBuilder buf = new StringBuilder();
- if (metaData != null && metaData.size() > 0) {
- buf.append("<metadata xmlns=\"http://jivesoftware.com/protocol/workgroup\">");
- for (Iterator<String> i = metaData.keySet().iterator(); i.hasNext();) {
- String key = i.next();
- List<String> value = metaData.get(key);
- for (Iterator<String> it = value.iterator(); it.hasNext();) {
- String v = it.next();
- buf.append("<value name=\"").append(key).append("\">");
- buf.append(StringUtils.escapeForXML(v));
- buf.append("</value>");
- }
- }
- buf.append("</metadata>");
- }
- return buf.toString();
- }
-}
+/**
+ * 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
+ *
+ * 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.workgroup.util;
+
+import org.jivesoftware.smackx.workgroup.MetaData;
+import org.jivesoftware.smack.util.StringUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Utility class for meta-data parsing and writing.
+ *
+ * @author Matt Tucker
+ */
+public class MetaDataUtils {
+
+ /**
+ * Parses any available meta-data and returns it as a Map of String name/value pairs. The
+ * parser must be positioned at an opening meta-data tag, or the an empty map will be returned.
+ *
+ * @param parser the XML parser positioned at an opening meta-data tag.
+ * @return the meta-data.
+ * @throws XmlPullParserException if an error occurs while parsing the XML.
+ * @throws IOException if an error occurs while parsing the XML.
+ */
+ public static Map<String, List<String>> parseMetaData(XmlPullParser parser) throws XmlPullParserException, IOException {
+ int eventType = parser.getEventType();
+
+ // If correctly positioned on an opening meta-data tag, parse meta-data.
+ if ((eventType == XmlPullParser.START_TAG)
+ && parser.getName().equals(MetaData.ELEMENT_NAME)
+ && parser.getNamespace().equals(MetaData.NAMESPACE)) {
+ Map<String, List<String>> metaData = new Hashtable<String, List<String>>();
+
+ eventType = parser.nextTag();
+
+ // Keep parsing until we've gotten to end of meta-data.
+ while ((eventType != XmlPullParser.END_TAG)
+ || (!parser.getName().equals(MetaData.ELEMENT_NAME))) {
+ String name = parser.getAttributeValue(0);
+ String value = parser.nextText();
+
+ if (metaData.containsKey(name)) {
+ List<String> values = metaData.get(name);
+ values.add(value);
+ }
+ else {
+ List<String> values = new ArrayList<String>();
+ values.add(value);
+ metaData.put(name, values);
+ }
+
+ eventType = parser.nextTag();
+ }
+
+ return metaData;
+ }
+
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Serializes a Map of String name/value pairs into the meta-data XML format.
+ *
+ * @param metaData the Map of meta-data as Map&lt;String,List&lt;String>>
+ * @return the meta-data values in XML form.
+ */
+ public static String serializeMetaData(Map<String, List<String>> metaData) {
+ StringBuilder buf = new StringBuilder();
+ if (metaData != null && metaData.size() > 0) {
+ buf.append("<metadata xmlns=\"http://jivesoftware.com/protocol/workgroup\">");
+ for (Iterator<String> i = metaData.keySet().iterator(); i.hasNext();) {
+ String key = i.next();
+ List<String> value = metaData.get(key);
+ for (Iterator<String> it = value.iterator(); it.hasNext();) {
+ String v = it.next();
+ buf.append("<value name=\"").append(key).append("\">");
+ buf.append(StringUtils.escapeForXML(v));
+ buf.append("</value>");
+ }
+ }
+ buf.append("</metadata>");
+ }
+ return buf.toString();
+ }
+}
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ModelUtil.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ModelUtil.java
index 06a72b08f..7f0c59bb0 100644
--- a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ModelUtil.java
+++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/workgroup/util/ModelUtil.java
@@ -1,321 +1,321 @@
-/**
- * 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
- *
- * 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.workgroup.util;
-
-import java.util.*;
-
-/**
- * Utility methods frequently used by data classes and design-time
- * classes.
- */
-public final class ModelUtil {
- private ModelUtil() {
- // Prevents instantiation.
- }
-
- /**
- * This is a utility method that compares two objects when one or
- * both of the objects might be <CODE>null</CODE> The result of
- * this method is determined as follows:
- * <OL>
- * <LI>If <CODE>o1</CODE> and <CODE>o2</CODE> are the same object
- * according to the <CODE>==</CODE> operator, return
- * <CODE>true</CODE>.
- * <LI>Otherwise, if either <CODE>o1</CODE> or <CODE>o2</CODE> is
- * <CODE>null</CODE>, return <CODE>false</CODE>.
- * <LI>Otherwise, return <CODE>o1.equals(o2)</CODE>.
- * </OL>
- * <p/>
- * This method produces the exact logically inverted result as the
- * {@link #areDifferent(Object, Object)} method.<P>
- * <p/>
- * For array types, one of the <CODE>equals</CODE> methods in
- * {@link java.util.Arrays} should be used instead of this method.
- * Note that arrays with more than one dimension will require some
- * custom code in order to implement <CODE>equals</CODE> properly.
- */
- public static final boolean areEqual(Object o1, Object o2) {
- if (o1 == o2) {
- return true;
- }
- else if (o1 == null || o2 == null) {
- return false;
- }
- else {
- return o1.equals(o2);
- }
- }
-
- /**
- * This is a utility method that compares two Booleans when one or
- * both of the objects might be <CODE>null</CODE> The result of
- * this method is determined as follows:
- * <OL>
- * <LI>If <CODE>b1</CODE> and <CODE>b2</CODE> are both TRUE or
- * neither <CODE>b1</CODE> nor <CODE>b2</CODE> is TRUE,
- * return <CODE>true</CODE>.
- * <LI>Otherwise, return <CODE>false</CODE>.
- * </OL>
- * <p/>
- */
- public static final boolean areBooleansEqual(Boolean b1, Boolean b2) {
- // !jwetherb treat NULL the same as Boolean.FALSE
- return (b1 == Boolean.TRUE && b2 == Boolean.TRUE) ||
- (b1 != Boolean.TRUE && b2 != Boolean.TRUE);
- }
-
- /**
- * This is a utility method that compares two objects when one or
- * both of the objects might be <CODE>null</CODE>. The result
- * returned by this method is determined as follows:
- * <OL>
- * <LI>If <CODE>o1</CODE> and <CODE>o2</CODE> are the same object
- * according to the <CODE>==</CODE> operator, return
- * <CODE>false</CODE>.
- * <LI>Otherwise, if either <CODE>o1</CODE> or <CODE>o2</CODE> is
- * <CODE>null</CODE>, return <CODE>true</CODE>.
- * <LI>Otherwise, return <CODE>!o1.equals(o2)</CODE>.
- * </OL>
- * <p/>
- * This method produces the exact logically inverted result as the
- * {@link #areEqual(Object, Object)} method.<P>
- * <p/>
- * For array types, one of the <CODE>equals</CODE> methods in
- * {@link java.util.Arrays} should be used instead of this method.
- * Note that arrays with more than one dimension will require some
- * custom code in order to implement <CODE>equals</CODE> properly.
- */
- public static final boolean areDifferent(Object o1, Object o2) {
- return !areEqual(o1, o2);
- }
-
-
- /**
- * This is a utility method that compares two Booleans when one or
- * both of the objects might be <CODE>null</CODE> The result of
- * this method is determined as follows:
- * <OL>
- * <LI>If <CODE>b1</CODE> and <CODE>b2</CODE> are both TRUE or
- * neither <CODE>b1</CODE> nor <CODE>b2</CODE> is TRUE,
- * return <CODE>false</CODE>.
- * <LI>Otherwise, return <CODE>true</CODE>.
- * </OL>
- * <p/>
- * This method produces the exact logically inverted result as the
- * {@link #areBooleansEqual(Boolean, Boolean)} method.<P>
- */
- public static final boolean areBooleansDifferent(Boolean b1, Boolean b2) {
- return !areBooleansEqual(b1, b2);
- }
-
-
- /**
- * Returns <CODE>true</CODE> if the specified array is not null
- * and contains a non-null element. Returns <CODE>false</CODE>
- * if the array is null or if all the array elements are null.
- */
- public static final boolean hasNonNullElement(Object[] array) {
- if (array != null) {
- final int n = array.length;
- for (int i = 0; i < n; i++) {
- if (array[i] != null) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Returns a single string that is the concatenation of all the
- * strings in the specified string array. A single space is
- * put between each string array element. Null array elements
- * are skipped. If the array itself is null, the empty string
- * is returned. This method is guaranteed to return a non-null
- * value, if no expections are thrown.
- */
- public static final String concat(String[] strs) {
- return concat(strs, " "); //NOTRANS
- }
-
- /**
- * Returns a single string that is the concatenation of all the
- * strings in the specified string array. The strings are separated
- * by the specified delimiter. Null array elements are skipped. If
- * the array itself is null, the empty string is returned. This
- * method is guaranteed to return a non-null value, if no expections
- * are thrown.
- */
- public static final String concat(String[] strs, String delim) {
- if (strs != null) {
- final StringBuilder buf = new StringBuilder();
- final int n = strs.length;
- for (int i = 0; i < n; i++) {
- final String str = strs[i];
- if (str != null) {
- buf.append(str).append(delim);
- }
- }
- final int length = buf.length();
- if (length > 0) {
- // Trim trailing space.
- buf.setLength(length - 1);
- }
- return buf.toString();
- }
- else {
- return ""; // NOTRANS
- }
- }
-
- /**
- * Returns <CODE>true</CODE> if the specified {@link String} is not
- * <CODE>null</CODE> and has a length greater than zero. This is
- * a very frequently occurring check.
- */
- public static final boolean hasLength(String s) {
- return (s != null && s.length() > 0);
- }
-
-
- /**
- * Returns <CODE>null</CODE> if the specified string is empty or
- * <CODE>null</CODE>. Otherwise the string itself is returned.
- */
- public static final String nullifyIfEmpty(String s) {
- return ModelUtil.hasLength(s) ? s : null;
- }
-
- /**
- * Returns <CODE>null</CODE> if the specified object is null
- * or if its <CODE>toString()</CODE> representation is empty.
- * Otherwise, the <CODE>toString()</CODE> representation of the
- * object itself is returned.
- */
- public static final String nullifyingToString(Object o) {
- return o != null ? nullifyIfEmpty(o.toString()) : null;
- }
-
- /**
- * Determines if a string has been changed.
- *
- * @param oldString is the initial value of the String
- * @param newString is the new value of the String
- * @return true If both oldString and newString are null or if they are
- * both not null and equal to each other. Otherwise returns false.
- */
- public static boolean hasStringChanged(String oldString, String newString) {
- if (oldString == null && newString == null) {
- return false;
- }
- else if ((oldString == null && newString != null)
- || (oldString != null && newString == null)) {
- return true;
- }
- else {
- return !oldString.equals(newString);
- }
- }
-
- public static String getTimeFromLong(long diff) {
- final String HOURS = "h";
- final String MINUTES = "min";
- final String SECONDS = "sec";
-
- final long MS_IN_A_DAY = 1000 * 60 * 60 * 24;
- final long MS_IN_AN_HOUR = 1000 * 60 * 60;
- final long MS_IN_A_MINUTE = 1000 * 60;
- final long MS_IN_A_SECOND = 1000;
- diff = diff % MS_IN_A_DAY;
- long numHours = diff / MS_IN_AN_HOUR;
- diff = diff % MS_IN_AN_HOUR;
- long numMinutes = diff / MS_IN_A_MINUTE;
- diff = diff % MS_IN_A_MINUTE;
- long numSeconds = diff / MS_IN_A_SECOND;
- diff = diff % MS_IN_A_SECOND;
-
- StringBuilder buf = new StringBuilder();
- if (numHours > 0) {
- buf.append(numHours + " " + HOURS + ", ");
- }
-
- if (numMinutes > 0) {
- buf.append(numMinutes + " " + MINUTES + ", ");
- }
-
- buf.append(numSeconds + " " + SECONDS);
-
- String result = buf.toString();
- return result;
- }
-
-
- /**
- * Build a List of all elements in an Iterator.
- */
- public static <T> List<T> iteratorAsList(Iterator<T> i) {
- ArrayList<T> list = new ArrayList<T>(10);
- while (i.hasNext()) {
- list.add(i.next());
- }
- return list;
- }
-
- /**
- * Creates an Iterator that is the reverse of a ListIterator.
- */
- public static <T> Iterator<T> reverseListIterator(ListIterator<T> i) {
- return new ReverseListIterator<T>(i);
- }
-}
-
-/**
- * An Iterator that is the reverse of a ListIterator.
- */
-class ReverseListIterator<T> implements Iterator<T> {
- private ListIterator<T> _i;
-
- ReverseListIterator(ListIterator<T> i) {
- _i = i;
- while (_i.hasNext())
- _i.next();
- }
-
- public boolean hasNext() {
- return _i.hasPrevious();
- }
-
- public T next() {
- return _i.previous();
- }
-
- public void remove() {
- _i.remove();
- }
-
-}
-
-
-
-
-
-
-
-
-
-
-
+/**
+ * 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
+ *
+ * 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.workgroup.util;
+
+import java.util.*;
+
+/**
+ * Utility methods frequently used by data classes and design-time
+ * classes.
+ */
+public final class ModelUtil {
+ private ModelUtil() {
+ // Prevents instantiation.
+ }
+
+ /**
+ * This is a utility method that compares two objects when one or
+ * both of the objects might be <CODE>null</CODE> The result of
+ * this method is determined as follows:
+ * <OL>
+ * <LI>If <CODE>o1</CODE> and <CODE>o2</CODE> are the same object
+ * according to the <CODE>==</CODE> operator, return
+ * <CODE>true</CODE>.
+ * <LI>Otherwise, if either <CODE>o1</CODE> or <CODE>o2</CODE> is
+ * <CODE>null</CODE>, return <CODE>false</CODE>.
+ * <LI>Otherwise, return <CODE>o1.equals(o2)</CODE>.
+ * </OL>
+ * <p/>
+ * This method produces the exact logically inverted result as the
+ * {@link #areDifferent(Object, Object)} method.<P>
+ * <p/>
+ * For array types, one of the <CODE>equals</CODE> methods in
+ * {@link java.util.Arrays} should be used instead of this method.
+ * Note that arrays with more than one dimension will require some
+ * custom code in order to implement <CODE>equals</CODE> properly.
+ */
+ public static final boolean areEqual(Object o1, Object o2) {
+ if (o1 == o2) {
+ return true;
+ }
+ else if (o1 == null || o2 == null) {
+ return false;
+ }
+ else {
+ return o1.equals(o2);
+ }
+ }
+
+ /**
+ * This is a utility method that compares two Booleans when one or
+ * both of the objects might be <CODE>null</CODE> The result of
+ * this method is determined as follows:
+ * <OL>
+ * <LI>If <CODE>b1</CODE> and <CODE>b2</CODE> are both TRUE or
+ * neither <CODE>b1</CODE> nor <CODE>b2</CODE> is TRUE,
+ * return <CODE>true</CODE>.
+ * <LI>Otherwise, return <CODE>false</CODE>.
+ * </OL>
+ * <p/>
+ */
+ public static final boolean areBooleansEqual(Boolean b1, Boolean b2) {
+ // !jwetherb treat NULL the same as Boolean.FALSE
+ return (b1 == Boolean.TRUE && b2 == Boolean.TRUE) ||
+ (b1 != Boolean.TRUE && b2 != Boolean.TRUE);
+ }
+
+ /**
+ * This is a utility method that compares two objects when one or
+ * both of the objects might be <CODE>null</CODE>. The result
+ * returned by this method is determined as follows:
+ * <OL>
+ * <LI>If <CODE>o1</CODE> and <CODE>o2</CODE> are the same object
+ * according to the <CODE>==</CODE> operator, return
+ * <CODE>false</CODE>.
+ * <LI>Otherwise, if either <CODE>o1</CODE> or <CODE>o2</CODE> is
+ * <CODE>null</CODE>, return <CODE>true</CODE>.
+ * <LI>Otherwise, return <CODE>!o1.equals(o2)</CODE>.
+ * </OL>
+ * <p/>
+ * This method produces the exact logically inverted result as the
+ * {@link #areEqual(Object, Object)} method.<P>
+ * <p/>
+ * For array types, one of the <CODE>equals</CODE> methods in
+ * {@link java.util.Arrays} should be used instead of this method.
+ * Note that arrays with more than one dimension will require some
+ * custom code in order to implement <CODE>equals</CODE> properly.
+ */
+ public static final boolean areDifferent(Object o1, Object o2) {
+ return !areEqual(o1, o2);
+ }
+
+
+ /**
+ * This is a utility method that compares two Booleans when one or
+ * both of the objects might be <CODE>null</CODE> The result of
+ * this method is determined as follows:
+ * <OL>
+ * <LI>If <CODE>b1</CODE> and <CODE>b2</CODE> are both TRUE or
+ * neither <CODE>b1</CODE> nor <CODE>b2</CODE> is TRUE,
+ * return <CODE>false</CODE>.
+ * <LI>Otherwise, return <CODE>true</CODE>.
+ * </OL>
+ * <p/>
+ * This method produces the exact logically inverted result as the
+ * {@link #areBooleansEqual(Boolean, Boolean)} method.<P>
+ */
+ public static final boolean areBooleansDifferent(Boolean b1, Boolean b2) {
+ return !areBooleansEqual(b1, b2);
+ }
+
+
+ /**
+ * Returns <CODE>true</CODE> if the specified array is not null
+ * and contains a non-null element. Returns <CODE>false</CODE>
+ * if the array is null or if all the array elements are null.
+ */
+ public static final boolean hasNonNullElement(Object[] array) {
+ if (array != null) {
+ final int n = array.length;
+ for (int i = 0; i < n; i++) {
+ if (array[i] != null) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns a single string that is the concatenation of all the
+ * strings in the specified string array. A single space is
+ * put between each string array element. Null array elements
+ * are skipped. If the array itself is null, the empty string
+ * is returned. This method is guaranteed to return a non-null
+ * value, if no expections are thrown.
+ */
+ public static final String concat(String[] strs) {
+ return concat(strs, " "); //NOTRANS
+ }
+
+ /**
+ * Returns a single string that is the concatenation of all the
+ * strings in the specified string array. The strings are separated
+ * by the specified delimiter. Null array elements are skipped. If
+ * the array itself is null, the empty string is returned. This
+ * method is guaranteed to return a non-null value, if no expections
+ * are thrown.
+ */
+ public static final String concat(String[] strs, String delim) {
+ if (strs != null) {
+ final StringBuilder buf = new StringBuilder();
+ final int n = strs.length;
+ for (int i = 0; i < n; i++) {
+ final String str = strs[i];
+ if (str != null) {
+ buf.append(str).append(delim);
+ }
+ }
+ final int length = buf.length();
+ if (length > 0) {
+ // Trim trailing space.
+ buf.setLength(length - 1);
+ }
+ return buf.toString();
+ }
+ else {
+ return ""; // NOTRANS
+ }
+ }
+
+ /**
+ * Returns <CODE>true</CODE> if the specified {@link String} is not
+ * <CODE>null</CODE> and has a length greater than zero. This is
+ * a very frequently occurring check.
+ */
+ public static final boolean hasLength(String s) {
+ return (s != null && s.length() > 0);
+ }
+
+
+ /**
+ * Returns <CODE>null</CODE> if the specified string is empty or
+ * <CODE>null</CODE>. Otherwise the string itself is returned.
+ */
+ public static final String nullifyIfEmpty(String s) {
+ return ModelUtil.hasLength(s) ? s : null;
+ }
+
+ /**
+ * Returns <CODE>null</CODE> if the specified object is null
+ * or if its <CODE>toString()</CODE> representation is empty.
+ * Otherwise, the <CODE>toString()</CODE> representation of the
+ * object itself is returned.
+ */
+ public static final String nullifyingToString(Object o) {
+ return o != null ? nullifyIfEmpty(o.toString()) : null;
+ }
+
+ /**
+ * Determines if a string has been changed.
+ *
+ * @param oldString is the initial value of the String
+ * @param newString is the new value of the String
+ * @return true If both oldString and newString are null or if they are
+ * both not null and equal to each other. Otherwise returns false.
+ */
+ public static boolean hasStringChanged(String oldString, String newString) {
+ if (oldString == null && newString == null) {
+ return false;
+ }
+ else if ((oldString == null && newString != null)
+ || (oldString != null && newString == null)) {
+ return true;
+ }
+ else {
+ return !oldString.equals(newString);
+ }
+ }
+
+ public static String getTimeFromLong(long diff) {
+ final String HOURS = "h";
+ final String MINUTES = "min";
+ final String SECONDS = "sec";
+
+ final long MS_IN_A_DAY = 1000 * 60 * 60 * 24;
+ final long MS_IN_AN_HOUR = 1000 * 60 * 60;
+ final long MS_IN_A_MINUTE = 1000 * 60;
+ final long MS_IN_A_SECOND = 1000;
+ diff = diff % MS_IN_A_DAY;
+ long numHours = diff / MS_IN_AN_HOUR;
+ diff = diff % MS_IN_AN_HOUR;
+ long numMinutes = diff / MS_IN_A_MINUTE;
+ diff = diff % MS_IN_A_MINUTE;
+ long numSeconds = diff / MS_IN_A_SECOND;
+ diff = diff % MS_IN_A_SECOND;
+
+ StringBuilder buf = new StringBuilder();
+ if (numHours > 0) {
+ buf.append(numHours + " " + HOURS + ", ");
+ }
+
+ if (numMinutes > 0) {
+ buf.append(numMinutes + " " + MINUTES + ", ");
+ }
+
+ buf.append(numSeconds + " " + SECONDS);
+
+ String result = buf.toString();
+ return result;
+ }
+
+
+ /**
+ * Build a List of all elements in an Iterator.
+ */
+ public static <T> List<T> iteratorAsList(Iterator<T> i) {
+ ArrayList<T> list = new ArrayList<T>(10);
+ while (i.hasNext()) {
+ list.add(i.next());
+ }
+ return list;
+ }
+
+ /**
+ * Creates an Iterator that is the reverse of a ListIterator.
+ */
+ public static <T> Iterator<T> reverseListIterator(ListIterator<T> i) {
+ return new ReverseListIterator<T>(i);
+ }
+}
+
+/**
+ * An Iterator that is the reverse of a ListIterator.
+ */
+class ReverseListIterator<T> implements Iterator<T> {
+ private ListIterator<T> _i;
+
+ ReverseListIterator(ListIterator<T> i) {
+ _i = i;
+ while (_i.hasNext())
+ _i.next();
+ }
+
+ public boolean hasNext() {
+ return _i.hasPrevious();
+ }
+
+ public T next() {
+ return _i.previous();
+ }
+
+ public void remove() {
+ _i.remove();
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+

Back to the top