/** | |
* $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 = Collections | |
.synchronizedMap(new WeakHashMap<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); | |
} | |
} | |
} |