001: /**
002: * $RCSfile$
003: * $Revision: $
004: * $Date: $
005: *
006: * Copyright (C) 2007 Jive Software. All rights reserved.
007: *
008: * This software is published under the terms of the GNU Public License (GPL),
009: * a copy of which is included in this distribution.
010: */package org.jivesoftware.openfire.handler;
011:
012: import org.dom4j.Element;
013: import org.jivesoftware.openfire.IQHandlerInfo;
014: import org.jivesoftware.openfire.SessionManager;
015: import org.jivesoftware.openfire.XMPPServer;
016: import org.jivesoftware.openfire.auth.UnauthorizedException;
017: import org.jivesoftware.openfire.disco.ServerFeaturesProvider;
018: import org.jivesoftware.openfire.event.UserEventListener;
019: import org.jivesoftware.openfire.privacy.PrivacyList;
020: import org.jivesoftware.openfire.privacy.PrivacyListManager;
021: import org.jivesoftware.openfire.privacy.PrivacyListProvider;
022: import org.jivesoftware.openfire.session.ClientSession;
023: import org.jivesoftware.openfire.user.User;
024: import org.jivesoftware.openfire.user.UserManager;
025: import org.xmpp.packet.IQ;
026: import org.xmpp.packet.JID;
027: import org.xmpp.packet.PacketError;
028:
029: import java.util.ArrayList;
030: import java.util.Iterator;
031: import java.util.List;
032: import java.util.Map;
033:
034: /**
035: * IQPrivacyHandler is responsible for handling privacy lists.
036: *
037: * @author Gaston Dombiak
038: */
039: public class IQPrivacyHandler extends IQHandler implements
040: ServerFeaturesProvider, UserEventListener {
041:
042: private IQHandlerInfo info;
043: private PrivacyListManager manager = PrivacyListManager
044: .getInstance();
045: private PrivacyListProvider provider = new PrivacyListProvider();
046: private SessionManager sessionManager;
047:
048: public IQPrivacyHandler() {
049: super ("Blocking Communication Handler");
050: info = new IQHandlerInfo("query", "jabber:iq:privacy");
051: }
052:
053: public IQ handleIQ(IQ packet) throws UnauthorizedException {
054: IQ.Type type = packet.getType();
055: JID from = packet.getFrom();
056: if (from.getNode() == null
057: || !UserManager.getInstance().isRegisteredUser(
058: from.getNode())) {
059: // Service is unavailable for anonymous users
060: IQ result = IQ.createResultIQ(packet);
061: result.setChildElement(packet.getChildElement()
062: .createCopy());
063: result.setError(PacketError.Condition.service_unavailable);
064: return result;
065: }
066: IQ result = null;
067: if (type.equals(IQ.Type.get)) {
068: // User wants to retrieve a privacy list or the list of privacy list
069: Element child = packet.getChildElement();
070: List elements = child.elements();
071: if (elements.isEmpty()) {
072: // User requested names of privacy lists
073: result = getPrivacyListsNames(packet, from);
074: } else {
075: // User requested a privacy list
076: result = getPrivacyList(packet, from);
077: }
078: } else if (type.equals(IQ.Type.set)) {
079: Element child = packet.getChildElement();
080: Element activeList = child.element("active");
081: Element defaultList = child.element("default");
082: if (activeList != null) {
083: // Active list handling
084: String listName = activeList.attributeValue("name");
085: if (listName != null) {
086: // User wants to set or change the active list currently being applied by
087: // the server to this session
088: result = setActiveList(packet, from, listName);
089: } else {
090: // User wants to decline the use of any active list for this session
091: result = declineActiveList(packet, from);
092:
093: }
094: } else if (defaultList != null) {
095: // Default list handling
096: String listName = defaultList.attributeValue("name");
097: if (listName != null) {
098: // User wants to set or change its default list (i.e. which applies
099: // to the user as a whole, not only the sending resource)
100: result = setDefaultList(packet, from, listName);
101: } else {
102: // User wants to decline the use of a default list
103: result = declineDefaultList(packet, from);
104: }
105: } else {
106: // Privacy list handling (create/edit/delete)
107: Element list = child.element("list");
108: String listName = list.attributeValue("name");
109: List items = list.elements();
110: if (!items.isEmpty()) {
111: // User wants to create or edit a privacy list
112: result = updateOrCreateList(packet, from, list);
113: } else {
114: // User wants to delete a privacy list
115: result = deleteList(packet, from, listName);
116:
117: }
118: }
119: }
120: return result;
121: }
122:
123: /**
124: * Returns the IQ packet containing the active and default lists and the lists
125: * defined by the user.
126: *
127: * @param packet IQ packet requesting the lists.
128: * @param from sender of the IQ packet.
129: * @return the IQ packet containing the active and default lists and the lists
130: * defined by the user.
131: */
132: private IQ getPrivacyListsNames(IQ packet, JID from) {
133: IQ result = IQ.createResultIQ(packet);
134: Element childElement = packet.getChildElement().createCopy();
135: result.setChildElement(childElement);
136: Map<String, Boolean> privacyLists = provider
137: .getPrivacyLists(from.getNode());
138: // Add the default list
139: for (String listName : privacyLists.keySet()) {
140: if (privacyLists.get(listName)) {
141: childElement.addElement("default").addAttribute("name",
142: listName);
143: }
144: }
145: // Add the active list (only if there is an active list for the session)
146: ClientSession session = sessionManager.getSession(from);
147: if (session != null && session.getActiveList() != null) {
148: childElement.addElement("active").addAttribute("name",
149: session.getActiveList().getName());
150: }
151:
152: // Add a list element for each privacy list
153: for (String listName : privacyLists.keySet()) {
154: childElement.addElement("list").addAttribute("name",
155: listName);
156: }
157: return result;
158: }
159:
160: /**
161: * Returns the IQ packet containing the details of the specified list. If no list
162: * was found or the IQ request contains more than one specified list then an error will
163: * be returned.
164: *
165: * @param packet IQ packet requesting a given list.
166: * @param from sender of the IQ packet.
167: * @return the IQ packet containing the details of the specified list.
168: */
169: private IQ getPrivacyList(IQ packet, JID from) {
170: IQ result = IQ.createResultIQ(packet);
171: Element childElement = packet.getChildElement().createCopy();
172: result.setChildElement(childElement);
173:
174: // Check that only one list was requested
175: List<Element> lists = childElement.elements("list");
176: if (lists.size() > 1) {
177: result.setError(PacketError.Condition.bad_request);
178: } else {
179: String listName = lists.get(0).attributeValue("name");
180: PrivacyList list = null;
181: if (listName != null) {
182: // A list name was specified so get it
183: list = manager.getPrivacyList(from.getNode(), listName);
184: }
185: if (list != null) {
186: // Add the privacy list to the result
187: childElement = result.setChildElement("query",
188: "jabber:iq:privacy");
189: childElement.add(list.asElement());
190: } else {
191: // List not found
192: result.setError(PacketError.Condition.item_not_found);
193: }
194: }
195: return result;
196: }
197:
198: /**
199: * User has specified a new active list that should be used for the current session.
200: *
201: * @param packet IQ packet setting new active list for the current session.
202: * @param from sender of the IQ packet.
203: * @param listName name of the new active list for the current session.
204: * @return acknowledge of success.
205: */
206: private IQ setActiveList(IQ packet, JID from, String listName) {
207: IQ result = IQ.createResultIQ(packet);
208: Element childElement = packet.getChildElement().createCopy();
209: result.setChildElement(childElement);
210:
211: // Get the list
212: PrivacyList list = manager.getPrivacyList(from.getNode(),
213: listName);
214: if (list != null) {
215: // Get the user session
216: ClientSession session = sessionManager.getSession(from);
217: if (session != null) {
218: // Set the new active list for this session
219: session.setActiveList(list);
220: }
221: } else {
222: // List not found
223: result.setError(PacketError.Condition.item_not_found);
224: }
225: return result;
226: }
227:
228: /**
229: * User has requested that no active list should be used for the current session. Return
230: * acknowledge of success.
231: *
232: * @param packet IQ packet declining active list for the current session.
233: * @param from sender of the IQ packet.
234: * @return acknowledge of success.
235: */
236: private IQ declineActiveList(IQ packet, JID from) {
237: // Get the user session
238: ClientSession session = sessionManager.getSession(from);
239: // Set that there is no active list for this session
240: session.setActiveList(null);
241: // Return acknowledge of success
242: return IQ.createResultIQ(packet);
243: }
244:
245: /**
246: * User has specified a new default list that should be used for all session.
247: *
248: * @param packet IQ packet setting new default list for all sessions.
249: * @param from sender of the IQ packet.
250: * @param listName name of the new default list for all sessions.
251: * @return acknowledge of success.
252: */
253: private IQ setDefaultList(IQ packet, JID from, String listName) {
254: IQ result = IQ.createResultIQ(packet);
255: Element childElement = packet.getChildElement().createCopy();
256: result.setChildElement(childElement);
257:
258: if (sessionManager.getSessionCount(from.getNode()) > 1) {
259: // Current default list is being used by more than one session
260: result.setError(PacketError.Condition.conflict);
261: } else {
262: // Get the list
263: PrivacyList list = manager.getPrivacyList(from.getNode(),
264: listName);
265: if (list != null) {
266: // Get the user session
267: ClientSession session = sessionManager.getSession(from);
268: PrivacyList oldDefaultList = session.getDefaultList();
269: manager.changeDefaultList(from.getNode(), list,
270: oldDefaultList);
271: // Set the new default list for this session (the only existing session)
272: session.setDefaultList(list);
273: } else {
274: // List not found
275: result.setError(PacketError.Condition.item_not_found);
276: }
277: }
278: return result;
279: }
280:
281: /**
282: * User has specified that there is no default list that should be used for this user.
283: *
284: * @param packet IQ packet declining default list for all sessions.
285: * @param from sender of the IQ packet.
286: * @return acknowledge of success.
287: */
288: private IQ declineDefaultList(IQ packet, JID from) {
289: IQ result = IQ.createResultIQ(packet);
290: Element childElement = packet.getChildElement().createCopy();
291: result.setChildElement(childElement);
292:
293: if (sessionManager.getSessionCount(from.getNode()) > 1) {
294: // Current default list is being used by more than one session
295: result.setError(PacketError.Condition.conflict);
296: } else {
297: // Get the user session
298: ClientSession session = sessionManager.getSession(from);
299: // Check if a default list was already defined
300: if (session.getDefaultList() != null) {
301: // Set the existing default list as non-default
302: session.getDefaultList().setDefaultList(false);
303: // Update the database with the new list state
304: provider.updatePrivacyList(from.getNode(), session
305: .getDefaultList());
306: session.setDefaultList(null);
307: }
308: }
309: return result;
310: }
311:
312: /**
313: * Updates an existing privacy list or creates a new one with the specified items list. The
314: * new list will not become the active or default list by default. The user will have to
315: * send another packet to set the new list as active or default.<p>
316: *
317: * Once the list was updated or created a "privacy list push" will be sent to all
318: * connected resources of the user.
319: *
320: * @param packet IQ packet updating or creating a new privacy list.
321: * @param from sender of the IQ packet.
322: * @param listElement the element containing the list and its items.
323: * @return acknowledge of success.
324: */
325: private IQ updateOrCreateList(IQ packet, JID from,
326: Element listElement) {
327: IQ result = IQ.createResultIQ(packet);
328: Element childElement = packet.getChildElement().createCopy();
329: result.setChildElement(childElement);
330:
331: String listName = listElement.attributeValue("name");
332: PrivacyList list = manager.getPrivacyList(from.getNode(),
333: listName);
334: if (list == null) {
335: list = manager.createPrivacyList(from.getNode(), listName,
336: listElement);
337: } else {
338: // Update existing list
339: list.updateList(listElement);
340: provider.updatePrivacyList(from.getNode(), list);
341: // Make sure that existing user sessions that are using the updated list are poining
342: // to the updated instance. This may happen since PrivacyListManager uses a Cache that
343: // may expire so it's possible to have many instances representing the same privacy
344: // list. Therefore, if a list is modified then we need to make sure that all
345: // instances are replaced with the updated instance. An OR Mapping Tool would have
346: // avoided this issue since identity is ensured.
347: for (ClientSession session : sessionManager
348: .getSessions(from.getNode())) {
349: if (list.equals(session.getDefaultList())) {
350: session.setDefaultList(list);
351: }
352: if (list.equals(session.getActiveList())) {
353: session.setActiveList(list);
354: }
355: }
356: }
357: // Send a "privacy list push" to all connected resources
358: IQ pushPacket = new IQ(IQ.Type.set);
359: Element child = pushPacket.setChildElement("query",
360: "jabber:iq:privacy");
361: child.addElement("list").addAttribute("name", list.getName());
362: sessionManager.userBroadcast(from.getNode(), pushPacket);
363:
364: return result;
365: }
366:
367: private IQ deleteList(IQ packet, JID from, String listName) {
368: ClientSession currentSession;
369: IQ result = IQ.createResultIQ(packet);
370: Element childElement = packet.getChildElement().createCopy();
371: result.setChildElement(childElement);
372: // Get the list to delete
373: PrivacyList list = manager.getPrivacyList(from.getNode(),
374: listName);
375:
376: if (list == null) {
377: // List to delete was not found
378: result.setError(PacketError.Condition.item_not_found);
379: return result;
380: } else {
381: currentSession = sessionManager.getSession(from);
382: // Check if the list is being used by another session
383: for (ClientSession session : sessionManager
384: .getSessions(from.getNode())) {
385: if (currentSession == session) {
386: // Ignore the active session for this checking
387: continue;
388: }
389: if (list.equals(session.getDefaultList())
390: || list.equals(session.getActiveList())) {
391: // List to delete is being used by another session so return a conflict error
392: result.setError(PacketError.Condition.conflict);
393: return result;
394: }
395: }
396: }
397: // Remove the list from the active session (if it was being used)
398: if (list.equals(currentSession.getDefaultList())) {
399: currentSession.setDefaultList(null);
400: }
401: if (list.equals(currentSession.getActiveList())) {
402: currentSession.setActiveList(null);
403: }
404: manager.deletePrivacyList(from.getNode(), listName);
405: return result;
406: }
407:
408: public IQHandlerInfo getInfo() {
409: return info;
410: }
411:
412: public Iterator<String> getFeatures() {
413: ArrayList<String> features = new ArrayList<String>();
414: features.add("jabber:iq:privacy");
415: return features.iterator();
416: }
417:
418: public void userCreated(User user, Map params) {
419: //Do nothing
420: }
421:
422: public void userDeleting(User user, Map params) {
423: // Delete privacy lists owned by the user being deleted
424: manager.deletePrivacyLists(user.getUsername());
425: }
426:
427: public void userModified(User user, Map params) {
428: //Do nothing
429: }
430:
431: public void initialize(XMPPServer server) {
432: super.initialize(server);
433: sessionManager = server.getSessionManager();
434: }
435: }
|