blob: 4dcc9e1cbec959943417942b8bb7081e947b6021 [file] [log] [blame]
/**
* $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);
}
}
}