| /** |
| * Copyright 2013 Georg Lukas |
| * |
| * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.jivesoftware.smackx.carbons; |
| |
| import java.util.Collections; |
| import java.util.Map; |
| import java.util.WeakHashMap; |
| |
| import org.jivesoftware.smack.Connection; |
| import org.jivesoftware.smack.ConnectionCreationListener; |
| import org.jivesoftware.smack.PacketCollector; |
| import org.jivesoftware.smack.PacketListener; |
| import org.jivesoftware.smack.SmackConfiguration; |
| import org.jivesoftware.smack.XMPPException; |
| import org.jivesoftware.smack.filter.PacketIDFilter; |
| import org.jivesoftware.smack.packet.IQ; |
| import org.jivesoftware.smack.packet.Message; |
| import org.jivesoftware.smack.packet.Packet; |
| import org.jivesoftware.smackx.ServiceDiscoveryManager; |
| import org.jivesoftware.smackx.packet.DiscoverInfo; |
| |
| /** |
| * Packet extension for XEP-0280: Message Carbons. This class implements |
| * the manager for registering {@link Carbon} support, enabling and disabling |
| * message carbons. |
| * |
| * You should call enableCarbons() before sending your first undirected |
| * presence. |
| * |
| * @author Georg Lukas |
| */ |
| public class CarbonManager { |
| |
| private static Map<Connection, CarbonManager> instances = |
| Collections.synchronizedMap(new WeakHashMap<Connection, CarbonManager>()); |
| |
| static { |
| Connection.addConnectionCreationListener(new ConnectionCreationListener() { |
| public void connectionCreated(Connection connection) { |
| new CarbonManager(connection); |
| } |
| }); |
| } |
| |
| private Connection connection; |
| private volatile boolean enabled_state = false; |
| |
| private CarbonManager(Connection connection) { |
| ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); |
| sdm.addFeature(Carbon.NAMESPACE); |
| this.connection = connection; |
| instances.put(connection, this); |
| } |
| |
| /** |
| * Obtain the CarbonManager responsible for a connection. |
| * |
| * @param connection the connection object. |
| * |
| * @return a CarbonManager instance |
| */ |
| public static CarbonManager getInstanceFor(Connection connection) { |
| CarbonManager carbonManager = instances.get(connection); |
| |
| if (carbonManager == null) { |
| carbonManager = new CarbonManager(connection); |
| } |
| |
| return carbonManager; |
| } |
| |
| private IQ carbonsEnabledIQ(final boolean new_state) { |
| IQ setIQ = new IQ() { |
| public String getChildElementXML() { |
| return "<" + (new_state? "enable" : "disable") + " xmlns='" + Carbon.NAMESPACE + "'/>"; |
| } |
| }; |
| setIQ.setType(IQ.Type.SET); |
| return setIQ; |
| } |
| |
| /** |
| * Returns true if XMPP Carbons are supported by the server. |
| * |
| * @return true if supported |
| */ |
| public boolean isSupportedByServer() { |
| try { |
| DiscoverInfo result = ServiceDiscoveryManager |
| .getInstanceFor(connection).discoverInfo(connection.getServiceName()); |
| return result.containsFeature(Carbon.NAMESPACE); |
| } |
| catch (XMPPException e) { |
| return false; |
| } |
| } |
| |
| /** |
| * Notify server to change the carbons state. This method returns |
| * immediately and changes the variable when the reply arrives. |
| * |
| * You should first check for support using isSupportedByServer(). |
| * |
| * @param new_state whether carbons should be enabled or disabled |
| */ |
| public void sendCarbonsEnabled(final boolean new_state) { |
| IQ setIQ = carbonsEnabledIQ(new_state); |
| |
| connection.addPacketListener(new PacketListener() { |
| public void processPacket(Packet packet) { |
| IQ result = (IQ)packet; |
| if (result.getType() == IQ.Type.RESULT) { |
| enabled_state = new_state; |
| } |
| connection.removePacketListener(this); |
| } |
| }, new PacketIDFilter(setIQ.getPacketID())); |
| |
| connection.sendPacket(setIQ); |
| } |
| |
| /** |
| * Notify server to change the carbons state. This method blocks |
| * some time until the server replies to the IQ and returns true on |
| * success. |
| * |
| * You should first check for support using isSupportedByServer(). |
| * |
| * @param new_state whether carbons should be enabled or disabled |
| * |
| * @return true if the operation was successful |
| */ |
| public boolean setCarbonsEnabled(final boolean new_state) { |
| if (enabled_state == new_state) |
| return true; |
| |
| IQ setIQ = carbonsEnabledIQ(new_state); |
| |
| PacketCollector collector = |
| connection.createPacketCollector(new PacketIDFilter(setIQ.getPacketID())); |
| connection.sendPacket(setIQ); |
| IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); |
| collector.cancel(); |
| |
| if (result != null && result.getType() == IQ.Type.RESULT) { |
| enabled_state = new_state; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Helper method to enable carbons. |
| * |
| * @return true if the operation was successful |
| */ |
| public boolean enableCarbons() { |
| return setCarbonsEnabled(true); |
| } |
| |
| /** |
| * Helper method to disable carbons. |
| * |
| * @return true if the operation was successful |
| */ |
| public boolean disableCarbons() { |
| return setCarbonsEnabled(false); |
| } |
| |
| /** |
| * Check if carbons are enabled on this connection. |
| */ |
| public boolean getCarbonsEnabled() { |
| return this.enabled_state; |
| } |
| |
| /** |
| * Obtain a Carbon from a message, if available. |
| * |
| * @param msg Message object to check for carbons |
| * |
| * @return a Carbon if available, null otherwise. |
| */ |
| public static Carbon getCarbon(Message msg) { |
| Carbon cc = (Carbon)msg.getExtension("received", Carbon.NAMESPACE); |
| if (cc == null) |
| cc = (Carbon)msg.getExtension("sent", Carbon.NAMESPACE); |
| return cc; |
| } |
| |
| /** |
| * Mark a message as "private", so it will not be carbon-copied. |
| * |
| * @param msg Message object to mark private |
| */ |
| public static void disableCarbons(Message msg) { |
| msg.addExtension(new Carbon.Private()); |
| } |
| } |