uk.org.retep.xmpp.muc.MucFeature Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2010, Peter T Mount
* All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
*
*
* GNU GENERAL PUBLIC LICENSE - CLASSPATH EXCEPTION
*
*
*
* Linking this library statically or dynamically with other modules
* is making a combined work based on this library. Thus, the terms
* and conditions of the GNU General Public License cover the whole
* combination.
*
*
*
* As a special exception, the copyright holders of this library give
* you permission to link this library with independent modules to
* produce an executable, regardless of the license terms of these
* independent modules, and to copy and distribute the resulting
* executable under terms of your choice, provided that you also meet,
* for each linked independent module, the terms and conditions of the
* license of that module.
*
*
*
* An independent module is a module which is either not derived from or based
* on this library, or a module who's classes extend those within this library
* as part of the implementation of the library.
*
*
*
* If you modify this library, you may extend this exception to your version
* of the library, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
*/
package uk.org.retep.xmpp.muc;
import org.jabber.protocol.disco_info.FeatureBuilder;
import uk.org.retep.util.messaging.MessageException;
import uk.org.retep.xmpp.message.ErrorCondition;
import uk.org.retep.xmpp.util.Role;
/**
* The Features present in a room.
*
*
* In XEP-0045 5.1.1 Privileges
* we have specific roles defined and implemented by {@link Role}. However
* Here we provide non standard features which implement the exceptions defined
* in the following section:
*
*
*
* For the most part, roles exist in a hierarchy. For instance, a participant
* can do anything a visitor can do, and a moderator can do anything a
* participant can do. Each role has privileges not possessed by the next-lowest
* role; these privileges are specified in the following table as defaults
* (an implementation MAY provide configuration options that override these
* defaults).
*
*
*
* Privilege None Visitor Participant Moderator
* Present in Room No Yes Yes Yes
* Receive Messages No Yes Yes Yes
* Receive Occupant Presence No Yes Yes Yes
* Presence Broadcasted to Room No Yes* Yes Yes
* Change Availability Status No Yes Yes Yes
* Change Room Nickname No Yes* Yes Yes
* Send Private Messages No Yes* Yes Yes
* Invite Other Users No Yes* Yes* Yes
* Send Messages to All No No** Yes Yes
* Modify Subject No No* Yes* Yes
* Kick Participants and Visitors No No No Yes
* Grant Voice No No No Yes
* Revoke Voice No No No Yes***
*
*
*
* * Default; configuration settings MAY modify this privilege.
*
*
*
* ** An implementation MAY grant voice by default to visitors in unmoderated rooms.
* This is implemented with {@link #VISITOR_SEND_MESSAGES_TO_ALL}
*
*
*
* *** A moderator MUST NOT be able to revoke voice privileges from an
* admin or owner.
*
*
* @author peter
*/
public enum MucFeature
{
/**
* XEP-0045: Hidden room in Multi-User Chat (MUC)
*/
MUC_HIDDEN,
/**
* XEP-0045: Members-only room in Multi-User Chat (MUC)
*/
MUC_MEMBERSONLY,
/**
* XEP-0045: Moderated room in Multi-User Chat (MUC)
*/
MUC_MODERATED
{
/**
* Moderators and participants may send messages to this room.
*/
@Override
public ErrorCondition validate( final MucRoomMember sender,
final MucRoom room )
throws MessageException
{
final Role role = sender.getRole();
if( room.hasFeature( this )
&& (role == Role.MODERATOR) || role == Role.PARTICIPANT )
{
return ErrorCondition.FORBIDDEN;
}
else
{
return ErrorCondition.OK;
}
}
},
/**
* XEP-0045: Non-anonymous room in Multi-User Chat (MUC)
*/
MUC_NONANONYMOUS,
/**
* XEP-0045: Open room in Multi-User Chat (MUC)
*/
MUC_OPEN,
/**
* XEP-0045: Password-protected room in Multi-User Chat (MUC)
*/
MUC_PASSWORDPROTECTED,
/**
* XEP-0045: Persistent room in Multi-User Chat (MUC)
*/
MUC_PERSISTENT,
/**
* XEP-0045: Public room in Multi-User Chat (MUC)
*/
MUC_PUBLIC,
/**
* XEP-0045: List of MUC rooms (each as a separate item)
*/
MUC_ROOMS,
/**
* XEP-0045: Semi-anonymous room in Multi-User Chat (MUC)
*/
MUC_SEMIANONYMOUS,
/**
* XEP-0045: Temporary room in Multi-User Chat (MUC)
*/
MUC_TEMPORARY,
/**
* XEP-0045: Unmoderated room in Multi-User Chat (MUC)
*/
MUC_UNMODERATED,
/**
* XEP-0045: Unsecured room in Multi-User Chat (MUC)
*/
MUC_UNSECURED,
// ----- NON-STANDARD features to go after this point
/**
* Non standard: If present a visitor may send messages to all.
*
*
* XEP-0045 5.1.1 Privileges
* An implementation MAY grant voice by default to visitors in unmoderated rooms.
*
*/
VISITOR_SEND_MESSAGES_TO_ALL
{
@Override
public ErrorCondition validate( final MucRoomMember sender,
final MucRoom room )
throws MessageException
{
final Role role = sender.getRole();
if( room.hasFeature( this )
&& (role == Role.MODERATOR) || role == Role.PARTICIPANT )
{
return ErrorCondition.FORBIDDEN;
}
else
{
return ErrorCondition.OK;
}
}
};
/**
* Usually I would use values() or in this case {@link MucRoom#getFeatures()}
* however I want the non-standard entries to go after the standard ones in
* the enum so we have this array defined which specify the MucFeatures the
* {@link #validateSender(uk.org.retep.xmpp.muc.MucRoomMember, uk.org.retep.xmpp.muc.MucRoom) }
* method will use to test and specifically the precedence of those features.
*
* This way the enum is defined in the order in the spec but we can play
* with the precedence allowing one feature to override another as the scan
* operates a fail-fast algorithm.
*
* It also means we can scan only those features which implement
* {@link #validate(uk.org.retep.xmpp.muc.MucRoomMember, uk.org.retep.xmpp.muc.MucRoom) }
*/
private static final MucFeature VALIDATE_SEQUENCE[] =
{
VISITOR_SEND_MESSAGES_TO_ALL,
MUC_MODERATED
};
/**
* Validate the sender against all features of the room. The first one
* to return an ErrorCondition other than ErrorCondition.OK stops the scan
* and returns that value.
*
* @param sender MucRoomMember to test
* @param room MucRoom of the room
* @return ErrorCondition
* @throws MessageException
*/
public static ErrorCondition validateSender( final MucRoomMember sender,
final MucRoom room )
throws MessageException
{
for( MucFeature feature : VALIDATE_SEQUENCE )
{
if( room.hasFeature( feature ) )
{
final ErrorCondition ec = feature.validate( sender, room );
if( ec != ErrorCondition.OK )
{
return ec;
}
}
}
return ErrorCondition.OK;
}
/**
* Validate the given sender with the given room for this feature
* @param sender MucRoomMember to test
* @param room MucRoom of the room
* @return ErrorCondition
* @throws MessageException
*/
public ErrorCondition validate( final MucRoomMember sender,
final MucRoom room )
throws MessageException
{
return ErrorCondition.OK;
}
/**
* Return a new {@link org.jabber.protocol.disco_info.Feature} instance
* representing this MucFeature
*
* @return
*/
public org.jabber.protocol.disco_info.Feature getDiscoInfoFeature()
{
final org.jabber.protocol.disco_info.Feature f =
new org.jabber.protocol.disco_info.Feature();
f.setVar( toString().toLowerCase() );
return f;
}
public org.jabber.protocol.disco_info.QueryBuilder add(
final org.jabber.protocol.disco_info.QueryBuilder builder )
{
return builder.addFeature( new FeatureBuilder().setVar( toString().toLowerCase() ) );
}
/**
* Add the {@link org.jabber.protocol.disco_info.Feature} representing this
* MucFeature to the supplied {@link org.jabber.protocol.disco_info.Query}
*
* @param query
* @throws NullPointerException if query is null
*/
public void add( org.jabber.protocol.disco_info.Query query )
{
query.getFeature().add( getDiscoInfoFeature() );
}
}