Commit 7fc0c18e authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gaston

Initial version. JM-234


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@1660 b35dd754-fafc-0310-a699-88a17e54d16e
parent dd735290
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Presence Plugin Changelog</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
H2 {
font-size : 10pt;
font-weight : bold;
padding-left : 1em;
}
A:hover {
text-decoration : none;
}
H1 {
font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE {
font-family : courier new;
font-size : 100%;
}
</style>
</head>
<body>
<h1>
Presence Plugin Changelog
</h1>
<p><b>1.0</b> -- Jul 20, 2005</p>
<ul>
<li>Initial release. </li>
</ul>
</body>
</html>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<class>org.jivesoftware.messenger.plugin.PresencePlugin</class>
<name>Presence Servlet</name>
<description>Exposes users presences through HTTP</description>
<author>Jive Software</author>
<version>1.0</version>
<date>07/20/2005</date>
<minServerVersion>2.2.0</minServerVersion>
<adminconsole>
<tab id="tab-server">
<sidebar id="sidebar-server-settings">
<item id="presence-servlet" name="Presence Servlet"
url="presence-servlet.jsp"
description="Click to manage servlet that exposes presence information" />
</sidebar>
</tab>
</adminconsole>
</plugin>
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Presence Plugin Readme</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
H2 {
font-size : 10pt;
font-weight : bold;
}
A:hover {
text-decoration : none;
}
H1 {
font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE {
font-family : courier new;
font-size : 100%;
}
</style>
</head>
<body>
<h1>
Presence Plugin Readme
</h1>
<h2>Overview</h2>
<p>
The presence plugin includes a servlet that provides presence information of the users in the server.
</p>
<h2>Installation</h2>
<p>Copy presence.jar into the plugins directory of your Jive Messenger installation. The
plugin will then be automatically deployed. To upgrade to a new version, copy the new
presence.jar file over the existing file.</p>
<h2>Configuration</h2>
The presence plugin can be configured via Jive Messenger Administration Console. Use the configuration
page to set if the presence information is visible to anyone or only to authorized users.
<h2>Using the Plugin</h2>
In order to get presence information of a user you should send HTTP requests to the servlet. The servlet
address should be [hostname]/plugins/presence/presence. Since the servlet may return different
types of content, the HTTP request should include a <b>type</b> parameter. Possible values are
<b>img</b> to get images that represent the user availability status or <b>xml</b> to get an XML stanza
with the presence of the user. If the <b>type</b> parameter is missing then an image format is assumed.<p>
Other parameters are:
<ul>
<li><b>sender</b> - bare JID of the user sending the request. This parameter is
optional if anyone may get presence information.</li>
<li><b>username</b> - username of the user whose presence is being probed. This parameter is
mandatory.</li>
</ul>
When using an image content type it is possible to configure the images to get depending on the user
presence status. Moreover, there are many ways to specify the images to use:
<ul>
<li>Use a single parameter for all the images - Use the <b>img</b> parameter that will include a
${presence} token. The ${presence} 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>. 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 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>notavailable</b> parameter will be used.
However, if the request does not include the <b>notavailable</b> parameter then the default
image for user offline will be used. Therefore, each request <b>MUST</b> include the
<b>notavailable</b> parameter.<p>
<b>Examples of URL<b>
This example is requesting images and is using a single parameter for all the images:
http://localhost:9090/plugins/presence/presence?username=admin&sender=user2@localhost&notavailable=http://localhost:9090/images/unknown.gif&img=http://localhost:9090/images/${presence}.gif
<p>
This example is requesting images and is sending a parameter for each possible presence type:
http://localhost:9090/plugins/presence/presence?username=admin&sender=user2@localhost&notavailable=http://localhost:9090/images/unknown.gif&offline=http://localhost:9090/images/user-red-16x16.gif&available=http://www.jivesoftware.com:9090/images/user-yellow-16x16.gif
</body>
</html>
/**
* $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;
public void initializePlugin(PluginManager manager, File pluginDirectory) {
XMPPServer server = XMPPServer.getInstance();
userManager = server.getUserManager();
presenceManager = server.getPresenceManager();
}
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. 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 username the username of the user 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 getUserPresence(String sender, String username) throws UserNotFoundException {
if (!isPresencePublic()) {
if (sender == null) {
throw new UserNotFoundException("Sender is null");
}
else if (!presenceManager.canProbePresence(new JID(sender), username)) {
throw new UserNotFoundException("Sender is not allowed to probe this user");
}
}
User user = userManager.getUser(username);
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>img</b> parameter that will include a
* ${presence} token. The ${presence} 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>. 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>notavailable</b> parameter will be used.
* However, if the request does not include the <b>notavailable</b> parameter then the default
* image for user offline will be used. Therefore, each request <b>MUST</b> include the
* <b>notavailable</b> parameter.
*
* @author Gaston Dombiak
*
*/
class ImagePresenceProvider extends PresenceInfoProvider {
private PresenceServlet servlet;
private Map<String, byte[]> imageCache = new HashMap<String, byte[]>();
private Map<String, String> imageTypeCache = new HashMap<String, String>();
public ImagePresenceProvider(PresenceServlet 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.getParameter("notavailable"), servlet.offline, response);
}
private void writeImageContent(HttpServletRequest request, HttpServletResponse response,
String presenceType, byte[] defaultImage) throws IOException {
String img = request.getParameter("img");
if (img != null) {
writeImageContent(img.replace("${presence}", presenceType), defaultImage, response);
}
else if (request.getParameter(presenceType) != null) {
writeImageContent(request.getParameter(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.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>img</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>username</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 PresenceServlet 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");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String sender = request.getParameter("sender");
String username = request.getParameter("username");
String type = request.getParameter("type");
type = type == null ? "img" : type;
try {
Presence presence = plugin.getUserPresence(sender, username);
if ("img".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 ("img".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;
}
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.xmpp.packet.Presence;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* The XMLPresenceProvider provides information about the users presence in XML format.
* The returned XML format has the following structure:
*
*
*
* @author Gaston Dombiak
*
*/
class XMLPresenceProvider extends PresenceInfoProvider {
public void sendInfo(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Presence presence) {
//TODO Implement
}
public void sendUserNotFound(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) {
//TODO Implement
}
}
<?xml version='1.0' encoding='ISO-8859-1'?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Servlets -->
<servlet>
<servlet-name>PresenceServlet</servlet-name>
<servlet-class>org.jivesoftware.messenger.plugin.presence.PresenceServlet</servlet-class>
</servlet>
<!-- Servlet mappings -->
<servlet-mapping>
<servlet-name>PresenceServlet</servlet-name>
<url-pattern>/presence</url-pattern>
</servlet-mapping>
</web-app>
<%@ page import="java.util.*,
org.jivesoftware.admin.*,
org.jivesoftware.messenger.XMPPServer,
org.jivesoftware.util.*,
org.jivesoftware.messenger.plugin.PresencePlugin"
errorPage="error.jsp"
%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
<%-- Define Administration Bean --%>
<jsp:useBean id="admin" class="org.jivesoftware.util.WebManager" />
<c:set var="admin" value="${admin.manager}" />
<% admin.init(request, response, session, application, out ); %>
<% // Get parameters
boolean save = request.getParameter("save") != null;
boolean success = request.getParameter("success") != null;
boolean presencePublic = ParamUtils.getBooleanParameter(request, "presencePublic");
PresencePlugin plugin = (PresencePlugin) XMPPServer.getInstance().getPluginManager().getPlugin("presence");
// Handle a save
Map errors = new HashMap();
if (save) {
if (errors.size() == 0) {
plugin.setPresencePublic(presencePublic);
response.sendRedirect("presence-servlet.jsp?success=true");
return;
}
}
presencePublic = plugin.isPresencePublic();
%>
<jsp:useBean id="pageinfo" scope="request" class="org.jivesoftware.admin.AdminPageBean" />
<%
String title = "Presence Servlet Properties";
pageinfo.setTitle(title);
pageinfo.getBreadcrumbs().add(new AdminPageBean.Breadcrumb(LocaleUtils.getLocalizedString("global.main"), "../../index.jsp"));
pageinfo.getBreadcrumbs().add(new AdminPageBean.Breadcrumb(title, "presence-servlet.jsp"));
pageinfo.setPageID("presence-servlet");
%>
<jsp:include page="top.jsp" flush="true" />
<jsp:include page="title.jsp" flush="true" />
<p>
Use the form below to configure users presence visibility. By default, users
presence should only be visible to those users that are authorized.<br>
</p>
<% if (success) { %>
<div class="jive-success">
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr><td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0"></td>
<td class="jive-icon-label">
Presence servlet properties edited successfully.
</td></tr>
</tbody>
</table>
</div><br>
<% } %>
<form action="presence-servlet.jsp?save" method="post">
<fieldset>
<legend>Presence visibility</legend>
<div>
<p>
For security reasons, the XMPP allows users to control which users are authorized to see their presences. However, it is
possible to configure the servlet so that anyone may get information about users presences. Use this feature with
precaution.
</p>
<table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td width="1%">
<input type="radio" name="presencePublic" value="true" id="rb01"
<%= ((presencePublic) ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb01"><b>Anyone</b> - Anyone may get presence information.</label>
</td>
</tr>
<tr>
<td width="1%">
<input type="radio" name="presencePublic" value="false" id="rb02"
<%= ((!presencePublic) ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb02"><b>Subscribed</b> - Presence information is only visibile to authorized users.</label>
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
<br><br>
<input type="submit" value="Save Properties">
</form>
<jsp:include page="bottom.jsp" flush="true" />
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