Commit b3f0b99e 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@3202 b35dd754-fafc-0310-a699-88a17e54d16e
parent ec7aa130
/**
* $RCSfile$
* $Revision$
* $Date$
*
* 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.messenger.plugin;
import org.jivesoftware.messenger.container.Plugin;
import org.jivesoftware.messenger.container.PluginManager;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.PresenceManager;
import org.jivesoftware.messenger.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$
* $Date$
*
* 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.messenger.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$
* $Date$
*
* 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.messenger.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$
* $Date$
*
* 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.messenger.plugin.presence;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.plugin.PresencePlugin;
import org.jivesoftware.messenger.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$
* $Date$
*
* 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.messenger.plugin.presence;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.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();
}
}
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