001: /**
002: * $RCSfile: LocalMUCRole.java,v $
003: * $Revision: 3168 $
004: * $Date: 2005-12-07 13:55:47 -0300 (Wed, 07 Dec 2005) $
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.muc.spi;
011:
012: import org.dom4j.DocumentHelper;
013: import org.dom4j.Element;
014: import org.dom4j.QName;
015: import org.jivesoftware.openfire.PacketRouter;
016: import org.jivesoftware.openfire.XMPPServer;
017: import org.jivesoftware.openfire.cluster.NodeID;
018: import org.jivesoftware.openfire.muc.MUCRole;
019: import org.jivesoftware.openfire.muc.MUCRoom;
020: import org.jivesoftware.openfire.muc.MultiUserChatServer;
021: import org.jivesoftware.openfire.muc.NotAllowedException;
022: import org.jivesoftware.openfire.session.ClientSession;
023: import org.jivesoftware.openfire.session.Session;
024: import org.jivesoftware.util.ElementUtil;
025: import org.xmpp.packet.JID;
026: import org.xmpp.packet.Packet;
027: import org.xmpp.packet.Presence;
028:
029: /**
030: * Implementation of a local room occupant.
031: *
032: * @author Gaston Dombiak
033: */
034: public class LocalMUCRole implements MUCRole {
035:
036: /**
037: * The room this role is valid in.
038: */
039: private LocalMUCRoom room;
040:
041: /**
042: * The user of the role.
043: */
044: private LocalMUCUser user;
045:
046: /**
047: * The user's nickname in the room.
048: */
049: private String nick;
050:
051: /**
052: * The user's presence in the room.
053: */
054: private Presence presence;
055:
056: /**
057: * The chatserver that hosts this role.
058: */
059: private MultiUserChatServer server;
060:
061: /**
062: * The role.
063: */
064: private MUCRole.Role role;
065:
066: /**
067: * The affiliation.
068: */
069: private MUCRole.Affiliation affiliation;
070:
071: /**
072: * Flag that indicates if the room occupant is in the room only to send messages or also
073: * to receive room messages. True means that the room occupant is deaf.
074: */
075: private boolean voiceOnly = false;
076:
077: /**
078: * The router used to send packets from this role.
079: */
080: private PacketRouter router;
081:
082: /**
083: * The address of the person masquerading in this role.
084: */
085: private JID rJID;
086:
087: /**
088: * A fragment containing the x-extension for non-anonymous rooms.
089: */
090: private Element extendedInformation;
091:
092: /**
093: * Cache session of local user that is a room occupant. If the room occupant is not a local
094: * user then nothing will be cached and packets will be sent through the PacketRouter.
095: */
096: private ClientSession session;
097:
098: /**
099: * Create a new role.
100: *
101: * @param chatserver the server hosting the role.
102: * @param chatroom the room the role is valid in.
103: * @param nickname the nickname of the user in the role.
104: * @param role the role of the user in the room.
105: * @param affiliation the affiliation of the user in the room.
106: * @param chatuser the user on the chat server.
107: * @param presence the presence sent by the user to join the room.
108: * @param packetRouter the packet router for sending messages from this role.
109: */
110: public LocalMUCRole(MultiUserChatServer chatserver,
111: LocalMUCRoom chatroom, String nickname, MUCRole.Role role,
112: MUCRole.Affiliation affiliation, LocalMUCUser chatuser,
113: Presence presence, PacketRouter packetRouter) {
114: this .room = chatroom;
115: this .nick = nickname;
116: this .user = chatuser;
117: this .server = chatserver;
118: this .router = packetRouter;
119: this .role = role;
120: this .affiliation = affiliation;
121: // Cache the user's session (will only work for local users)
122: this .session = XMPPServer.getInstance().getSessionManager()
123: .getSession(presence.getFrom());
124:
125: extendedInformation = DocumentHelper.createElement(QName.get(
126: "x", "http://jabber.org/protocol/muc#user"));
127: calculateExtendedInformation();
128: rJID = new JID(room.getName(), server.getServiceDomain(), nick);
129: setPresence(presence);
130: // Check if new occupant wants to be a deaf occupant
131: Element element = presence.getElement().element(
132: QName.get("x", "http://jivesoftware.org/protocol/muc"));
133: if (element != null) {
134: voiceOnly = element.element("deaf-occupant") != null;
135: }
136: // Add the new role to the list of roles
137: user.addRole(room.getName(), this );
138: }
139:
140: public Presence getPresence() {
141: return presence;
142: }
143:
144: public void setPresence(Presence newPresence) {
145: // Try to remove the element whose namespace is "http://jabber.org/protocol/muc" since we
146: // don't need to include that element in future presence broadcasts
147: Element element = newPresence.getElement().element(
148: QName.get("x", "http://jabber.org/protocol/muc"));
149: if (element != null) {
150: newPresence.getElement().remove(element);
151: }
152: this .presence = newPresence;
153: this .presence.setFrom(getRoleAddress());
154: if (extendedInformation != null) {
155: extendedInformation.setParent(null);
156: presence.getElement().add(extendedInformation);
157: }
158: }
159:
160: public void setRole(MUCRole.Role newRole)
161: throws NotAllowedException {
162: // Don't allow to change the role to an owner or admin unless the new role is moderator
163: if (MUCRole.Affiliation.owner == affiliation
164: || MUCRole.Affiliation.admin == affiliation) {
165: if (MUCRole.Role.moderator != newRole) {
166: throw new NotAllowedException();
167: }
168: }
169: // A moderator cannot be kicked from a room
170: if (MUCRole.Role.moderator == role
171: && MUCRole.Role.none == newRole) {
172: throw new NotAllowedException();
173: }
174: // TODO A moderator MUST NOT be able to revoke voice from a user whose affiliation is at or
175: // TODO above the moderator's level.
176:
177: role = newRole;
178: if (MUCRole.Role.none == role) {
179: presence.setType(Presence.Type.unavailable);
180: presence.setStatus(null);
181: }
182: calculateExtendedInformation();
183: }
184:
185: public MUCRole.Role getRole() {
186: return role;
187: }
188:
189: public void setAffiliation(MUCRole.Affiliation newAffiliation)
190: throws NotAllowedException {
191: // Don't allow to ban an owner or an admin
192: if (MUCRole.Affiliation.owner == affiliation
193: || MUCRole.Affiliation.admin == affiliation) {
194: if (MUCRole.Affiliation.outcast == newAffiliation) {
195: throw new NotAllowedException();
196: }
197: }
198: affiliation = newAffiliation;
199: // TODO The fragment is being calculated twice (1. setting the role & 2. setting the aff)
200: calculateExtendedInformation();
201: }
202:
203: public MUCRole.Affiliation getAffiliation() {
204: return affiliation;
205: }
206:
207: public String getNickname() {
208: return nick;
209: }
210:
211: public void changeNickname(String nickname) {
212: this .nick = nickname;
213: setRoleAddress(new JID(room.getName(), server
214: .getServiceDomain(), nick));
215: }
216:
217: public void destroy() {
218: // Notify the user that he/she is no longer in the room
219: user.removeRole(room.getName());
220: }
221:
222: public MUCRoom getChatRoom() {
223: return room;
224: }
225:
226: public JID getRoleAddress() {
227: return rJID;
228: }
229:
230: public JID getUserAddress() {
231: return user.getAddress();
232: }
233:
234: public boolean isLocal() {
235: return true;
236: }
237:
238: public NodeID getNodeID() {
239: return XMPPServer.getInstance().getNodeID();
240: }
241:
242: private void setRoleAddress(JID jid) {
243: rJID = jid;
244: // Set the new sender of the user presence in the room
245: presence.setFrom(jid);
246: }
247:
248: public boolean isVoiceOnly() {
249: return voiceOnly;
250: }
251:
252: public void send(Packet packet) {
253: if (packet == null) {
254: return;
255: }
256: packet.setTo(user.getAddress());
257:
258: if (session != null
259: && session.getStatus() == Session.STATUS_AUTHENTICATED) {
260: // Send the packet directly to the local user session
261: session.process(packet);
262: } else {
263: router.route(packet);
264: }
265: }
266:
267: /**
268: * Calculates and sets the extended presence information to add to the presence.
269: * The information to add contains the user's jid, affiliation and role.
270: */
271: private void calculateExtendedInformation() {
272: ElementUtil.setProperty(extendedInformation, "x.item:jid", user
273: .getAddress().toString());
274: ElementUtil.setProperty(extendedInformation,
275: "x.item:affiliation", affiliation.toString());
276: ElementUtil.setProperty(extendedInformation, "x.item:role",
277: role.toString());
278: }
279: }
|