mucroomimpl.java

来自「基于Jabber协议的即时消息服务器」· Java 代码 · 共 1,693 行 · 第 1/5 页

JAVA
1,693
字号
            for (String nickname: occupants.keySet()) {
                leaveRole = occupants.remove(nickname);

                if (leaveRole != null) {
                    // Add the removed occupant to the list of removed occupants. We are keeping a
                    // list of removed occupants to process later outside of the lock.
                    removedRoles.add(leaveRole);
                    removeOccupantRole(leaveRole);
                }
            }
            endTime = System.currentTimeMillis();
            // Removes the room from the list of rooms hosted in the server
            server.removeChatRoom(name);
            // Set that the room has been destroyed
            isDestroyed = true;
        }
        finally {
            lock.writeLock().unlock();
        }
        // Send an unavailable presence to each removed occupant
        for (MUCRole removedRole : removedRoles) {
            try {
                // Send a presence stanza of type "unavailable" to the occupant
                Presence presence = createPresence(Presence.Type.unavailable);
                presence.setFrom(removedRole.getRoleAddress());

                // A fragment containing the x-extension for room destruction.
                Element fragment = presence.addChildElement("x",
                        "http://jabber.org/protocol/muc#user");
                Element item = fragment.addElement("item");
                item.addAttribute("affiliation", "none");
                item.addAttribute("role", "none");
                if (alternateJID != null && alternateJID.length() > 0) {
                    fragment.addElement("destroy").addAttribute("jid", alternateJID);
                }
                if (reason != null && reason.length() > 0) {
                    Element destroy = fragment.element("destroy");
                    if (destroy == null) {
                        destroy = fragment.addElement("destroy");
                    }
                    destroy.addElement("reason").setText(reason);
                }
                removedRole.send(presence);
            }
            catch (Exception e) {
                Log.error(e);
            }
        }
        // Remove the room from the DB if the room was persistent
        MUCPersistenceManager.deleteFromDB(this);
    }

    public Presence createPresence(Presence.Type presenceType) throws UnauthorizedException {
        Presence presence = new Presence();
        presence.setType(presenceType);
        presence.setFrom(role.getRoleAddress());
        return presence;
    }

    public void serverBroadcast(String msg) {
        Message message = new Message();
        message.setType(Message.Type.groupchat);
        message.setBody(msg);
        message.setFrom(role.getRoleAddress());
        roomHistory.addMessage(message);
        broadcast(message);
    }

    public void sendPublicMessage(Message message, MUCRole senderRole) throws ForbiddenException {
        // Check that if the room is moderated then the sender of the message has to have voice
        if (isModerated() && senderRole.getRole().compareTo(MUCRole.Role.participant) > 0) {
            throw new ForbiddenException();
        }
        // Send the message to all occupants
        message.setFrom(senderRole.getRoleAddress());
        send(message);
    }

    public void sendPrivatePacket(Packet packet, MUCRole senderRole) throws NotFoundException {
        String resource = packet.getTo().getResource();
        MUCRole occupant = occupants.get(resource.toLowerCase());
        if (occupant != null) {
            packet.setFrom(senderRole.getRoleAddress());
            occupant.send(packet);
        }
        else {
            throw new NotFoundException();
        }
    }

    public void send(Packet packet) {
        if (packet instanceof Message) {
            roomHistory.addMessage((Message)packet);
            broadcast((Message)packet);
        }
        else if (packet instanceof Presence) {
            broadcastPresence((Presence)packet);
        }
        else if (packet instanceof IQ) {
            IQ reply = IQ.createResultIQ((IQ) packet);
            reply.setChildElement(((IQ) packet).getChildElement());
            reply.setError(PacketError.Condition.bad_request);
            router.route(reply);
        }
    }

    /**
     * Broadcasts the specified presence to all room occupants. If the presence belongs to a
     * user whose role cannot be broadcast then the presence will only be sent to the presence's
     * user. On the other hand, the JID of the user that sent the presence won't be included if the
     * room is semi-anon and the target occupant is not a moderator.
     *
     * @param presence the presence to broadcast.
     */
    private void broadcastPresence(Presence presence) {
        if (presence == null) {
            return;
        }
        Element frag = null;
        String jid = null;
        if (hasToCheckRoleToBroadcastPresence()) {
            frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
            // Check if we can broadcast the presence for this role
            if (!canBroadcastPresence(frag.element("item").attributeValue("role"))) {
                // Just send the presence to the sender of the presence
                try {
                    MUCRole occupant = getOccupant(presence.getFrom().getResource());
                    occupant.send(presence);
                }
                catch (UserNotFoundException e) {
                    // Do nothing
                }
                return;
            }
        }

        // Don't include the occupant's JID if the room is semi-anon and the new occupant
        // is not a moderator
        if (!canAnyoneDiscoverJID()) {
            if (frag == null) {
                frag = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
            }
            jid = frag.element("item").attributeValue("jid");
        }
        for (MUCRole occupant : occupants.values()) {
            // Don't include the occupant's JID if the room is semi-anon and the new occupant
            // is not a moderator
            if (!canAnyoneDiscoverJID()) {
                if (MUCRole.Role.moderator == occupant.getRole()) {
                    frag.element("item").addAttribute("jid", jid);
                }
                else {
                    frag.element("item").addAttribute("jid", null);
                }
            }
            occupant.send(presence);
        }
    }

    private void broadcast(Message message) {
        for (MUCRole occupant : occupants.values()) {
            // Do not send broadcast messages to deaf occupants
            if (!occupant.isVoiceOnly()) {
                occupant.send(message);
            }
        }
        if (isLogEnabled()) {
            MUCRole senderRole = null;
            JID senderAddress;
            if (message.getFrom() != null && message.getFrom().getResource() != null) {
                senderRole = occupants.get(message.getFrom().getResource());
            }
            if (senderRole == null) {
                // The room itself is sending the message
                senderAddress = getRole().getRoleAddress();
            }
            else {
                // An occupant is sending the message
                senderAddress = senderRole.getChatUser().getAddress();
            }
            // Log the conversation
            server.logConversation(this, message, senderAddress);
        }
        server.messageBroadcastedTo(occupants.size());
    }

    /**
     * An empty role that represents the room itself in the chatroom. Chatrooms need to be able to
     * speak (server messages) and so must have their own role in the chatroom.
     */
    private class RoomRole implements MUCRole {

        private MUCRoom room;

        private RoomRole(MUCRoom room) {
            this.room = room;
        }

        public Presence getPresence() {
            return null;
        }

        public Element getExtendedPresenceInformation() {
            return null;
        }

        public void setPresence(Presence presence) {
        }

        public void setRole(MUCRole.Role newRole) {
        }

        public MUCRole.Role getRole() {
            return MUCRole.Role.moderator;
        }

        public void setAffiliation(MUCRole.Affiliation newAffiliation) {
        }

        public MUCRole.Affiliation getAffiliation() {
            return MUCRole.Affiliation.owner;
        }

        public String getNickname() {
            return null;
        }

        public MUCUser getChatUser() {
            return null;
        }

        public boolean isVoiceOnly() {
            return false;
        }

        public MUCRoom getChatRoom() {
            return room;
        }

        private JID crJID = null;

        public JID getRoleAddress() {
            if (crJID == null) {
                crJID = new JID(room.getName(), server.getServiceDomain(), "");
            }
            return crJID;
        }

        public void send(Packet packet) {
            room.send(packet);
        }

        public void changeNickname(String nickname) {
        }
    }

    public long getChatLength() {
        return endTime - startTime;
    }

    /**
     * Updates all the presences of the given user with the new affiliation and role information. Do
     * nothing if the given jid is not present in the room. If the user has joined the room from
     * several client resources, all his/her occupants' presences will be updated.
     * 
     * @param bareJID the bare jid of the user to update his/her role.
     * @param newAffiliation the new affiliation for the JID.
     * @param newRole the new role for the JID.
     * @return the list of updated presences of all the client resources that the client used to
     *         join the room.
     * @throws NotAllowedException If trying to change the moderator role to an owner or an admin or
     *         if trying to ban an owner or an administrator.
     */
    private List<Presence> changeOccupantAffiliation(String bareJID, MUCRole.Affiliation newAffiliation, MUCRole.Role newRole)
            throws NotAllowedException {
        List<Presence> presences = new ArrayList<Presence>();
        // Get all the roles (i.e. occupants) of this user based on his/her bare JID
        List<MUCRole> roles = occupantsByBareJID.get(bareJID);
        if (roles == null) {
            return presences;
        }
        // Collect all the updated presences of these roles
        for (MUCRole role : roles) {
            // Update the presence with the new affiliation and role
            role.setAffiliation(newAffiliation);
            role.setRole(newRole);
            // Prepare a new presence to be sent to all the room occupants
            presences.add(role.getPresence().createCopy());
        }
        // Answer all the updated presences
        return presences;
    }

    /**
     * Updates the presence of the given user with the new role information. Do nothing if the given
     * jid is not present in the room.
     * 
     * @param jid the full jid of the user to update his/her role.
     * @param newRole the new role for the JID.
     * @return the updated presence of the user or null if none.
     * @throws NotAllowedException If trying to change the moderator role to an owner or an admin.
     */
    private Presence changeOccupantRole(JID jid, MUCRole.Role newRole) throws NotAllowedException {
        // Try looking the role in the bare JID list
        MUCRole role = occupantsByFullJID.get(jid);
        if (role != null) {
            // Update the presence with the new role
            role.setRole(newRole);
            // Prepare a new presence to be sent to all the room occupants
            return role.getPresence().createCopy();
        }
        return null;
    }

    public void addFirstOwner(String bareJID) {
        owners.add(bareJID);
    }

    public List<Presence> addOwner(String bareJID, MUCRole sendRole) throws ForbiddenException {
        MUCRole.Affiliation oldAffiliation = MUCRole.Affiliation.none;
        if (MUCRole.Affiliation.owner != sendRole.getAffiliation()) {
            throw new ForbiddenException();
        }
        // Check if user is already an owner
        if (owners.contains(bareJID)) {
            // Do nothing
            return Collections.emptyList();
        }
        owners.add(bareJID);
        // Remove the user from other affiliation lists
        if (removeAdmin(bareJID)) {
            oldAffiliation = MUCRole.Affiliation.admin;
        }
        else if (removeMember(bareJID)) {
            oldAffiliation = MUCRole.Affiliation.member;
        }
        else if (removeOutcast(bareJID)) {
            oldAffiliation = MUCRole.Affiliation.outcast;
        }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?