001/** 002 * 003 * Copyright 2013-2014 Georg Lukas 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.carbons; 018 019import java.util.Map; 020import java.util.WeakHashMap; 021 022import org.jivesoftware.smack.SmackException; 023import org.jivesoftware.smack.SmackException.NoResponseException; 024import org.jivesoftware.smack.SmackException.NotConnectedException; 025import org.jivesoftware.smack.XMPPConnection; 026import org.jivesoftware.smack.ConnectionCreationListener; 027import org.jivesoftware.smack.Manager; 028import org.jivesoftware.smack.StanzaListener; 029import org.jivesoftware.smack.XMPPConnectionRegistry; 030import org.jivesoftware.smack.XMPPException; 031import org.jivesoftware.smack.XMPPException.XMPPErrorException; 032import org.jivesoftware.smack.packet.IQ; 033import org.jivesoftware.smack.packet.Message; 034import org.jivesoftware.smack.packet.Stanza; 035import org.jivesoftware.smackx.carbons.packet.CarbonExtension; 036import org.jivesoftware.smackx.carbons.packet.Carbon; 037import org.jivesoftware.smackx.carbons.packet.CarbonExtension.Private; 038import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; 039 040/** 041 * Stanza(/Packet) extension for XEP-0280: Message Carbons. This class implements 042 * the manager for registering {@link CarbonExtension} support, enabling and disabling 043 * message carbons. 044 * 045 * You should call enableCarbons() before sending your first undirected 046 * presence. 047 * 048 * @author Georg Lukas 049 */ 050public class CarbonManager extends Manager { 051 052 private static Map<XMPPConnection, CarbonManager> INSTANCES = new WeakHashMap<XMPPConnection, CarbonManager>(); 053 054 static { 055 XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { 056 public void connectionCreated(XMPPConnection connection) { 057 getInstanceFor(connection); 058 } 059 }); 060 } 061 062 private volatile boolean enabled_state = false; 063 064 private CarbonManager(XMPPConnection connection) { 065 super(connection); 066 ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); 067 sdm.addFeature(CarbonExtension.NAMESPACE); 068 } 069 070 /** 071 * Obtain the CarbonManager responsible for a connection. 072 * 073 * @param connection the connection object. 074 * 075 * @return a CarbonManager instance 076 */ 077 public static synchronized CarbonManager getInstanceFor(XMPPConnection connection) { 078 CarbonManager carbonManager = INSTANCES.get(connection); 079 080 if (carbonManager == null) { 081 carbonManager = new CarbonManager(connection); 082 INSTANCES.put(connection, carbonManager); 083 } 084 085 return carbonManager; 086 } 087 088 private static IQ carbonsEnabledIQ(final boolean new_state) { 089 IQ request; 090 if (new_state) { 091 request = new Carbon.Enable(); 092 } else { 093 request = new Carbon.Disable(); 094 } 095 return request; 096 } 097 098 /** 099 * Returns true if XMPP Carbons are supported by the server. 100 * 101 * @return true if supported 102 * @throws NotConnectedException 103 * @throws XMPPErrorException 104 * @throws NoResponseException 105 */ 106 public boolean isSupportedByServer() throws NoResponseException, XMPPErrorException, NotConnectedException { 107 return ServiceDiscoveryManager.getInstanceFor(connection()).serverSupportsFeature(CarbonExtension.NAMESPACE); 108 } 109 110 /** 111 * Notify server to change the carbons state. This method returns 112 * immediately and changes the variable when the reply arrives. 113 * 114 * You should first check for support using isSupportedByServer(). 115 * 116 * @param new_state whether carbons should be enabled or disabled 117 * @throws NotConnectedException 118 */ 119 public void sendCarbonsEnabled(final boolean new_state) throws NotConnectedException { 120 IQ setIQ = carbonsEnabledIQ(new_state); 121 122 connection().sendIqWithResponseCallback(setIQ, new StanzaListener() { 123 public void processPacket(Stanza packet) { 124 enabled_state = new_state; 125 } 126 }); 127 } 128 129 /** 130 * Notify server to change the carbons state. This method blocks 131 * some time until the server replies to the IQ and returns true on 132 * success. 133 * 134 * You should first check for support using isSupportedByServer(). 135 * 136 * @param new_state whether carbons should be enabled or disabled 137 * @throws XMPPErrorException 138 * @throws NoResponseException 139 * @throws NotConnectedException 140 * 141 */ 142 public synchronized void setCarbonsEnabled(final boolean new_state) throws NoResponseException, 143 XMPPErrorException, NotConnectedException { 144 if (enabled_state == new_state) 145 return; 146 147 IQ setIQ = carbonsEnabledIQ(new_state); 148 149 connection().createPacketCollectorAndSend(setIQ).nextResultOrThrow(); 150 enabled_state = new_state; 151 } 152 153 /** 154 * Helper method to enable carbons. 155 * 156 * @throws XMPPException 157 * @throws SmackException if there was no response from the server. 158 */ 159 public void enableCarbons() throws XMPPException, SmackException { 160 setCarbonsEnabled(true); 161 } 162 163 /** 164 * Helper method to disable carbons. 165 * 166 * @throws XMPPException 167 * @throws SmackException if there was no response from the server. 168 */ 169 public void disableCarbons() throws XMPPException, SmackException { 170 setCarbonsEnabled(false); 171 } 172 173 /** 174 * Check if carbons are enabled on this connection. 175 */ 176 public boolean getCarbonsEnabled() { 177 return this.enabled_state; 178 } 179 180 /** 181 * Mark a message as "private", so it will not be carbon-copied. 182 * 183 * @param msg Message object to mark private 184 * @deprecated use {@link Private#addTo(Message)} 185 */ 186 @Deprecated 187 public static void disableCarbons(Message msg) { 188 msg.addExtension(Private.INSTANCE); 189 } 190}