Commit 80b0b21b authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Allow to have bare JIDs inside shared groups (does not include JIDs of remote users). JM-210

git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@3117 b35dd754-fafc-0310-a699-88a17e54d16e
parent c61a38c2
......@@ -12,16 +12,17 @@
package org.jivesoftware.messenger.group;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.util.*;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.List;
/**
* Database implementation of the GroupManager interface.
......@@ -63,6 +64,8 @@ public class DefaultGroupProvider implements GroupProvider {
"SELECT groupName FROM jiveGroupUser WHERE username=?";
private static final String ALL_GROUPS = "SELECT groupName FROM jiveGroup ORDER BY groupName";
private XMPPServer server = XMPPServer.getInstance();
public Group createGroup(String name) throws GroupAlreadyExistsException {
Connection con = null;
PreparedStatement pstmt = null;
......@@ -82,8 +85,8 @@ public class DefaultGroupProvider implements GroupProvider {
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
}
Collection<String> members = getMembers(name, false);
Collection<String> administrators = getMembers(name, true);
Collection<JID> members = getMembers(name, false);
Collection<JID> administrators = getMembers(name, true);
return new Group(this, name, "", members, administrators);
}
......@@ -112,8 +115,8 @@ public class DefaultGroupProvider implements GroupProvider {
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
}
Collection<String> members = getMembers(name, false);
Collection<String> administrators = getMembers(name, true);
Collection<JID> members = getMembers(name, false);
Collection<JID> administrators = getMembers(name, true);
return new Group(this, name, description, members, administrators);
}
......@@ -306,14 +309,14 @@ public class DefaultGroupProvider implements GroupProvider {
return groups;
}
public Collection<Group> getGroups(User user) {
public Collection<Group> getGroups(JID user) {
List<String> groupNames = new ArrayList<String>();
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(USER_GROUPS);
pstmt.setString(1, user.getUsername());
pstmt.setString(1, server.isLocal(user) ? user.getNode() : user.toString());
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
groupNames.add(rs.getString(1));
......@@ -342,14 +345,14 @@ public class DefaultGroupProvider implements GroupProvider {
return groups;
}
public void addMember(String groupName, String username, boolean administrator) {
public void addMember(String groupName, JID user, boolean administrator) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(ADD_USER);
pstmt.setString(1, groupName);
pstmt.setString(2, username);
pstmt.setString(2, server.isLocal(user) ? user.getNode() : user.toString());
pstmt.setInt(3, administrator ? 1 : 0);
pstmt.executeUpdate();
}
......@@ -364,7 +367,7 @@ public class DefaultGroupProvider implements GroupProvider {
}
}
public void updateMember(String groupName, String username, boolean administrator) {
public void updateMember(String groupName, JID user, boolean administrator) {
Connection con = null;
PreparedStatement pstmt = null;
try {
......@@ -372,7 +375,7 @@ public class DefaultGroupProvider implements GroupProvider {
pstmt = con.prepareStatement(UPDATE_USER);
pstmt.setInt(1, administrator ? 1 : 0);
pstmt.setString(2, groupName);
pstmt.setString(3, username);
pstmt.setString(3, server.isLocal(user) ? user.getNode() : user.toString());
pstmt.executeUpdate();
}
catch (SQLException e) {
......@@ -386,14 +389,14 @@ public class DefaultGroupProvider implements GroupProvider {
}
}
public void deleteMember(String groupName, String username) {
public void deleteMember(String groupName, JID user) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(REMOVE_USER);
pstmt.setString(1, groupName);
pstmt.setString(2, username);
pstmt.setString(2, server.isLocal(user) ? user.getNode() : user.toString());
pstmt.executeUpdate();
}
catch (SQLException e) {
......@@ -411,8 +414,8 @@ public class DefaultGroupProvider implements GroupProvider {
return false;
}
private Collection<String> getMembers(String groupName, boolean adminsOnly) {
List<String> members = new ArrayList<String>();
private Collection<JID> getMembers(String groupName, boolean adminsOnly) {
List<JID> members = new ArrayList<JID>();
Connection con = null;
PreparedStatement pstmt = null;
try {
......@@ -426,7 +429,15 @@ public class DefaultGroupProvider implements GroupProvider {
pstmt.setString(1, groupName);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
members.add(rs.getString(1));
String user = rs.getString(1);
JID userJID = new JID(user);
if (user.indexOf('@') == -1) {
// Create JID of local user if JID does not match a component's JID
if (!server.matchesComponent(userJID)) {
userJID = server.createJID(user, null);
}
}
members.add(userJID);
}
rs.close();
}
......
......@@ -14,8 +14,6 @@ package org.jivesoftware.messenger.group;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.event.GroupEventDispatcher;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.Log;
......@@ -51,8 +49,8 @@ public class Group implements Cacheable {
private String name;
private String description;
private Map<String, String> properties;
private Collection<String> members;
private Collection<String> administrators;
private Collection<JID> members;
private Collection<JID> administrators;
/**
* Constructs a new group. Note: this constructor is intended for implementors of the
......@@ -66,7 +64,7 @@ public class Group implements Cacheable {
* @param administrators a Collection of the group administrators.
*/
public Group(GroupProvider provider, String name, String description,
Collection<String> members, Collection<String> administrators)
Collection<JID> members, Collection<JID> administrators)
{
this.provider = provider;
this.groupManager = GroupManager.getInstance();
......@@ -172,7 +170,7 @@ public class Group implements Cacheable {
*
* @return a Collection of the group administrators.
*/
public Collection<String> getAdmins() {
public Collection<JID> getAdmins() {
// Return a wrapper that will intercept add and remove commands.
return new MemberCollection(administrators, true);
}
......@@ -182,24 +180,19 @@ public class Group implements Cacheable {
*
* @return a Collection of the group members.
*/
public Collection<String> getMembers() {
public Collection<JID> getMembers() {
// Return a wrapper that will intercept add and remove commands.
return new MemberCollection(members, false);
}
/**
* Returns true if the provided username belongs to a local user that is part of the group.
* Returns true if the provided username belongs to a user that is part of the group.
*
* @param user the JID address of the user to check.
* @return true if the provided username belongs to a user of the group.
* @return true if the specified user is a group user.
*/
public boolean isUser(JID user) {
String serverName = XMPPServer.getInstance().getServerInfo().getName();
if (user != null && serverName.equals(user.getDomain())) {
return isUser(user.getNode());
} else {
return false;
}
return user != null && (members.contains(user) || administrators.contains(user));
}
/**
......@@ -210,7 +203,7 @@ public class Group implements Cacheable {
*/
public boolean isUser(String username) {
if (username != null) {
return members.contains(username) || administrators.contains(username);
return isUser(XMPPServer.getInstance().createJID(username, null));
} else {
return false;
}
......@@ -232,18 +225,18 @@ public class Group implements Cacheable {
*/
private class MemberCollection extends AbstractCollection {
private Collection<String> users;
private Collection<JID> users;
private boolean adminCollection;
public MemberCollection(Collection<String> users, boolean adminCollection) {
public MemberCollection(Collection<JID> users, boolean adminCollection) {
this.users = users;
this.adminCollection = adminCollection;
}
public Iterator iterator() {
public Iterator<JID> iterator() {
return new Iterator() {
Iterator iter = users.iterator();
Iterator<JID> iter = users.iterator();
Object current = null;
public boolean hasNext() {
......@@ -259,7 +252,7 @@ public class Group implements Cacheable {
if (current == null) {
throw new IllegalStateException();
}
String user = (String)current;
JID user = (JID)current;
// Remove the user from the collection in memory.
iter.remove();
// Remove the group user from the backend store.
......@@ -267,13 +260,13 @@ public class Group implements Cacheable {
// Fire event.
if (adminCollection) {
Map<String, String> params = new HashMap<String, String>();
params.put("admin", user);
params.put("admin", user.toString());
GroupEventDispatcher.dispatchEvent(Group.this,
GroupEventDispatcher.EventType.admin_removed, params);
}
else {
Map<String, String> params = new HashMap<String, String>();
params.put("member", user);
params.put("member", user.toString());
GroupEventDispatcher.dispatchEvent(Group.this,
GroupEventDispatcher.EventType.member_removed, params);
}
......@@ -286,36 +279,29 @@ public class Group implements Cacheable {
}
public boolean add(Object member) {
String username = (String) member;
try {
username = Stringprep.nodeprep(username);
UserManager.getInstance().getUser(username);
}
catch (Exception e) {
throw new IllegalArgumentException("Invalid user.", e);
}
JID user = (JID) member;
// Find out if the user was already a group user
boolean alreadyGroupUser = false;
if (adminCollection) {
alreadyGroupUser = members.contains(username);
alreadyGroupUser = members.contains(user);
}
else {
alreadyGroupUser = administrators.contains(username);
alreadyGroupUser = administrators.contains(user);
}
if (users.add(username)) {
if (users.add(user)) {
if (alreadyGroupUser) {
// Update the group user privileges in the backend store.
provider.updateMember(name, username, adminCollection);
provider.updateMember(name, user, adminCollection);
}
else {
// Add the group user to the backend store.
provider.addMember(name, username, adminCollection);
provider.addMember(name, user, adminCollection);
}
// Fire event.
if (adminCollection) {
Map<String, String> params = new HashMap<String, String>();
params.put("admin", username);
params.put("admin", user.toString());
if (alreadyGroupUser) {
GroupEventDispatcher.dispatchEvent(Group.this,
GroupEventDispatcher.EventType.member_removed, params);
......@@ -325,7 +311,7 @@ public class Group implements Cacheable {
}
else {
Map<String, String> params = new HashMap<String, String>();
params.put("member", username);
params.put("member", user.toString());
if (alreadyGroupUser) {
GroupEventDispatcher.dispatchEvent(Group.this,
GroupEventDispatcher.EventType.admin_removed, params);
......@@ -337,13 +323,13 @@ public class Group implements Cacheable {
// user from the other collection
if (alreadyGroupUser) {
if (adminCollection) {
if (members.contains(username)) {
members.remove(username);
if (members.contains(user)) {
members.remove(user);
}
}
else {
if (administrators.contains(username)) {
administrators.remove(username);
if (administrators.contains(user)) {
administrators.remove(user);
}
}
}
......
......@@ -15,6 +15,8 @@ import org.jivesoftware.util.*;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.messenger.event.GroupEventDispatcher;
import org.jivesoftware.messenger.XMPPServer;
import org.xmpp.packet.JID;
import java.util.Collection;
import java.util.Collections;
......@@ -136,12 +138,13 @@ public class GroupManager {
* @param user the deleted user from the system.
*/
public void deleteUser(User user) {
for (Group group : getGroups(user)) {
if (group.getAdmins().contains(user.getUsername())) {
group.getAdmins().remove(user.getUsername());
JID userJID = XMPPServer.getInstance().createJID(user.getUsername(), null);
for (Group group : getGroups(userJID)) {
if (group.getAdmins().contains(userJID)) {
group.getAdmins().remove(userJID);
}
else {
group.getMembers().remove(user.getUsername());
group.getMembers().remove(userJID);
}
}
}
......@@ -186,12 +189,12 @@ public class GroupManager {
}
/**
* Returns an iterator for all groups that a user is a member of.
* Returns an iterator for all groups that the entity with the specified JID is a member of.
*
* @param user the user to get a list of groups for.
* @return all groups that a user belongs to.
* @param user the JID of the entity to get a list of groups for.
* @return all groups that an entity belongs to.
*/
public Collection<Group> getGroups(User user) {
public Collection<Group> getGroups(JID user) {
// TODO: add caching
return provider.getGroups(user);
}
......
......@@ -11,7 +11,7 @@
package org.jivesoftware.messenger.group;
import org.jivesoftware.messenger.user.User;
import org.xmpp.packet.JID;
import java.util.Collection;
......@@ -113,46 +113,46 @@ public interface GroupProvider {
Collection<Group> getGroups(int startIndex, int numResults);
/**
* Returns the Collection of Groups that a user belongs to.
* Returns the Collection of Groups that an entity belongs to.
*
* @param user the user.
* @param user the JID of the entity.
* @return the Collection of groups that the user belongs to.
*/
Collection<Group> getGroups(User user);
Collection<Group> getGroups(JID user);
/**
* Adds a user to a group (optional operation).
* Adds an entity to a group (optional operation).
*
* @param groupName the group to add the member to
* @param username the username to add
* @param user the JID of the entity to add
* @param administrator True if the member is an administrator of the group
* @throws UnsupportedOperationException if the provider does not
* support the operation.
*/
void addMember(String groupName, String username, boolean administrator)
void addMember(String groupName, JID user, boolean administrator)
throws UnsupportedOperationException;
/**
* Updates the privileges of a user in a group.
* Updates the privileges of an entity in a group.
*
* @param groupName the group where the change happened
* @param username the username to of the user with new privileges
* @param user the JID of the entity with new privileges
* @param administrator True if the member is an administrator of the group
* @throws UnsupportedOperationException if the provider does not
* support the operation.
*/
void updateMember(String groupName, String username, boolean administrator)
void updateMember(String groupName, JID user, boolean administrator)
throws UnsupportedOperationException;
/**
* Deletes a user from a group (optional operation).
* Deletes an entity from a group (optional operation).
*
* @param groupName the group name.
* @param username the username.
* @param user the JID of the entity to delete.
* @throws UnsupportedOperationException if the provider does not
* support the operation.
*/
void deleteMember(String groupName, String username) throws UnsupportedOperationException;
void deleteMember(String groupName, JID user) throws UnsupportedOperationException;
/**
* Returns true if this GroupProvider is read-only. When read-only,
......
......@@ -11,22 +11,20 @@
package org.jivesoftware.messenger.ldap;
import org.jivesoftware.util.*;
import org.jivesoftware.messenger.user.*;
import org.jivesoftware.messenger.group.*;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.group.Group;
import org.jivesoftware.messenger.group.GroupProvider;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
import java.util.ArrayList;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Vector;
import java.text.MessageFormat;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
import javax.naming.ldap.LdapName;
import java.text.MessageFormat;
import java.util.*;
/**
* LDAP implementation of the GroupProvider interface. All data in the directory is
......@@ -171,8 +169,9 @@ public class LdapGroupProvider implements GroupProvider {
return populateGroups(v.elements());
}
public Collection<Group> getGroups(User user) {
String username = JID.unescapeNode(user.getUsername());
public Collection<Group> getGroups(JID user) {
XMPPServer server = XMPPServer.getInstance();
String username = server.isLocal(user) ? JID.unescapeNode(user.getNode()) : user.toString();
if (!manager.isPosixMode()) {
try {
username = manager.findUserDN(username) + "," +
......@@ -192,11 +191,11 @@ public class LdapGroupProvider implements GroupProvider {
* LDAP groups are read-only.
*
* @param groupName name of a group.
* @param username name of a user.
* @param user the JID of the user to add
* @param administrator true if is an administrator.
* @throws UnsupportedOperationException when called.
*/
public void addMember(String groupName, String username, boolean administrator)
public void addMember(String groupName, JID user, boolean administrator)
throws UnsupportedOperationException
{
throw new UnsupportedOperationException();
......@@ -207,11 +206,11 @@ public class LdapGroupProvider implements GroupProvider {
* LDAP groups are read-only.
*
* @param groupName the naame of a group.
* @param username the name of a user.
* @param user the JID of the user with new privileges
* @param administrator true if is an administrator.
* @throws UnsupportedOperationException when called.
*/
public void updateMember(String groupName, String username, boolean administrator)
public void updateMember(String groupName, JID user, boolean administrator)
throws UnsupportedOperationException
{
throw new UnsupportedOperationException();
......@@ -222,10 +221,10 @@ public class LdapGroupProvider implements GroupProvider {
* LDAP groups are read-only.
*
* @param groupName the name of a group.
* @param username the ame of a user.
* @param user the JID of the user to delete.
* @throws UnsupportedOperationException when called.
*/
public void deleteMember(String groupName, String username)
public void deleteMember(String groupName, JID user)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
......@@ -306,6 +305,8 @@ public class LdapGroupProvider implements GroupProvider {
ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String userSearchFilter = MessageFormat.format(manager.getSearchFilter(), "*");
XMPPServer server = XMPPServer.getInstance();
String serverName = server.getServerInfo().getName();
while (answer.hasMoreElements()) {
String name = "";
......@@ -319,7 +320,7 @@ public class LdapGroupProvider implements GroupProvider {
catch (Exception e) {
description = "";
}
TreeSet<String> members = new TreeSet<String>();
TreeSet<JID> members = new TreeSet<JID>();
Attribute member = a.get(manager.getGroupMemberField());
NamingEnumeration ne = member.getAll();
while (ne.hasMore()) {
......@@ -352,13 +353,22 @@ public class LdapGroupProvider implements GroupProvider {
// Therefore, we have to try to load each user we found to see if
// it passes the filter.
try {
// In order to lookup a username from the manager, the username
// must be a properly escaped JID node.
String escapedUsername = JID.escapeNode(username);
userManager.getUser(escapedUsername);
// No exception, so the user must exist. Add the user as a group
// member using the escaped username.
members.add(escapedUsername);
JID userJID = null;
// Create JID of local user if JID does not match a component's JID
if (!username.contains(serverName)) {
// In order to lookup a username from the manager, the username
// must be a properly escaped JID node.
String escapedUsername = JID.escapeNode(username);
userManager.getUser(escapedUsername);
// No exception, so the user must exist. Add the user as a group
// member using the escaped username.
userJID = server.createJID(escapedUsername, null);
}
else {
// This is a JID of a component or node of a server's component
userJID = new JID(username);
}
members.add(userJID);
}
catch (UserNotFoundException e) {
if (manager.isDebugEnabled()) {
......@@ -369,7 +379,7 @@ public class LdapGroupProvider implements GroupProvider {
if (manager.isDebugEnabled()) {
Log.debug("Adding group \"" + name + "\" with " + members.size() + " members.");
}
Group g = new Group(this, name, description, members, new ArrayList<String>());
Group g = new Group(this, name, description, members, new ArrayList<JID>());
groups.put(name, g);
}
catch (Exception e) {
......
......@@ -164,9 +164,8 @@ public class BroadcastPlugin implements Plugin, Component, PropertyEventListener
if (disableGroupPermissions ||
(groupMembersAllowed && group.isUser(message.getFrom())) ||
allowedUsers.contains(message.getFrom().toBareJID())) {
for (String user : group.getMembers()) {
for (JID userJID : group.getMembers()) {
Message newMessage = message.createCopy();
JID userJID = XMPPServer.getInstance().createJID(user, null);
newMessage.setTo(userJID);
try {
componentManager.sendPacket(this, newMessage);
......
......@@ -304,7 +304,8 @@ public class RegistrationPlugin implements Plugin {
try {
GroupManager groupManager = GroupManager.getInstance();
Group group = groupManager.getGroup(getGroup());
group.getMembers().add(user.getUsername());
group.getMembers()
.add(XMPPServer.getInstance().createJID(user.getUsername(), null));
}
catch (GroupNotFoundException e) {
Log.error(e);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment