Commit 1bad1502 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Changing name to Wildfire (initial work).

git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@3208 b35dd754-fafc-0310-a699-88a17e54d16e
parent bb8e15b8
/**
* $RCSfile: BroadcastPlugin.java,v $
* $Revision: 3117 $
* $Date: 2005-11-25 22:57:29 -0300 (Fri, 25 Nov 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.*;
import org.jivesoftware.util.PropertyEventListener;
import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.group.GroupManager;
import org.jivesoftware.wildfire.group.Group;
import org.jivesoftware.wildfire.group.GroupNotFoundException;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.JID;
import org.xmpp.component.Component;
import org.xmpp.component.ComponentManager;
import org.xmpp.component.ComponentManagerFactory;
import java.io.File;
import java.util.*;
/**
* Broadcast service plugin. It accepts messages and broadcasts them out to
* groups of connected users. The address <tt>all@[serviceName].[server]</tt> is
* reserved for sending a broadcast message to all connected users. Otherwise,
* broadcast messages can be sent to groups of users by using addresses
* in the form <tt>[group]@[serviceName].[server]</tt>.
*
* @author Matt Tucker
*/
public class BroadcastPlugin implements Plugin, Component, PropertyEventListener {
private String serviceName;
private SessionManager sessionManager;
private GroupManager groupManager;
private List<JID> allowedUsers;
private boolean groupMembersAllowed;
private boolean disableGroupPermissions;
private ComponentManager componentManager;
private PluginManager pluginManager;
/**
* Constructs a new broadcast plugin.
*/
public BroadcastPlugin() {
serviceName = JiveGlobals.getProperty("plugin.broadcast.serviceName", "broadcast");
disableGroupPermissions = JiveGlobals.getBooleanProperty(
"plugin.broadcast.disableGroupPermissions");
groupMembersAllowed = JiveGlobals.getBooleanProperty(
"plugin.broadcast.groupMembersAllowed", true);
allowedUsers = stringToList(JiveGlobals.getProperty("plugin.broadcast.allowedUsers", ""));
}
// Plugin Interface
public void initializePlugin(PluginManager manager, File pluginDirectory) {
pluginManager = manager;
sessionManager = SessionManager.getInstance();
groupManager = GroupManager.getInstance();
// Register as a component.
componentManager = ComponentManagerFactory.getComponentManager();
try {
componentManager.addComponent(serviceName, this);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
PropertyEventDispatcher.addListener(this);
}
public void destroyPlugin() {
PropertyEventDispatcher.removeListener(this);
// Unregister component.
try {
componentManager.removeComponent(serviceName);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
componentManager = null;
pluginManager = null;
sessionManager = null;
groupManager = null;
allowedUsers.clear();
}
public void initialize(JID jid, ComponentManager componentManager) {
}
public void start() {
}
public void shutdown() {
}
// Component Interface
public String getName() {
// Get the name from the plugin.xml file.
return pluginManager.getName(this);
}
public String getDescription() {
// Get the description from the plugin.xml file.
return pluginManager.getDescription(this);
}
public void processPacket(Packet packet) {
// Only respond to incoming messages. TODO: handle disco, presence, etc.
if (packet instanceof Message) {
Message message = (Message)packet;
String toNode = message.getTo().getNode();
String fromNode = message.getFrom().getNode();
// Check to see if trying to broadcast to all connected users.
if ("all".equals(toNode)) {
if (allowedUsers.size() > 0) {
// See if the user is allowed to send the message.
JID address = new JID(message.getFrom().toBareJID());
if (!allowedUsers.contains(address)) {
Message error = new Message();
if (message.getID() != null) {
error.setID(message.getID());
}
error.setError(PacketError.Condition.not_allowed);
error.setTo(message.getFrom());
error.setSubject("Error sending broadcast message");
error.setBody("Not allowed to send a broadcast message to " +
message.getTo());
try {
componentManager.sendPacket(this, error);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
return;
}
}
try {
sessionManager.broadcast(message);
}
catch (UnauthorizedException ue) {
Log.error(ue);
}
}
// See if the name is a group.
else {
try {
Group group = groupManager.getGroup(toNode);
if (disableGroupPermissions ||
(groupMembersAllowed && group.isUser(message.getFrom())) ||
allowedUsers.contains(message.getFrom().toBareJID())) {
for (JID userJID : group.getMembers()) {
Message newMessage = message.createCopy();
newMessage.setTo(userJID);
try {
componentManager.sendPacket(this, newMessage);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
}
}
else {
// Otherwise, the address is recognized so send an error message back.
Message error = new Message();
if (message.getID() != null) {
error.setID(message.getID());
}
error.setTo(message.getFrom());
error.setError(PacketError.Condition.not_allowed);
error.setSubject("Error sending broadcast message");
error.setBody("Not allowed to send a broadcast message to " +
message.getTo());
try {
componentManager.sendPacket(this, error);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
}
}
catch (GroupNotFoundException gnfe) {
// Otherwise, the address is recognized so send an error message back.
Message error = new Message();
if (message.getID() != null) {
error.setID(message.getID());
}
error.setTo(message.getFrom());
error.setError(PacketError.Condition.not_allowed);
error.setSubject("Error sending broadcast message");
error.setBody("Address not valid: " +
message.getTo());
try {
componentManager.sendPacket(this, error);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
}
}
}
}
// Other Methods
/**
* Returns the service name of this component, which is "broadcast" by default.
*
* @return the service name of this component.
*/
public String getServiceName() {
return serviceName;
}
/**
* Sets the service name of this component, which is "broadcast" by default.
*
* @param serviceName the service name of this component.
*/
public void setServiceName(String serviceName) {
JiveGlobals.setProperty("plugin.broadcast.serviceName", serviceName);
}
/**
* Returns a collection of the addresses of users allowed to send broadcast
* messages. If no users are defined, anyone can send broadcast messages to
* all users. Additional users may also be allowed to send broadcast messages
* to specific groups depending on the group settings.
*
* @return the users allowed to send broadcast messages.
*/
public Collection<JID> getGlobalAllowedUsers() {
return allowedUsers;
}
/**
* Sets the collection of addresses of users allowed to send broadcast
* messages. If the collection is empty, anyone can send broadcast messages.
* Additional users may also be allowed to send broadcast messages to
* specific groups depending on the group settings.
*
* @param allowedUsers collection of users allowed to send broadcast messages
* to all users.
*/
public void setGlobalAllowedUsers(Collection<String> allowedUsers) {
StringBuilder buf = new StringBuilder();
for (String jid : allowedUsers) {
buf.append(jid).append(",");
}
JiveGlobals.setProperty("plugin.broadcast.allowedUsers", buf.toString());
}
/**
* Returns true if all permission checking on sending messages to groups is disabled
* (enabled by default). When disabled, any user in the system can send a message to
* a group.
*
* @return true if group permission checking is disabled.
*/
public boolean isGroupPermissionsDisabled() {
return disableGroupPermissions;
}
/**
* Enables or disables permission checking when sending messages to a group. When
* disabled, any user in the system can send a message to a group.
*
* @param disableGroupPermissions true if group permission checking should be disabled.
*/
public void setGroupPermissionsDisabled(boolean disableGroupPermissions) {
this.disableGroupPermissions = disableGroupPermissions;
JiveGlobals.setProperty("plugin.broadcast.disableGroupPermissions",
Boolean.toString(disableGroupPermissions));
}
/**
* Returns true if normal group members are allowed to send broadcast messages
* to groups they belong to. Otherwise, only group administrators can send
* broadcast messages to groups. Global allowed users can also send messages to
* groups.
*
* @return true if group members are allowed to broadcast messages; otherwise only
* group admins are allowed.
*/
public boolean isGroupMembersAllowed() {
return groupMembersAllowed;
}
/**
* Sets whether normal group members are allowed to send broadcast messages
* to groups they belong to. Otherwise, only group administrators can send
* broadcast messages to groups. Global allowed users can also send messages to
* groups.
*
* @param allowed true if group members are allowed to broadcast messages; otherwise only
* group admins are allowed.
*/
public void setGroupMembersAllowed(boolean allowed) {
this.groupMembersAllowed = allowed;
JiveGlobals.setProperty("plugin.broadcast.groupMembersAllowed", Boolean.toString(allowed));
}
// PropertyEventListener Methods
public void propertySet(String property, Map params) {
if (property.equals("plugin.broadcast.groupMembersAllowed")) {
this.groupMembersAllowed = Boolean.parseBoolean((String)params.get("value"));
}
else if (property.equals("plugin.broadcast.disableGroupPermissions")) {
this.disableGroupPermissions = Boolean.parseBoolean((String)params.get("value"));
}
else if (property.equals("plugin.broadcast.allowedUsers")) {
this.allowedUsers = stringToList((String)params.get("value"));
}
else if (property.equals("plugin.broadcast.serviceName")) {
changeServiceName((String)params.get("value"));
}
}
public void propertyDeleted(String property, Map params) {
if (property.equals("plugin.broadcast.groupMembersAllowed")) {
this.groupMembersAllowed = true;
}
else if (property.equals("plugin.broadcast.disableGroupPermissions")) {
this.disableGroupPermissions = false;
}
else if (property.equals("plugin.broadcast.allowedUsers")) {
this.allowedUsers = Collections.emptyList();
}
else if (property.equals("plugin.broadcast.serviceName")) {
changeServiceName("broadcast");
}
}
public void xmlPropertySet(String property, Map params) {
// Ignore.
}
public void xmlPropertyDeleted(String property, Map params) {
// Ignore.
}
/**
* Changes the service name to a new value.
*
* @param serviceName the service name.
*/
private void changeServiceName(String serviceName) {
if (serviceName == null) {
throw new NullPointerException("Service name cannot be null");
}
if (this.serviceName.equals(serviceName)) {
return;
}
// Re-register the service.
try {
componentManager.removeComponent(this.serviceName);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
try {
componentManager.addComponent(serviceName, this);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
this.serviceName = serviceName;
}
/**
* Returns a comma-delimitted list of strings into a Collection of Strings.
*
* @param str the String.
* @return a list.
*/
private List<JID> stringToList(String str) {
List<JID> values = new ArrayList<JID>();
StringTokenizer tokens = new StringTokenizer(str, ",");
while (tokens.hasMoreTokens()) {
String value = tokens.nextToken().trim();
if (!value.equals("")) {
// See if this is a full JID or just a username.
if (value.contains("@")) {
values.add(new JID(value));
}
else {
values.add(XMPPServer.getInstance().createJID(value, null));
}
}
}
return values;
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision: 1594 $
* $Date: 2005-07-04 14:08:42 -0300 (Mon, 04 Jul 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin;
import org.xmpp.packet.Message;
import java.util.ArrayList;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Filters message content using regular expressions. If a content mask is
* provided message content will be altered.
*
* @author Conor Hayes
*/
public class ContentFilter {
private String patterns;
private Collection<Pattern> compiledPatterns = new ArrayList<Pattern>();
private String mask;
/**
* A default instance will allow all message content.
*
* @see #setPatterns(String)
* @see #setMask(String)
*/
public ContentFilter() {
}
/**
* Set the patterns to use for searching content.
*
* @param regExps a comma separated String of regular expressions
*/
public void setPatterns(String patterns) {
if (patterns != null) {
this.patterns = patterns;
String[] data = patterns.split(",");
compiledPatterns.clear();
for (int i = 0; i < data.length; i++) {
compiledPatterns.add(Pattern.compile(data[i]));
}
}
else {
clearPatterns();
}
}
public String getPatterns() {
return this.patterns;
}
/**
* Clears all patterns. Calling this method means that all message content
* will be allowed.
*/
public void clearPatterns() {
patterns = null;
compiledPatterns.clear();
}
/**
* Set the content replacement mask.
*
* @param mask the mask to use when replacing content
*/
public void setMask(String mask) {
this.mask = mask;
}
/**
* @return the current mask or null if none has been set
*/
public String getMask() {
return mask;
}
/**
* Clears the content mask.
*
* @see #filter(Message)
*/
public void clearMask() {
mask = null;
}
/**
* @return true if the filter is currently masking content, false otherwise
*/
public boolean isMaskingContent() {
return mask != null;
}
/**
* Filters message content.
*
* @param msg the message to filter, its subject/body may be altered if there
* are content matches and a content mask is set
* @return true if the msg content matched up, false otherwise
*/
public boolean filter(Message msg) {
boolean hasMatch = false;
if (msg.getSubject() != null) {
if (hasMatch(msg.getSubject())) {
hasMatch = true;
if (isMaskingContent()) {
String newSubject = replaceContent(msg.getSubject());
msg.setSubject(newSubject);
}
}
}
if (msg.getBody() != null) {
if (hasMatch(msg.getBody())) {
hasMatch = true;
if (isMaskingContent()) {
String newBody = replaceContent(msg.getBody());
msg.setBody(newBody);
}
}
}
return hasMatch;
}
private String replaceContent(String content) {
for (Pattern pattern : compiledPatterns) {
Matcher m = pattern.matcher(content);
content = m.replaceAll(mask);
}
return content;
}
/**
* Performs sequential search for any pattern match.
*
* @param content the content to search against
* @return true if a match is found, false otherwise
*/
private boolean hasMatch(String content) {
boolean hasMatch = false;
for (Pattern pattern : compiledPatterns) {
Matcher m = pattern.matcher(content);
if (m.find()) {
hasMatch = true;
break;
}
}
return hasMatch;
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision: 1594 $
* $Date: 2005-07-04 14:08:42 -0300 (Mon, 04 Jul 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin;
import org.jivesoftware.wildfire.MessageRouter;
import org.jivesoftware.wildfire.Session;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.interceptor.InterceptorManager;
import org.jivesoftware.wildfire.interceptor.PacketInterceptor;
import org.jivesoftware.wildfire.interceptor.PacketRejectedException;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import java.io.File;
/**
* Content filter plugin.
*
* @author Conor Hayes
*/
public class ContentFilterPlugin implements Plugin, PacketInterceptor {
/**
* The expected value is a boolean, if true the user identified by the value
* of the property #VIOLATION_NOTIFICATION_CONTACT_PROPERTY will be notified
* every time there is a content match, otherwise no notification will be
* sent. Then default value is false.
*/
public static final String VIOLATION_NOTIFICATION_ENABLED_PROPERTY =
"plugin.contentFilter.violation.notification.enabled";
/**
* The expected value is a user name. The default value is "admin".
*/
public static final String VIOLATION_NOTIFICATION_CONTACT_PROPERTY =
"plugin.contentFilter.violation.notification.contact";
/**
* The expected value is a boolean, if true the sender will be notified when a
* message is rejected, otherwise the message will be silently rejected,i.e. the
* sender will not know that the message was rejected and the receiver will
* not get the message. The default value is false.
*/
public static final String REJECTION_NOTIFICATION_ENABLED_PROPERTY =
"plugin.contentFilter.rejection.notification.enabled";
/**
* The expected value is a string, containing the desired message for the
* sender notification.
*/
public static final String REJECTION_MSG_PROPERTY = "plugin.contentFilter.rejection.msg";
/**
* The expected value is a boolean, if true the value of #PATTERNS_PROPERTY
* will be used for pattern matching.
*/
public static final String PATTERNS_ENABLED_PROPERTY = "plugin.contentFilter.patterns.enabled";
/**
* The expected value is a comma separated string of regular expressions.
*/
public static final String PATTERNS_PROPERTY = "plugin.contentFilter.patterns";
/**
* The expected value is a boolean, if true the value of #MASK_PROPERTY will
* be used to mask matching content.
*/
public static final String MASK_ENABLED_PROPERTY = "plugin.contentFilter.mask.enabled";
/**
* The expected value is a string. If this property is set any
* matching content will not be rejected but masked with the given value.
* Setting a content mask means that property #SENDER_NOTIFICATION_ENABLED_PROPERTY
* is ignored. The default value is "**".
*/
public static final String MASK_PROPERTY = "plugin.contentFilter.mask";
/**
* the hook into the inteceptor chain
*/
private InterceptorManager interceptorManager;
/**
* used to send violation notifications
*/
private MessageRouter messageRouter;
/**
* delegate that does the real work of this plugin
*/
private ContentFilter contentFilter;
/**
* flags if sender should be notified of rejections
*/
private boolean rejectionNotificationEnabled;
/**
* the rejection msg to send
*/
private String rejectionMessage;
/**
* flags if content matches should result in admin notification
*/
private boolean violationNotificationEnabled;
/**
* the admin user to send violation notifications to
*/
private String violationContact;
/**
* flag if patterns should be used
*/
private boolean patternsEnabled;
/**
* the patterns to use
*/
private String patterns;
/**
* flag if mask should be used
*/
private boolean maskEnabled;
/**
* the mask to use
*/
private String mask;
/**
* violation notification messages will be from this JID
*/
private JID violationNotificationFrom;
public ContentFilterPlugin() {
contentFilter = new ContentFilter();
interceptorManager = InterceptorManager.getInstance();
violationNotificationFrom = new JID(XMPPServer.getInstance()
.getServerInfo().getName());
messageRouter = XMPPServer.getInstance().getMessageRouter();
}
public boolean isMaskEnabled() {
return maskEnabled;
}
public void setMaskEnabled(boolean enabled) {
maskEnabled = enabled;
JiveGlobals.setProperty(MASK_ENABLED_PROPERTY, enabled ? "true" : "false");
changeContentFilterMask();
}
public void setMask(String mas) {
mask = mas;
JiveGlobals.setProperty(MASK_PROPERTY, mas);
changeContentFilterMask();
}
private void changeContentFilterMask() {
if (maskEnabled) {
contentFilter.setMask(mask);
}
else {
contentFilter.clearMask();
}
}
public String getMask() {
return mask;
}
public boolean isPatternsEnabled() {
return patternsEnabled;
}
public void setPatternsEnabled(boolean enabled) {
patternsEnabled = enabled;
JiveGlobals.setProperty(PATTERNS_ENABLED_PROPERTY, enabled ? "true"
: "false");
changeContentFilterPatterns();
}
public void setPatterns(String patt) {
patterns = patt;
JiveGlobals.setProperty(PATTERNS_PROPERTY, patt);
changeContentFilterPatterns();
}
private void changeContentFilterPatterns() {
if (patternsEnabled) {
contentFilter.setPatterns(patterns);
}
else {
contentFilter.clearPatterns();
}
}
public String getPatterns() {
return patterns;
}
public boolean isRejectionNotificationEnabled() {
return rejectionNotificationEnabled;
}
public void setRejectionNotificationEnabled(boolean enabled) {
rejectionNotificationEnabled = enabled;
JiveGlobals.setProperty(REJECTION_NOTIFICATION_ENABLED_PROPERTY,
enabled ? "true" : "false");
}
public String getRejectionMessage() {
return rejectionMessage;
}
public void setRejectionMessage(String message) {
this.rejectionMessage = message;
JiveGlobals.setProperty(REJECTION_MSG_PROPERTY, message);
}
public boolean isViolationNotificationEnabled() {
return violationNotificationEnabled;
}
public void setViolationNotificationEnabled(boolean enabled) {
violationNotificationEnabled = enabled;
JiveGlobals.setProperty(VIOLATION_NOTIFICATION_ENABLED_PROPERTY,
enabled ? "true" : "false");
}
public void setViolationContact(String contact) {
violationContact = contact;
JiveGlobals.setProperty(VIOLATION_NOTIFICATION_CONTACT_PROPERTY, contact);
}
public String getViolationContact() {
return violationContact;
}
public void initializePlugin(PluginManager pManager, File pluginDirectory) {
// configure this plugin
initFilter();
// register with interceptor manager
interceptorManager.addInterceptor(this);
}
private void initFilter() {
// default to false
violationNotificationEnabled = JiveGlobals.getBooleanProperty(
VIOLATION_NOTIFICATION_ENABLED_PROPERTY, false);
// default to "admin"
violationContact = JiveGlobals.getProperty(VIOLATION_NOTIFICATION_CONTACT_PROPERTY,
"admin");
// default to false
rejectionNotificationEnabled = JiveGlobals.getBooleanProperty(
REJECTION_NOTIFICATION_ENABLED_PROPERTY, false);
// default to english
rejectionMessage = JiveGlobals.getProperty(REJECTION_MSG_PROPERTY,
"Message rejected. This is an automated server response");
// default to false
patternsEnabled = JiveGlobals.getBooleanProperty(PATTERNS_ENABLED_PROPERTY,
false);
//default to "fox,dog"
patterns = JiveGlobals.getProperty(PATTERNS_PROPERTY, "fox,dog");
changeContentFilterPatterns();
// default to false
maskEnabled = JiveGlobals.getBooleanProperty(MASK_ENABLED_PROPERTY, false);
//default to "***"
mask = JiveGlobals.getProperty(MASK_PROPERTY, "***");
changeContentFilterMask();
}
/**
* @see org.jivesoftware.wildfire.container.Plugin#destroyPlugin()
*/
public void destroyPlugin() {
// unregister with interceptor manager
interceptorManager.removeInterceptor(this);
}
public void interceptPacket(Packet packet, Session session, boolean read,
boolean processed) throws PacketRejectedException {
if (patternsEnabled && !processed && (packet instanceof Message)) {
Message msg = (Message) packet;
// filter the message
boolean contentMatched = contentFilter.filter(msg);
// notify contact of violations
if (contentMatched && violationNotificationEnabled) {
sendViolationNotification(msg);
}
// reject the message if not masking content
if (contentMatched && !maskEnabled) {
PacketRejectedException rejected = new PacketRejectedException(
"Message rejected with disallowed content!");
if (rejectionNotificationEnabled) {
// let the sender know about the rejection, this is
// only possible/useful if the content is not masked
rejected.setRejectionMessage(rejectionMessage);
}
throw rejected;
}
}
}
private void sendViolationNotification(Message offendingMsg) {
String subject = "Content filter notification!";
String msg = "Disallowed content detected in message from:"
+ offendingMsg.getFrom() + " to:" + offendingMsg.getTo()
+ ", message was "
+ (contentFilter.isMaskingContent() ? "altered" : "rejected");
messageRouter.route(createServerMessage(subject, msg));
}
private Message createServerMessage(String subject, String body) {
Message message = new Message();
message.setTo(violationContact + "@"
+ violationNotificationFrom.getDomain());
message.setFrom(violationNotificationFrom);
message.setSubject(subject);
message.setBody(body);
return message;
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision: 1722 $
* $Date: 2005-07-28 19:19:16 -0300 (Thu, 28 Jul 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.user.UserManager;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.wildfire.PresenceManager;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import java.io.File;
/**
* Plugin that includes a servlet that provides information about the presence type of the
* users in the server. For security reasons, the XMPP spec does not allow anyone to see
* the presence of any user. Only the users that are subscribed to the presence of other
* users may see their presences.<p>
*
* However, in order to make the servlet more useful it is possible to configure this plugin
* so that anyone or only the users that are subscribed to a user presence may see the presence
* of other users.<p>
*
* Currently, the servlet provides information about user presences in two formats. In XML format
* or using images.
*
* @author Gaston Dombiak
*/
public class PresencePlugin implements Plugin {
private UserManager userManager;
private PresenceManager presenceManager;
private String hostname;
public void initializePlugin(PluginManager manager, File pluginDirectory) {
XMPPServer server = XMPPServer.getInstance();
userManager = server.getUserManager();
presenceManager = server.getPresenceManager();
hostname = server.getServerInfo().getName();
}
public void destroyPlugin() {
userManager = null;
presenceManager = null;
}
/**
* Returns true if anyone is allowed to see the presence of other users. False means that
* only the users that are subscribed to a user presence will be able to get information
* about the user. By default, presence information is not publicly available.
*
* @return true if anyone is allowed to see the presence of other users.
*/
public boolean isPresencePublic() {
return JiveGlobals.getBooleanProperty("plugin.presence.public", false);
}
/**
* Sets if anyone is allowed to see the presence of other users. A false value means that
* only the users that are subscribed to a user presence will be able to get information
* about the user. By default, presence information is not publicly available.
*
* @param presencesPublic if anyone is allowed to see the presence of other users.
*/
public void setPresencePublic(boolean presencesPublic) {
JiveGlobals.setProperty("plugin.presence.public", presencesPublic ? "true" : "false");
}
/**
* Returns the presence of the requested user or <tt>null</tt> if the user is offline. If
* presences are not public then the user presence will be returned if and only if the sender
* of the request is subscribed to the user presence.
*
* @param sender the bare JID of the user making the request.
* @param jid the bare JID of the entity whose presence is being probed.
* @return the presence of the requested user.
* @throws UserNotFoundException If presences are not public and the sender is null or the
* sender cannot probe the presence of the requested user. Or if the requested user
* does not exist in the local server.
*/
public Presence getPresence(String sender, String jid) throws UserNotFoundException {
JID targetJID = new JID(jid);
// Check that the sender is not requesting information of a remote server entity
if (targetJID.getDomain() == null || XMPPServer.getInstance().isRemote(targetJID)) {
throw new UserNotFoundException("Domain does not matches local server domain");
}
if (!hostname.equals(targetJID.getDomain())) {
// Sender is requesting information about component presence
// TODO Implement this
throw new UserNotFoundException("Presence of components not supported yet!");
}
if (targetJID.getNode() == null) {
// Sender is requesting presence information of an anonymous user
throw new UserNotFoundException("Username is null");
}
if (!isPresencePublic()) {
if (sender == null) {
throw new UserNotFoundException("Sender is null");
}
else if (!presenceManager.canProbePresence(new JID(sender), targetJID.getNode())) {
throw new UserNotFoundException("Sender is not allowed to probe this user");
}
}
User user = userManager.getUser(targetJID.getNode());
return presenceManager.getPresence(user);
}
}
/**
* $RCSfile$
* $Revision: 1682 $
* $Date: 2005-07-22 18:13:38 -0300 (Fri, 22 Jul 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin.presence;
import org.jivesoftware.util.Log;
import org.xmpp.packet.Presence;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
/**
* The ImagePresenceProvider provides information about the users presence by returning
* images. There are many ways to specify the images to use.
*
* <ul>
* <li>Use a single parameter in the URL - Use the <b>images</b> parameter that will include a
* --IMAGE-- token. The --IMAGE-- token would be filtered and would be replaced with
* codes like "dnd", "offline", "away", etc.</li>
* <li>Use a parameter for each possible presence type - Possible parameters are: <b>offline</b>,
* <b>available</b>, <b>away</b>, <b>chat</b>, <b>dnd</b>, <b>xa</b> and <b>forbidden</b>. If
* the parameter was not passed then the default image will be used.</li>
* <li>Do not pass any parameter - When no parameter was passed the default images will be
* used.</li>
* </ul>
*
* If the required user was not found or the user making the request is not allowed to see the
* user presence then the image specified in the <b>forbidden</b> parameter will be used.
* However, if the request does not include the <b>forbidden</b> parameter then the default
* image for user offline will be used.
*
* @author Gaston Dombiak
*
*/
class ImagePresenceProvider extends PresenceInfoProvider {
private PresenceStatusServlet servlet;
private Map<String, byte[]> imageCache = new HashMap<String, byte[]>();
private Map<String, String> imageTypeCache = new HashMap<String, String>();
public ImagePresenceProvider(PresenceStatusServlet servlet) {
this.servlet = servlet;
}
public void sendInfo(HttpServletRequest request,
HttpServletResponse response, Presence presence) throws IOException {
if (presence == null) {
writeImageContent(request, response, "offline", servlet.offline);
}
else if (presence.getShow() == null) {
writeImageContent(request, response, "available", servlet.available);
}
else if (presence.getShow().equals(org.xmpp.packet.Presence.Show.away)) {
writeImageContent(request, response, "away", servlet.away);
}
else if (presence.getShow().equals(org.xmpp.packet.Presence.Show.chat)) {
writeImageContent(request, response, "chat", servlet.chat);
}
else if (presence.getShow().equals(org.xmpp.packet.Presence.Show.dnd)) {
writeImageContent(request, response, "dnd", servlet.dnd);
}
else if (presence.getShow().equals(org.xmpp.packet.Presence.Show.xa)) {
writeImageContent(request, response, "xa", servlet.xa);
}
}
public void sendUserNotFound(HttpServletRequest request, HttpServletResponse response)
throws IOException {
writeImageContent(request, response, "forbidden", servlet.offline);
}
private void writeImageContent(HttpServletRequest request, HttpServletResponse response,
String presenceType, byte[] defaultImage) throws IOException {
String images = request.getParameter("images");
if (request.getParameter(presenceType) != null) {
writeImageContent(request.getParameter(presenceType), defaultImage, response);
}
else if (images != null) {
writeImageContent(images.replace("--IMAGE--", presenceType), defaultImage, response);
}
else {
writeImageContent(null, defaultImage, response);
}
}
private void writeImageContent(String url, byte[] defaultContent, HttpServletResponse response)
throws IOException {
ServletOutputStream os = response.getOutputStream();
byte[] imageContent = defaultContent;
String contentType = "image/gif";
if (url != null) {
try {
byte[] cachedContent = imageCache.get(url);
if (cachedContent == null) {
URLConnection connection = new URL(url).openConnection();
InputStream in = connection.getInputStream();
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
byte buffer[] = new byte[1024 * 4];
int last_read_bytes = 0;
while ((last_read_bytes = in.read(buffer)) != -1) {
bytes.write(buffer, 0, last_read_bytes);
}
if (bytes.size() > 0) {
imageCache.put(url, bytes.toByteArray());
imageTypeCache.put(url, connection.getContentType());
}
}
if (imageTypeCache.get(url) != null) {
contentType = imageTypeCache.get(url);
imageContent = imageCache.get(url);
}
}
catch (IOException e) {
Log.error(e);
}
}
response.setContentType(contentType);
os.write(imageContent);
os.flush();
os.close();
}
}
/**
* $RCSfile$
* $Revision: 1660 $
* $Date: 2005-07-21 00:05:27 -0300 (Thu, 21 Jul 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin.presence;
import org.xmpp.packet.Presence;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Abstract class for the different ways to provide information about user presences.
*
* @author Gaston Dombiak
*/
abstract class PresenceInfoProvider {
/**
* Sends information to the sender of the http request about the presence of a user.
*
* @param httpServletRequest the http request.
* @param httpServletResponse the http response.
* @param presence the presence of the user or <tt>null</tt> if the user is offline.
* @throws IOException If an error occured while sending the information.
*/
public abstract void sendInfo(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Presence presence) throws IOException;
/**
* Informs the sender of the http request that the user presence is not available. This may
* happen if the user does not exist or if the user that made the request is not allowed to
* see the presence of the requested user.
*
* @param httpServletRequest the http request.
* @param httpServletResponse the http response.
* @throws IOException If an error occured while sending the information.
*/
public abstract void sendUserNotFound(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws IOException;
}
/**
* $RCSfile$
* $Revision: 1710 $
* $Date: 2005-07-26 15:56:14 -0300 (Tue, 26 Jul 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin.presence;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.plugin.PresencePlugin;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.jivesoftware.util.Log;
import org.jivesoftware.admin.AuthCheckFilter;
import org.xmpp.packet.Presence;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Servlet that provides information about the presence status of the users in the system.
* The information may be provided in XML format or in graphical mode. Use the <b>type</b>
* parameter to specify the type of information to get. Possible values are <b>image</b> and
* <b>xml</b>. If no type was defined then an image representation is assumed.<p>
* <p/>
* The request <b>MUST</b> include the <b>jid</b> parameter. This parameter will be used
* to locate the local user in the server. If this parameter is missing from the request then
* an error will be logged and nothing will be returned.
*
* @author Gaston Dombiak
*/
public class PresenceStatusServlet extends HttpServlet {
private PresencePlugin plugin;
private XMLPresenceProvider xmlProvider;
private ImagePresenceProvider imageProvider;
byte available[];
byte away[];
byte chat[];
byte dnd[];
byte offline[];
byte xa[];
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
plugin =
(PresencePlugin) XMPPServer.getInstance().getPluginManager().getPlugin("presence");
xmlProvider = new XMLPresenceProvider();
imageProvider = new ImagePresenceProvider(this);
available = loadResource("/images/user-green-16x16.gif");
away = loadResource("/images/user-yellow-16x16.gif");
chat = loadResource("/images/user-green-16x16.gif");
dnd = loadResource("/images/user-red-16x16.gif");
offline = loadResource("/images/user-clear-16x16.gif");
xa = loadResource("/images/user-yellow-16x16.gif");
// Exclude this servlet from requering the user to login
AuthCheckFilter.addExclude("presence/status");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String sender = request.getParameter("req_jid");
String jid = request.getParameter("jid");
String type = request.getParameter("type");
type = type == null ? "image" : type;
try {
Presence presence = plugin.getPresence(sender, jid);
if ("image".equals(type)) {
imageProvider.sendInfo(request, response, presence);
}
else if ("xml".equals(type)) {
xmlProvider.sendInfo(request, response, presence);
}
else {
Log.warn("The presence servlet received an invalid request of type: " + type);
// TODO Do something
}
}
catch (UserNotFoundException e) {
if ("image".equals(type)) {
imageProvider.sendUserNotFound(request, response);
}
else if ("xml".equals(type)) {
xmlProvider.sendUserNotFound(request, response);
}
else {
Log.warn("The presence servlet received an invalid request of type: " + type);
// TODO Do something
}
}
catch (IllegalArgumentException e) {
if ("image".equals(type)) {
imageProvider.sendUserNotFound(request, response);
}
else if ("xml".equals(type)) {
xmlProvider.sendUserNotFound(request, response);
}
else {
Log.warn("The presence servlet received an invalid request of type: " + type);
// TODO Do something
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
public void destroy() {
super.destroy();
available = null;
away = null;
chat = null;
dnd = null;
offline = null;
xa = null;
// Release the excluded URL
AuthCheckFilter.removeExclude("presence/status");
}
private byte[] loadResource(String path) {
ServletContext context = getServletContext();
InputStream in = context.getResourceAsStream(path);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
for (int i = in.read(); i > -1; i = in.read()) {
out.write(i);
}
}
catch (IOException e) {
Log.error("error loading:" + path);
}
return out.toByteArray();
}
}
/**
* $RCSfile$
* $Revision: 1680 $
* $Date: 2005-07-22 17:49:46 -0300 (Fri, 22 Jul 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin.presence;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* The XMLPresenceProvider provides information about the users presence in XML format.
* The returned XML will include the last known presence of the user. If the user is offline
* then the unavailable presence will be recreated with the last known presence status.
*
* @author Gaston Dombiak
*/
class XMLPresenceProvider extends PresenceInfoProvider {
public void sendInfo(HttpServletRequest request, HttpServletResponse response,
Presence presence) throws IOException {
response.setContentType("text/xml");
PrintWriter out = response.getWriter();
if (presence == null) {
// Recreate the unavailable presence with the last known status
JID targetJID = new JID(request.getParameter("jid"));
presence = new Presence(Presence.Type.unavailable);
XMPPServer server = XMPPServer.getInstance();
try {
User user = server.getUserManager().getUser(targetJID.getNode());
String status = server.getPresenceManager().getLastPresenceStatus(user);
if (status != null) {
presence.setStatus(status);
}
}
catch (UserNotFoundException e) {}
presence.setFrom(targetJID);
}
out.println(presence.toXML());
out.flush();
}
public void sendUserNotFound(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.setContentType("text/xml");
PrintWriter out = response.getWriter();
// Send a forbidden presence
Presence presence = new Presence();
presence.setError(PacketError.Condition.forbidden);
try {
presence.setFrom(new JID(request.getParameter("jid")));
}
catch (Exception e) {}
try {
presence.setTo(new JID(request.getParameter("req_jid")));
}
catch (Exception e) {}
out.println(presence.toXML());
out.flush();
}
}
/**
* Copyright (C) 2005 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin;
import org.jivesoftware.wildfire.MessageRouter;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.event.UserEventDispatcher;
import org.jivesoftware.wildfire.event.UserEventListener;
import org.jivesoftware.wildfire.group.Group;
import org.jivesoftware.wildfire.group.GroupManager;
import org.jivesoftware.wildfire.group.GroupNotFoundException;
import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.util.EmailService;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
/**
* Registration plugin.
*
* @author Ryan Graham.
*/
public class RegistrationPlugin implements Plugin {
/**
* The expected value is a boolean, if true all contacts specified in the property #IM_CONTACTS
* will receive a notification when a new user registers. The default value is false.
*/
private static final String IM_NOTIFICATION_ENABLED = "registration.imnotification.enabled";
/**
* The expected value is a boolean, if true all contacts specified in the property #EMAIL_CONTACTS
* will receive a notification when a new user registers. The default value is false.
*/
private static final String EMAIL_NOTIFICATION_ENABLED = "registration.emailnotification.enabled";
/**
* The expected value is a boolean, if true any user who registers will receive the welcome
* message specified in the property #WELCOME_MSG. The default value is false.
*/
private static final String WELCOME_ENABLED = "registration.welcome.enabled";
/**
* The expected value is a boolean, if true any user who registers will be added to the group
* specified in the property #REGISTRAION_GROUP. The default value is false.
*/
private static final String GROUP_ENABLED = "registration.group.enabled";
/**
* The expected value is a comma separated String of usernames who will receive a instant
* message when a new user registers if the property #IM_NOTIFICATION_ENABLED is set to true.
*/
private static final String IM_CONTACTS = "registration.notification.imContacts";
/**
* The expected value is a comma separated String of email addresses who will receive an email
* when a new user registers, if the property #EMAIL_NOTIFICATION_ENABLED is set to true.
*/
private static final String EMAIL_CONTACTS = "registration.notification.emailContacts";
/**
* The expected value is a String that contains the message that will be sent to a new user
* when they register, if the property #WELCOME_ENABLED is set to true.
*/
private static final String WELCOME_MSG = "registration.welcome.message";
/**
* The expected value is a String that contains the name of the group that a new user will
* be added to when they register, if the property #GROUP_ENABLED is set to true.
*/
private static final String REGISTRAION_GROUP = "registration.group";
private RegistrationUserEventListener listener = new RegistrationUserEventListener();
private String serverName;
private JID serverAddress;
private MessageRouter router;
private List<String> imContacts = new ArrayList<String>();
private List<String> emailContacts = new ArrayList<String>();
public RegistrationPlugin() {
serverName = XMPPServer.getInstance().getServerInfo().getName();
serverAddress = new JID(serverName);
router = XMPPServer.getInstance().getMessageRouter();
String imcs = JiveGlobals.getProperty(IM_CONTACTS);
if (imcs != null) {
imContacts.addAll(Arrays.asList(imcs.split(",")));
}
String ecs = JiveGlobals.getProperty(EMAIL_CONTACTS);
if (ecs != null) {
emailContacts.addAll(Arrays.asList(ecs.split(",")));
}
UserEventDispatcher.addListener(listener);
//delete properties from version 1.0
JiveGlobals.deleteProperty("registration.notification.contact");
JiveGlobals.deleteProperty("registration.notification.enabled");
}
public void processPacket(Packet packet) {
}
public void initializePlugin(PluginManager manager, File pluginDirectory) {
}
public void destroyPlugin() {
UserEventDispatcher.removeListener(listener);
serverAddress = null;
listener = null;
router = null;
}
public void setIMNotificationEnabled(boolean enable) {
JiveGlobals.setProperty(IM_NOTIFICATION_ENABLED, enable ? "true" : "false");
}
public boolean imNotificationEnabled() {
return JiveGlobals.getBooleanProperty(IM_NOTIFICATION_ENABLED, false);
}
public void setEmailNotificationEnabled(boolean enable) {
JiveGlobals.setProperty(EMAIL_NOTIFICATION_ENABLED, enable ? "true" : "false");
}
public boolean emailNotificationEnabled() {
return JiveGlobals.getBooleanProperty(EMAIL_NOTIFICATION_ENABLED, false);
}
public Collection<String> getIMContacts() {
Collections.sort(imContacts);
return imContacts;
}
public void addIMContact(String contact) {
if (!imContacts.contains(contact.trim().toLowerCase())) {
imContacts.add(contact.trim().toLowerCase());
JiveGlobals.setProperty(IM_CONTACTS, propPrep(imContacts));
}
}
public void removeIMContact(String contact) {
imContacts.remove(contact.trim().toLowerCase());
if (imContacts.size() == 0) {
JiveGlobals.deleteProperty(IM_CONTACTS);
}
else {
JiveGlobals.setProperty(IM_CONTACTS, propPrep(imContacts));
}
}
public Collection<String> getEmailContacts() {
Collections.sort(emailContacts);
return emailContacts;
}
public void addEmailContact(String contact) {
if (!emailContacts.contains(contact.trim())) {
emailContacts.add(contact.trim());
JiveGlobals.setProperty(EMAIL_CONTACTS, propPrep(emailContacts));
}
}
public void removeEmailContact(String contact) {
emailContacts.remove(contact);
if (emailContacts.size() == 0) {
JiveGlobals.deleteProperty(EMAIL_CONTACTS);
}
else {
JiveGlobals.setProperty(EMAIL_CONTACTS, propPrep(emailContacts));
}
}
public void setWelcomeEnabled(boolean enable) {
JiveGlobals.setProperty(WELCOME_ENABLED, enable ? "true" : "false");
}
public boolean welcomeEnabled() {
return JiveGlobals.getBooleanProperty(WELCOME_ENABLED, false);
}
public void setWelcomeMessage(String message) {
JiveGlobals.setProperty(WELCOME_MSG, message);
}
public String getWelcomeMessage() {
return JiveGlobals.getProperty(WELCOME_MSG, "Welcome to Wildfire!");
}
public void setGroupEnabled(boolean enable) {
JiveGlobals.setProperty(GROUP_ENABLED, enable ? "true" : "false");
}
public boolean groupEnabled() {
return JiveGlobals.getBooleanProperty(GROUP_ENABLED, false);
}
public void setGroup(String group) {
JiveGlobals.setProperty(REGISTRAION_GROUP, group);
}
public String getGroup() {
return JiveGlobals.getProperty(REGISTRAION_GROUP);
}
private class RegistrationUserEventListener implements UserEventListener {
public void userCreated(User user, Map params) {
if (imNotificationEnabled()) {
sendIMNotificatonMessage(user);
}
if (emailNotificationEnabled()) {
sendAlertEmail(user);
}
if (welcomeEnabled()) {
sendWelcomeMessage(user);
}
if (groupEnabled()) {
addUserToGroup(user);
}
}
public void userDeleting(User user, Map params) {
}
public void userModified(User user, Map params) {
}
private void sendIMNotificatonMessage(User user) {
String msg = " A new user with the username of '" + user.getUsername() + "' just registered";
for (String contact : getIMContacts()) {
router.route(createServerMessage(contact + "@" + serverName,
"Registration Notification", msg));
}
}
private void sendAlertEmail(User user) {
String msg = " A new user with the username of '" + user.getUsername() + "' just registered";
List<MimeMessage> messages = new ArrayList<MimeMessage>();
EmailService emailService = EmailService.getInstance();
MimeMessage message = emailService.createMimeMessage();
String encoding = MimeUtility.mimeCharset("iso-8859-1");
for (String toAddress : emailContacts) {
try {
message.setRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(toAddress));
message.setFrom(new InternetAddress("no_reply@" + serverName, "Wildfire", encoding));
message.setText(msg);
message.setSubject("User Registration");
messages.add(message);
} catch (Exception e) {
Log.error(e);
}
}
emailService.sendMessages(messages);
}
private void sendWelcomeMessage(User user) {
router.route(createServerMessage(user.getUsername() + "@" + serverName, "Welcome",
getWelcomeMessage()));
}
private Message createServerMessage(String to, String subject, String body) {
Message message = new Message();
message.setTo(to);
message.setFrom(serverAddress);
if (subject != null) {
message.setSubject(subject);
}
message.setBody(body);
return message;
}
private void addUserToGroup(User user) {
try {
GroupManager groupManager = GroupManager.getInstance();
Group group = groupManager.getGroup(getGroup());
group.getMembers()
.add(XMPPServer.getInstance().createJID(user.getUsername(), null));
}
catch (GroupNotFoundException e) {
Log.error(e);
}
}
}
private String propPrep(Collection<String> props) {
StringBuilder buf = new StringBuilder();
Iterator<String> iter = props.iterator();
while (iter.hasNext()) {
String con = iter.next();
buf.append(con);
if (iter.hasNext()) {
buf.append(",");
}
}
return buf.toString();
}
public boolean isValidAddress(String address) {
if (address == null) {
return false;
}
//must at least match x@x.xx
if (!address.matches(".{1,}[@].{1,}[.].{2,}")) {
return false;
}
return true;
}
}
/**
* Copyright (C) 2005 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.plugin;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.dom4j.Attribute;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.forms.DataForm;
import org.jivesoftware.wildfire.forms.FormField;
import org.jivesoftware.wildfire.forms.spi.XDataFormImpl;
import org.jivesoftware.wildfire.forms.spi.XFormFieldImpl;
import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.wildfire.user.UserManager;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener;
import org.xmpp.component.Component;
import org.xmpp.component.ComponentException;
import org.xmpp.component.ComponentManager;
import org.xmpp.component.ComponentManagerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
/**
* Provides support for Jabber Search
* (<a href="http://www.jabber.org/jeps/jep-0055.html">JEP-0055</a>).<p>
*
* The basic functionality is to query an information repository
* regarding the possible search fields, to send a search query,
* and to receive search results. This implementation below primarily uses
* <a href="http://www.jabber.org/jeps/jep-0004.html">Data Forms</a>, but
* limited support for non-datforms searches has been added to support the
* Miranda client.
* <p/>
*
* @author Ryan Graham
*/
public class SearchPlugin implements Component, Plugin, PropertyEventListener {
public static final String PLUGIN_SEARCH_SERVICENAME = "plugin.search.serviceName";
public static final String PLUGIN_SEARCH_SERVICEENABLED = "plugin.search.serviceEnabled";
private XMPPServer server;
private UserManager userManager;
private ComponentManager componentManager;
private PluginManager pluginManager;
private String serviceName;
private boolean serviceEnabled;
private static String serverName;
private static String instructions = "The following fields are available for search. "
+ "Wildcard (*) characters are allowed as part the of query.";
private static Element probeResult;
private Collection<String> searchFields;
public SearchPlugin() {
serviceName = JiveGlobals.getProperty("plugin.search.serviceName", "search");
serviceEnabled = JiveGlobals.getBooleanProperty("plugin.search.serviceEnabled", true);
server = XMPPServer.getInstance();
serverName = server.getServerInfo().getName();
// See if the installed provider supports searching. If not, workaround
// by providing our own searching.
UserManager manager = UserManager.getInstance();
try {
searchFields = manager.getSearchFields();
userManager = UserManager.getInstance();
searchFields = userManager.getSearchFields();
}
catch (UnsupportedOperationException uoe) {
// Use a SearchPluginUserManager instead.
searchFields = getSearchFields();
}
}
public String getName() {
return pluginManager.getName(this);
}
public String getDescription() {
return pluginManager.getDescription(this);
}
public void initializePlugin(PluginManager manager, File pluginDirectory) {
pluginManager = manager;
componentManager = ComponentManagerFactory.getComponentManager();
try {
componentManager.addComponent(serviceName, this);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
PropertyEventDispatcher.addListener(this);
if (probeResult == null) {
probeResult = DocumentHelper.createElement(QName.get("query", "jabber:iq:search"));
//non-data form
probeResult.addElement("instructions").addText(instructions);
XDataFormImpl searchForm = new XDataFormImpl(DataForm.TYPE_FORM);
searchForm.setTitle("User Search");
searchForm.addInstruction(instructions);
XFormFieldImpl field = new XFormFieldImpl("FORM_TYPE");
field.setType(FormField.TYPE_HIDDEN);
field.addValue("jabber:iq:search");
searchForm.addField(field);
field = new XFormFieldImpl("search");
field.setType(FormField.TYPE_TEXT_SINGLE);
field.setLabel("Search");
field.setRequired(false);
searchForm.addField(field);
for (String searchField : searchFields) {
//non-data form
probeResult.addElement(searchField.toLowerCase());
field = new XFormFieldImpl(searchField);
field.setType(FormField.TYPE_BOOLEAN);
field.addValue("1");
field.setLabel(searchField);
field.setRequired(false);
searchForm.addField(field);
}
probeResult.add(searchForm.asXMLElement());
}
}
public void initialize(JID jid, ComponentManager componentManager) {
}
public void start() {
}
public void destroyPlugin() {
PropertyEventDispatcher.removeListener(this);
pluginManager = null;
try {
componentManager.removeComponent(serviceName);
componentManager = null;
}
catch (Exception e) {
componentManager.getLog().error(e);
}
server = null;
userManager = null;
}
public void shutdown() {
}
public void processPacket(Packet p) {
if (p instanceof IQ) {
IQ packet = (IQ) p;
Element childElement = (packet).getChildElement();
String namespace = null;
if (childElement != null) {
namespace = childElement.getNamespaceURI();
}
if ("jabber:iq:search".equals(namespace)) {
try {
IQ replyPacket = handleIQ(packet);
componentManager.sendPacket(this, replyPacket);
}
catch (ComponentException e) {
componentManager.getLog().error(e);
}
}
else if ("http://jabber.org/protocol/disco#info".equals(namespace)) {
try {
IQ replyPacket = IQ.createResultIQ(packet);
Element responseElement = DocumentHelper.createElement(QName.get(
"query", "http://jabber.org/protocol/disco#info"));
responseElement.addElement("identity").addAttribute("category", "search")
.addAttribute("type", "text")
.addAttribute("name", "User Search");
responseElement.addElement("feature").addAttribute("var", "jabber:iq:search");
replyPacket.setChildElement(responseElement);
componentManager.sendPacket(this, replyPacket);
}
catch (ComponentException e) {
componentManager.getLog().error(e);
}
}
else if ("http://jabber.org/protocol/disco#items".equals(namespace)) {
try {
IQ replyPacket = IQ.createResultIQ(packet);
Element responseElement = DocumentHelper.createElement(QName.get(
"query", "http://jabber.org/protocol/disco#info"));
replyPacket.setChildElement(responseElement);
componentManager.sendPacket(this, replyPacket);
}
catch (ComponentException e) {
componentManager.getLog().error(e);
}
}
}
}
private IQ handleIQ(IQ packet) {
if (!serviceEnabled) {
return replyDisabled(packet);
}
if (IQ.Type.get.equals(packet.getType())) {
return processGetPacket(packet);
}
else if (IQ.Type.set.equals(packet.getType())) {
return processSetPacket(packet);
}
return null;
}
private IQ replyDisabled(IQ packet) {
Element reply = DocumentHelper.createElement(QName.get("query", "jabber:iq:search"));
XDataFormImpl unavailableForm = new XDataFormImpl(DataForm.TYPE_CANCEL);
unavailableForm.setTitle("User Search");
unavailableForm.addInstruction("This service is unavailable.");
reply.add(unavailableForm.asXMLElement());
IQ replyPacket = IQ.createResultIQ(packet);
replyPacket.setChildElement("query", "jabber:iq:search");
replyPacket.setChildElement(reply.createCopy());
return replyPacket;
}
private IQ processGetPacket(IQ packet) {
IQ replyPacket = IQ.createResultIQ(packet);
replyPacket.setChildElement("query", "jabber:iq:search");
replyPacket.setChildElement(probeResult.createCopy());
return replyPacket;
}
private IQ processSetPacket(IQ packet) {
Set<User> users = new HashSet<User>();
Element incomingForm = packet.getChildElement();
boolean isDataFormQuery = (incomingForm.element(QName.get("x", "jabber:x:data")) != null);
Hashtable<String, String> searchList = extractSearchQuery(incomingForm);
Enumeration<String> searchIter = searchList.keys();
while (searchIter.hasMoreElements()) {
String field = searchIter.nextElement();
String query = searchList.get(field);
Collection<User> foundUsers = new ArrayList<User>();
if (userManager != null) {
if (query.length() > 0 && !query.equals("jabber:iq:search")) {
foundUsers.addAll(userManager.findUsers(new HashSet<String>(
Arrays.asList((field))), query));
}
}
else {
foundUsers.addAll(findUsers(field, query));
}
for (User user : foundUsers) {
if (user != null) {
users.add(user);
}
}
}
if (isDataFormQuery) {
return replyDataFormResult(users, packet);
}
else {
return replyNonDataFormResult(users, packet);
}
}
/**
* nick, first, last, email fields have been hardcoded to support Miranda which does not
* make a query to discover which fields are available to be searched
*/
private Hashtable<String, String> extractSearchQuery(Element incomingForm) {
Hashtable<String, String> searchList = new Hashtable<String, String>();
Element form = incomingForm.element(QName.get("x", "jabber:x:data"));
if (form == null) {
Element name = incomingForm.element("name");
if (name != null) {
searchList.put("Name", name.getTextTrim());
}
Element nick = incomingForm.element("nick");
if (nick != null) {
searchList.put("Username", nick.getTextTrim());
}
Element first = incomingForm.element("first");
if (first != null) {
searchList.put("Name", first.getTextTrim());
}
Element last = incomingForm.element("last");
if (last != null) {
searchList.put("Name", last.getTextTrim());
}
Element email = incomingForm.element("email");
if (email != null) {
searchList.put("Email", email.getTextTrim());
}
}
else {
List<String> searchFields = new ArrayList<String>();
String search = "";
Iterator fields = form.elementIterator("field");
while (fields.hasNext()) {
Element searchField = (Element) fields.next();
String field = searchField.attributeValue("var");
String value = searchField.element("value").getTextTrim();
if (field.equals("search")) {
search = value;
}
else if (value.equals("1")) {
searchFields.add(field);
}
}
for (String field : searchFields) {
searchList.put(field, search);
}
}
return searchList;
}
private IQ replyDataFormResult(Set<User> users, IQ packet) {
XDataFormImpl searchResults = new XDataFormImpl(DataForm.TYPE_RESULT);
XFormFieldImpl field = new XFormFieldImpl("FORM_TYPE");
field.setType(FormField.TYPE_HIDDEN);
searchResults.addField(field);
field = new XFormFieldImpl("jid");
field.setLabel("JID");
searchResults.addReportedField(field);
for (String fieldName : searchFields) {
field = new XFormFieldImpl(fieldName);
field.setLabel(fieldName);
searchResults.addReportedField(field);
}
for (User user : users) {
String username = user.getUsername();
ArrayList<XFormFieldImpl> items = new ArrayList<XFormFieldImpl>();
XFormFieldImpl fieldJID = new XFormFieldImpl("jid");
fieldJID.addValue(username + "@" + serverName);
items.add(fieldJID);
XFormFieldImpl fieldUsername = new XFormFieldImpl("Username");
fieldUsername.addValue(username);
items.add(fieldUsername);
XFormFieldImpl fieldName = new XFormFieldImpl("Name");
fieldName.addValue(user.getName());
items.add(fieldName);
XFormFieldImpl fieldEmail = new XFormFieldImpl("Email");
fieldEmail.addValue(user.getEmail());
items.add(fieldEmail);
searchResults.addItemFields(items);
}
Element reply = DocumentHelper.createElement(QName.get("query", "jabber:iq:search"));
reply.add(searchResults.asXMLElement());
IQ replyPacket = IQ.createResultIQ(packet);
replyPacket.setChildElement(reply);
return replyPacket;
}
private IQ replyNonDataFormResult(Set<User> users, IQ packet) {
Element replyQuery = DocumentHelper.createElement(QName.get("query", "jabber:iq:search"));
String serverName = XMPPServer.getInstance().getServerInfo().getName();
for (User user : users) {
Element item = DocumentHelper.createElement("item");
Attribute jib = DocumentHelper.createAttribute(item, "jid", user.getUsername() + "@" + serverName);
item.add(jib);
Element nick = DocumentHelper.createElement("nick");
nick.addText(user.getName());
item.add(nick);
Element email = DocumentHelper.createElement("email");
email.addText(user.getEmail());
item.add(email);
replyQuery.add(item);
}
IQ replyPacket = IQ.createResultIQ(packet);
replyPacket.setChildElement(replyQuery);
return replyPacket;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String name) {
changeServiceName(name);
JiveGlobals.setProperty(PLUGIN_SEARCH_SERVICENAME, name);
}
public boolean getServiceEnabled() {
return serviceEnabled;
}
public void setServiceEnabled(boolean enabled) {
serviceEnabled = enabled;
JiveGlobals.setProperty(PLUGIN_SEARCH_SERVICEENABLED, enabled ? "true" : "false");
}
public void propertySet(String property, Map params) {
if (property.equals(PLUGIN_SEARCH_SERVICEENABLED)) {
this.serviceEnabled = Boolean.parseBoolean((String)params.get("value"));
}
else if (property.equals(PLUGIN_SEARCH_SERVICENAME)) {
changeServiceName((String)params.get("value"));
}
}
public void propertyDeleted(String property, Map params) {
if (property.equals(PLUGIN_SEARCH_SERVICEENABLED)) {
this.serviceEnabled = true;
}
else if (property.equals(PLUGIN_SEARCH_SERVICENAME)) {
changeServiceName("search");
}
}
public void xmlPropertySet(String property, Map params) {
// not used
}
public void xmlPropertyDeleted(String property, Map params) {
// not used
}
private void changeServiceName(String serviceName) {
if (serviceName == null) {
throw new NullPointerException("Service name cannot be null");
}
if (this.serviceName.equals(serviceName)) {
return;
}
// Re-register the service.
try {
componentManager.removeComponent(this.serviceName);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
try {
componentManager.addComponent(serviceName, this);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
this.serviceName = serviceName;
}
/**
* Returns the collection of field names that can be used to search for a
* user. Typical fields are username, name, and email. These values can be
* used to contruct a data form.
*/
public Collection<String> getSearchFields() {
return Arrays.asList("Username", "Name", "Email");
}
/**
* Finds a user using the specified field and query string. For example, a
* field name of "email" and query of "jsmith@example.com" would search for
* the user with that email address. Wildcard (*) characters are allowed as
* part of queries.
*
* A possible future improvement would be to have a third parameter that
* sets the maximum number of users returned and/or the number of users
* that are searched.
*/
public Collection<User> findUsers(String field, String query) {
List<User> foundUsers = new ArrayList<User>();
if (!getSearchFields().contains(field)) {
return foundUsers;
}
int index = query.indexOf("*");
if (index == -1) {
Collection<User> users = userManager.getUsers();
for (User user : users) {
if (field.equals("Username")) {
try {
foundUsers.add(userManager.getUser(query));
return foundUsers;
}
catch (UserNotFoundException e) {
Log.error("Error getting user", e);
}
}
else if (field.equals("Name")) {
if (query.equalsIgnoreCase(user.getName())) {
foundUsers.add(user);
}
}
else if (field.equals("Email")) {
if (user.getEmail() != null) {
if (query.equalsIgnoreCase(user.getEmail())) {
foundUsers.add(user);
}
}
}
}
}
else {
String prefix = query.substring(0, index);
Collection<User> users = userManager.getUsers();
for (User user : users) {
String userInfo = "";
if (field.equals("Username")) {
userInfo = user.getUsername();
}
else if (field.equals("Name")) {
userInfo = user.getName();
}
else if (field.equals("Email")) {
userInfo = user.getEmail() == null ? "" : user.getEmail();
}
if (index < userInfo.length()) {
if (userInfo.substring(0, index).equalsIgnoreCase(prefix)) {
foundUsers.add(user);
}
}
}
}
return foundUsers;
}
}
package org.jivesoftware.wildfire.plugin;
import org.apache.commons.fileupload.FileItem;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.roster.RosterItem;
import org.jivesoftware.wildfire.roster.RosterItemProvider;
import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.wildfire.user.UserAlreadyExistsException;
import org.jivesoftware.wildfire.user.UserManager;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.jivesoftware.wildfire.user.UserProvider;
import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
* The user import/export plugin provides a way to import and export Wildfire
* user data via the Admin Console. The user data consists of jid (aka "username"),
* name, email address, password and roster list (aka "buddy list"). This plugin also
* can aid in the migration of users from other Jabber/XMPP based systems to Jive
* Wildfire.
*
* @author Ryan Graham
*/
public class ImportExportPlugin implements Plugin {
private UserManager userManager;
private UserProvider provider;
private String serverName;
public ImportExportPlugin() {
userManager = XMPPServer.getInstance().getUserManager();
provider = UserManager.getUserProvider();
serverName = XMPPServer.getInstance().getServerInfo().getName();
}
public void initializePlugin(PluginManager manager, File pluginDirectory) {
}
public void destroyPlugin() {
userManager = null;
provider = null;
serverName = null;
}
public boolean isUserProviderReadOnly() {
return provider.isReadOnly();
}
public byte[] exportUsersToFile() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
XMLWriter writer = writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
writer.write(exportUsers());
return out.toByteArray();
}
public String exportUsersToString() throws IOException {
StringWriter stringWriter = new StringWriter();
XMLWriter writer = null;
try {
writer = new XMLWriter(stringWriter, OutputFormat.createPrettyPrint());
writer.write(exportUsers());
} catch (IOException ioe) {
Log.error(ioe);
throw ioe;
} finally {
if (writer != null) {
writer.close();
}
}
return stringWriter.toString();
}
public List<String> importUserData(FileItem file, String previousDomain) throws IOException, DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(file.getInputStream());
return importUsers(document, previousDomain);
}
public boolean validateImportFile(FileItem file) {
try {
return new UserSchemaValidator(file, "wildfire-user-schema.xsd.xml").validate();
}
catch (Exception e) {
Log.error(e);
return false;
}
}
private Document exportUsers() {
Document document = DocumentHelper.createDocument();
Element root = document.addElement("Wildfire");
Collection<User> users = userManager.getUsers();
for (User user : users) {
Element userElement = root.addElement("User");
String userName = user.getUsername();
userElement.addElement("Username").addText(userName);
try {
userElement.addElement("Password").addText(provider.getPassword(user.getUsername()));
}
catch (UserNotFoundException e) {
//this should never happen
Log.info("User not found: " + userName + ", setting password to their username");
userElement.addElement("Password").addText(userName);
}
userElement.addElement("Email").addText(user.getEmail() == null ? "" : user.getEmail());
String name = user.getName();
userElement.addElement("Name").addText(name == null ? "" : name);
//creation and modified datte are not used as part of the import process but are exported
//for historical purposes, should they be formatted differently?
userElement.addElement("CreationDate").addText(String.valueOf(user.getCreationDate().getTime()));
userElement.addElement("ModifiedDate").addText(String.valueOf(user.getModificationDate().getTime()));
Element rosterElement = userElement.addElement("Roster");
Collection<RosterItem> roster = user.getRoster().getRosterItems();
for (RosterItem ri : roster) {
Element itemElement = rosterElement.addElement("Item");
itemElement.addAttribute("jid", ri.getJid().toBareJID());
itemElement.addAttribute("askstatus", String.valueOf(ri.getAskStatus().getValue()));
itemElement.addAttribute("recvstatus", String.valueOf(ri.getRecvStatus().getValue()));
itemElement.addAttribute("substatus", String.valueOf(ri.getSubStatus().getValue()));
itemElement.addAttribute("name", ri.getNickname());
Element groupElement = itemElement.addElement("Group");
List<String> groups = ri.getGroups();
for (String group : groups) {
groupElement.addText(group);
}
}
}
return document;
}
private List<String> importUsers(Document document, String previousDomain) {
List<String> duplicateUsers = new ArrayList<String>();
UserManager userManager = UserManager.getInstance();
RosterItemProvider rosterItemProvider = RosterItemProvider.getInstance();
Map<String, List> rosterMap = new HashMap<String, List>();
Element users = document.getRootElement();
Iterator usersIter = users.elementIterator("User");
while (usersIter.hasNext()) {
Element user = (Element) usersIter.next();
String userName = null;
String password = null;
String email = null;
String name = null;
List<RosterItem> rosterItems = new ArrayList<RosterItem>();
Iterator userElements = user.elementIterator();
while (userElements.hasNext()) {
Element userElement = (Element) userElements.next();
String nameElement = userElement.getName();
if ("Username".equals(nameElement)) {
userName = userElement.getText();
}
else if ("Password".equals(nameElement)) {
password = userElement.getText();
}
else if ("Name".equals(nameElement)) {
name = userElement.getText();
}
else if ("Email".equals(nameElement)) {
email = userElement.getText();
}
else if ("Roster".equals(nameElement)) {
Iterator rosterIter = userElement.elementIterator("Item");
while (rosterIter.hasNext()) {
Element rosterElement = (Element) rosterIter.next();
String jid = rosterElement.attributeValue("jid");
String askstatus = rosterElement.attributeValue("askstatus");
String recvstatus = rosterElement.attributeValue("recvstatus");
String substatus = rosterElement.attributeValue("substatus");
String nickname = rosterElement.attributeValue("name");
List<String> groups = new ArrayList<String>();
Iterator groupIter = rosterElement.elementIterator("Group");
while (groupIter.hasNext()) {
Element group = (Element) groupIter.next();
groups.add(group.getText());
}
//used for migration
if (previousDomain != null) {
jid = jid.replace(previousDomain, serverName);
}
rosterItems.add(new RosterItem(new JID(jid),
RosterItem.SubType.getTypeFromInt(Integer.parseInt(substatus)),
RosterItem.AskType.getTypeFromInt(Integer.parseInt(askstatus)),
RosterItem.RecvType.getTypeFromInt(Integer.parseInt(recvstatus)),
nickname,
groups));
}
}
}
if ((userName != null) && (password != null)) {
try {
userManager.createUser(userName, password, name, email);
rosterMap.put(userName, rosterItems);
}
catch (UserAlreadyExistsException e) {
Log.info("User already exists: " + userName);
duplicateUsers.add(userName);
}
}
}
//this prevents a user from adding a non-existent user to their roster
Iterator i = rosterMap.keySet().iterator();
while (i.hasNext()) {
String userName = (String) i.next();
Iterator rosterIter = rosterMap.get(userName).iterator();
while (rosterIter.hasNext()) {
RosterItem ri = (RosterItem) rosterIter.next();
try {
// If the contact is a local user then check that the user exists
if (serverName.equals(ri.getJid().getDomain())) {
userManager.getUser(removeDoman(ri.getJid()));
}
rosterItemProvider.createItem(userName, ri);
}
catch (UserNotFoundException e) {
Log.info("User '" + removeDoman(ri.getJid()) + "' not found, will not be added to '" + userName + "' roster.");
}
catch (UserAlreadyExistsException e) {
Log.info("User '" + removeDoman(ri.getJid()) + "' already belongs to '" + userName + "' roster.");
}
}
}
return duplicateUsers;
}
private static String removeDoman(JID jid) {
StringTokenizer tokens = new StringTokenizer(jid.toBareJID(), "@");
if (tokens.hasMoreTokens()) {
return tokens.nextToken();
}
return null;
}
}
package org.jivesoftware.wildfire.plugin;
import com.sun.msv.reader.util.GrammarLoader;
import com.sun.msv.reader.util.IgnoreController;
import com.sun.msv.verifier.DocumentDeclaration;
import com.sun.msv.verifier.Verifier;
import org.apache.commons.fileupload.FileItem;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.dom4j.io.SAXWriter;
import org.jivesoftware.util.Log;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXParseException;
import java.io.IOException;
import java.net.URL;
import javax.xml.parsers.SAXParserFactory;
public class UserSchemaValidator {
private Document doc;
private String schema;
UserSchemaValidator(FileItem usersFile, String schemaFile) throws DocumentException, IOException {
SAXReader reader = new SAXReader();
doc = reader.read(usersFile.getInputStream());
URL schemaURL = this.getClass().getClassLoader().getResource(schemaFile);
schema = schemaURL.toExternalForm();
}
boolean validate() {
try {
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
saxFactory.setNamespaceAware(true);
DocumentDeclaration docDeclaration = GrammarLoader.loadVGM(schema, new IgnoreController() {
public void error(Locator[] locations,
String message,
Exception exception) {
Log.error("ERROR: " + message);
}
public void error(Locator[] locations, String message) {
Log.error("WARNING: " + message);
}
}, saxFactory);
ValidatorErrorHandler validatorErrorHandler = new ValidatorErrorHandler();
Verifier verifier = new Verifier(docDeclaration, validatorErrorHandler);
SAXWriter writer = new SAXWriter((ContentHandler) verifier);
writer.setErrorHandler(validatorErrorHandler);
writer.write(doc);
if (verifier.isValid()) {
return true;
} else {
Log.error(doc.getName() + " is invalid.");
return false;
}
} catch (Exception e) {
Log.error(e);
return false;
}
}
private class ValidatorErrorHandler implements ErrorHandler {
public void error(SAXParseException e) {
Log.error("ERROR:" + e);
}
public void fatalError(SAXParseException e) {
Log.error("Fatal:" + e);
}
public void warning(SAXParseException e) {
Log.error("Warning:" + 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