Commit 0b5ba6cf authored by Anno van Vliet's avatar Anno van Vliet Committed by daryl herzmann

Added User Status Plugin (#977)

* Added User Status Plugin
Plugin from Stefan Reuter to keep a history of the user status in the
database.

* revert unrelated javadoc change

* update plugin versioning

we still have to support ant builds

* update note about supported databases
parent e56d299e
......@@ -135,6 +135,7 @@
<module>userCreation</module>
<module>userImportExport</module>
<module>userservice</module>
<module>userStatus</module>
<module>xmldebugger</module>
</modules>
......
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>UserStatus Plugin Changelog</title>
<style type="text/css">
/* global font and body settings */
body {
font-size: 100%;
background-color: #d3d6d9;
padding: 0;
margin: 0 0 30px 0;
}
body, td, th {
font-family: arial, helvetica, sans-serif;
font-size: 10pt;
}
pre, tt, code {
font-family: courier new, monospace;
font-size: 9pt;
}
#pageContainer {
display: block;
position: relative;
clear: both;
background-color: #fff;
border: 1px solid #999;
padding: 40px;
margin: 30px;
}
#pageHeader {
display: block;
position: relative;
height: 80px;
background-color: #e7eaee;
border: 1px solid #cccccc;
border-bottom: none;
margin: 10px 0 0 0;
}
#pageBody {
margin: 0 18px 0 20px;
}
/* anchors */
a:link {
color: #11568c;
}
a:visited {
color: #571c8d;
}
a:hover {
color: #7a1d42;
text-decoration: underline;
}
a:active {
color: #7a1d42;
}
/* page header elements (logo and navigation) */
.navigation {
display: block;
position: relative;
height: 20px;
background-color: #335588;
border: 1px solid #cccccc;
border-top: none;
color: #ffffff;
font-size: 11px;
line-height: 18px;
padding: 0 0 0 0;
margin: 0 0 25px 0;
overflow: hidden;
}
.navigation a {
margin: 0 20px 0 20px;
}
.navigation a:link {
color: #ffffff;
}
.navigation a:visited {
color: #ffffff;
}
.navigation a:hover {
color: #ffffff;
}
.navigation a:active {
color: #ffffff;
}
/* headings */
h1 {
display: block;
position: relative;
font-size: 1.7em;
font-weight: bold;
color: #670e15;
padding: 0;
margin: 30px 0 0 20px;
}
h2 {
font-size: 1.3em;
font-weight: bold;
margin: 40px 0 6px 0;
padding: 0;
color: #335588;
}
h3 {
font-size: 1.0em;
font-weight: bold;
margin: 25px 0 3px 0;
padding: 0;
color: #334466;
}
/* general elements */
p {
margin: 0 0 15px 0;
}
ul {
margin: 5px 0 15px 35px;
}
li {
padding-bottom: 4px;
}
tt {
font-family: courier new, monospace;
font-weight: bold;
color: #060;
}
hr {
display: block;
height: 1px;
background-color: #999999;
border: none;
margin: 40px 0 20px 0;
}
.footer {
font-size: 8pt;
color: #666;
text-align: center;
margin-top: 2em;
padding-top: 0.5em;
border-top: 1px #CCC solid;
}
</style>
</head>
<body>
<div id="pageContainer">
<div id="pageHeader">
<h1>UserStatus Plugin Changelog</h1>
</div>
<div id="pageBody">
<h2>1.2.0 -- <span style="font-weight: normal;">December 13, 2017</span></h2>
<ul>
<li>Added to the Openfire deliverable</li>
</ul>
<h2>1.1.0 -- <span style="font-weight: normal;">October 24, 2017</span></h2>
<ul>
<li>Upgraded for Openfire 4.0.</li>
</ul>
<h2>1.0.3 -- <span style="font-weight: normal;">October 6, 2008</span></h2>
<ul>
<li>Added support for DB2.</li>
<li>Upgraded for Openfire 3.6.0.</li>
</ul>
<h2>1.0.2 -- <span style="font-weight: normal;">November 7, 2007</span></h2>
<ul>
<li>Added site.</li>
</ul>
<h2>1.0.1 -- <span style="font-weight: normal;">November 6, 2007</span></h2>
<ul>
<li>Updated for Openfire 3.4.1.</li>
</ul>
<h2>1.0.0 -- <span style="font-weight: normal;">July 14, 2007</span></h2>
<ul>
<li>Initial release.</li>
</ul>
</div>
</div>
</body>
</html>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<!-- Main plugin class -->
<class>com.reucon.openfire.plugins.userstatus.UserStatusPlugin</class>
<!-- Plugin meta-data -->
<name>User Status Plugin</name>
<description>Openfire plugin to save the user status to the database.</description>
<author>Stefan Reuter</author>
<version>1.2.0</version>
<date>12/13/2017</date>
<minServerVersion>4.0.0</minServerVersion>
<databaseKey>user-status</databaseKey>
<databaseVersion>0</databaseVersion>
<licenseType>gpl</licenseType>
<!-- Admin console meta-data -->
<adminconsole>
<tab id="tab-server">
<sidebar id="sidebar-server-settings">
<item id="user-status-settings" name="${user-status.settings.title}"
url="user-status-settings.jsp"
description="${user-status.settings.description}" />
</sidebar>
</tab>
</adminconsole>
</plugin>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>plugins</artifactId>
<groupId>org.igniterealtime.openfire</groupId>
<version>4.3.0-SNAPSHOT</version>
</parent>
<groupId>org.igniterealtime.openfire.plugins</groupId>
<artifactId>userstatus</artifactId>
<version>1.2.0</version>
<name>UserStatus Plugin</name>
<description>Openfire plugin to save the user status to the database</description>
<developers>
<developer>
<name>Stefan Reuter</name>
</developer>
<developer>
<name>Anno van Vliet</name>
</developer>
</developers>
<build>
<sourceDirectory>src/java</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<!-- Compiles the Openfire Admin Console JSP pages. -->
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jspc-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>UserStatus Plugin Readme</title>
<style type="text/css">
/* global font and body settings */
body {
font-size: 100%;
background-color: #d3d6d9;
padding: 0;
margin: 0 0 30px 0;
}
body, td, th {
font-family: arial, helvetica, sans-serif;
font-size: 10pt;
}
pre, tt, code {
font-family: courier new, monospace;
font-size: 9pt;
}
#pageContainer {
display: block;
position: relative;
clear: both;
background-color: #fff;
border: 1px solid #999;
padding: 40px;
margin: 30px;
}
#pageHeader {
display: block;
position: relative;
height: 80px;
background-color: #e7eaee;
border: 1px solid #cccccc;
border-bottom: none;
margin: 10px 0 0 0;
}
#pageBody {
margin: 0 18px 0 20px;
}
/* anchors */
a:link {
color: #11568c;
}
a:visited {
color: #571c8d;
}
a:hover {
color: #7a1d42;
text-decoration: underline;
}
a:active {
color: #7a1d42;
}
/* page header elements (logo and navigation) */
.navigation {
display: block;
position: relative;
height: 20px;
background-color: #335588;
border: 1px solid #cccccc;
border-top: none;
color: #ffffff;
font-size: 11px;
line-height: 18px;
padding: 0 0 0 0;
margin: 0 0 25px 0;
overflow: hidden;
}
.navigation a {
margin: 0 20px 0 20px;
}
.navigation a:link {
color: #ffffff;
}
.navigation a:visited {
color: #ffffff;
}
.navigation a:hover {
color: #ffffff;
}
.navigation a:active {
color: #ffffff;
}
/* headings */
h1 {
display: block;
position: relative;
font-size: 1.7em;
font-weight: bold;
color: #670e15;
padding: 0;
margin: 30px 0 0 20px;
}
h2 {
font-size: 1.3em;
font-weight: bold;
margin: 40px 0 6px 0;
padding: 0;
color: #335588;
}
h3 {
font-size: 1.0em;
font-weight: bold;
margin: 25px 0 3px 0;
padding: 0;
color: #334466;
}
/* general elements */
p {
margin: 0 0 15px 0;
}
ul {
margin: 5px 0 15px 35px;
}
li {
padding-bottom: 4px;
}
tt {
font-family: courier new, monospace;
font-weight: bold;
color: #060;
}
hr {
display: block;
height: 1px;
background-color: #999999;
border: none;
margin: 40px 0 20px 0;
}
.footer {
font-size: 8pt;
color: #666;
text-align: center;
margin-top: 2em;
padding-top: 0.5em;
border-top: 1px #CCC solid;
}
</style>
</head>
<body>
<div id="pageContainer">
<div id="pageHeader">
<h1>UserStatus Plugin Readme</h1>
</div>
<div id="pageBody">
<h2>Overview</h2>
<p>
Openfire plugin to save the user status to the database.
</p>
<p>
This plugin automatically saves the last status
(presence, IP address, logon and logoff time) per user and resource to <tt>userStatus</tt>
table in the Openfire database.
</p>
<p>
Optionally you can archive user status entries (IP address, logon and logoff time)
for a specified time. History entries are stored in the <tt>userStatusHistory</tt> table.
The settings for history archiving can be configured on the "User Status Settings" page
that you'll find on the "Server" tab of the Openfire Admin Console.
</p>
<h2>Limitations</h2>
<p>
Of the databases supported by Openfire, this plugin does not
support Oracle. This is not due to any technical reason, just nobody has
submitted the needed sql script to initialize the userStatus plugin database
schema for Oracle.
</p>
<h2>Database Schema</h2>
<p>
The <tt>userStatus</tt> table contains the last status per user and resource:
</p>
<pre>
CREATE TABLE userStatus (
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
online TINYINT NOT NULL,
presence CHAR(15),
lastIpAddress CHAR(15) NOT NULL,
lastLoginDate CHAR(15) NOT NULL,
lastLogoffDate CHAR(15),
PRIMARY KEY pk_userStatus (username, resource)
);
</pre>
<p>
The <tt>userStatusHistory</tt> table contains the archived status entries if enabled:
</p>
<pre>
CREATE TABLE userStatusHistory (
historyID BIGINT NOT NULL,
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
lastIpAddress CHAR(15) NOT NULL,
lastLoginDate CHAR(15) NOT NULL,
lastLogoffDate CHAR(15) NOT NULL,
PRIMARY KEY pk_userStatusHistory (historyID)
);
</pre>
</div>
<div class="footer">
Copyright &copy; 2007,2017 Stefan Reuter
</div>
</div>
</body>
</html>
CREATE TABLE userStatusHistory (
historyID BIGINT NOT NULL,
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
lastIpAddress CHAR(15) NOT NULL,
lastLoginDate CHAR(15) NOT NULL,
lastLogoffDate CHAR(15) NOT NULL,
PRIMARY KEY(historyID)
);
CREATE TABLE userStatus (
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
online INT NOT NULL,
presence CHAR(15),
lastIpAddress CHAR(15) NOT NULL,
lastLoginDate CHAR(15) NOT NULL,
lastLogoffDate CHAR(15),
PRIMARY KEY(username, resource)
);
INSERT INTO ofVersion (name, version) VALUES ('user-status', 0);
CREATE TABLE userStatus (
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
online INTEGER NOT NULL,
presence VARCHAR(15),
lastIpAddress VARCHAR(15) NOT NULL,
lastLoginDate VARCHAR(15) NOT NULL,
lastLogoffDate VARCHAR(15),
PRIMARY KEY (username, resource)
);
CREATE TABLE userStatusHistory (
historyID BIGINT NOT NULL,
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
lastIpAddress VARCHAR(15) NOT NULL,
lastLoginDate VARCHAR(15) NOT NULL,
lastLogoffDate VARCHAR(15) NOT NULL,
PRIMARY KEY (historyID)
);
INSERT INTO ofVersion (name, version) VALUES ('user-status', 0);
CREATE TABLE userStatus (
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
online TINYINT NOT NULL,
presence CHAR(15),
lastIpAddress CHAR(15) NOT NULL,
lastLoginDate CHAR(15) NOT NULL,
lastLogoffDate CHAR(15),
PRIMARY KEY pk_userStatus (username, resource)
);
CREATE TABLE userStatusHistory (
historyID BIGINT NOT NULL,
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
lastIpAddress CHAR(15) NOT NULL,
lastLoginDate CHAR(15) NOT NULL,
lastLogoffDate CHAR(15) NOT NULL,
PRIMARY KEY pk_userStatusHistory (historyID)
);
INSERT INTO ofVersion (name, version) VALUES ('user-status', 0);
CREATE TABLE userStatus (
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
online INTEGER NOT NULL,
presence CHAR(15),
lastIpAddress CHAR(15) NOT NULL,
lastLoginDate CHAR(15) NOT NULL,
lastLogoffDate CHAR(15),
constraint pk_userStatus PRIMARY KEY (username, resource)
);
CREATE TABLE userStatusHistory (
historyID BIGINT NOT NULL,
username VARCHAR(64) NOT NULL,
resource VARCHAR(64) NOT NULL,
lastIpAddress CHAR(15) NOT NULL,
lastLoginDate CHAR(15) NOT NULL,
lastLogoffDate CHAR(15) NOT NULL,
constraint pk_userStatusHistory PRIMARY KEY (historyID)
);
INSERT INTO ofVersion (name, version) VALUES ('user-status', 0);
CREATE TABLE userStatus (
username NVARCHAR(64) NOT NULL,
resource NVARCHAR(64) NOT NULL,
online TINYINT NOT NULL,
presence NVARCHAR(15),
lastIpAddress NVARCHAR(15) NOT NULL,
lastLoginDate NVARCHAR(15) NOT NULL,
lastLogoffDate NVARCHAR(15),
CONSTRAINT userStatus_pk PRIMARY KEY (username, resource)
);
CREATE TABLE userStatusHistory (
historyID BIGINT NOT NULL,
username NVARCHAR(64) NOT NULL,
resource NVARCHAR(64) NOT NULL,
lastIpAddress NVARCHAR(15) NOT NULL,
lastLoginDate NVARCHAR(15) NOT NULL,
lastLogoffDate NVARCHAR(15) NOT NULL,
CONSTRAINT userStatusHistory_pk PRIMARY KEY (historyID)
);
INSERT INTO ofVersion (name, version) VALUES ('user-status', 0);
user-status.title = User Status
user-status.settings.title = User Status Settings
user-status.settings.description = Click to edit User status settings
user-status.settings.intro = This plugin automatically saves the last status \
(presence, IP address, logon and logoff time) per user and resource to the database.<br/> \
Optionally you can archive user status entries (IP address, logon and logoff time) \
for a specified time.
user-status.settings.update.success=User status settings updated successfully.
user-status.settings.basic.title=Basic
user-status.settings.basic.history.disabled=Do not archive user status.
user-status.settings.basic.history.forever=Archive user status forever.
user-status.settings.basic.historyDays=Archive user status for {0} days.
user-status.settings.save=Save Settings
login.title = Admin Console
\ No newline at end of file
package com.reucon.openfire.plugins.userstatus;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jivesoftware.openfire.session.Session;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
import java.net.UnknownHostException;
/**
* Default implementation of the PersistenceManager interface.
*/
public class DefaultPersistenceManager implements PersistenceManager
{
private static final Logger Log = LoggerFactory.getLogger(DefaultPersistenceManager.class);
private static final int SEQ_ID = 510;
private static final String ADD_USER_STATUS =
"INSERT INTO userStatus (username, resource, online, lastIpAddress, lastLoginDate) " +
"VALUES (?, ?, 1, ?, ?)";
private static final String UPDATE_USER_STATUS =
"UPDATE userStatus SET online = 1, lastIpAddress = ?, lastLoginDate = ? " +
"WHERE username = ? AND resource = ?";
private static final String SET_PRESENCE =
"UPDATE userStatus SET presence = ? WHERE username = ? AND resource = ?";
private static final String SET_OFFLINE =
"UPDATE userStatus SET online = 0, lastLogoffDate = ? WHERE username = ? AND resource = ?";
private static final String SET_ALL_OFFLINE =
"UPDATE userStatus SET online = 0 WHERE online = 1";
private static final String ADD_USER_STATUS_HISTORY =
"INSERT INTO userStatusHistory (historyID, username, resource, lastIpAddress," +
"lastLoginDate, lastLogoffDate) " +
"SELECT ?, username, resource, lastipaddress, lastlogindate, lastlogoffdate " +
"from userStatus WHERE username = ? and resource = ?";
private static final String DELETE_OLD_USER_STATUS_HISTORY =
"DELETE from userStatusHistory WHERE lastLogoffDate < ?";
/**
* Number of days to keep history entries.<p>
* 0 for no history entries, -1 for unlimited.
*/
private int historyDays = -1;
public void setHistoryDays(int historyDays)
{
this.historyDays = historyDays;
}
public void setAllOffline()
{
Connection con = null;
PreparedStatement pstmt = null;
try
{
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(SET_ALL_OFFLINE);
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to clean up user status", e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
public void setOnline(Session session)
{
Connection con = null;
PreparedStatement pstmt = null;
int rowsUpdated = 0;
try
{
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(UPDATE_USER_STATUS);
pstmt.setString(1, getHostAddress(session));
pstmt.setString(2, StringUtils.dateToMillis(session.getCreationDate()));
pstmt.setString(3, session.getAddress().getNode());
pstmt.setString(4, session.getAddress().getResource());
rowsUpdated = pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to update user status for " + session.getAddress(), e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
// if update did not affect any rows insert a new row
if (rowsUpdated == 0)
{
try
{
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(ADD_USER_STATUS);
pstmt.setString(1, session.getAddress().getNode());
pstmt.setString(2, session.getAddress().getResource());
pstmt.setString(3, getHostAddress(session));
pstmt.setString(4, StringUtils.dateToMillis(session.getCreationDate()));
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to insert user status for " + session.getAddress(), e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
}
public void setOffline(Session session, Date logoffDate)
{
Connection con = null;
PreparedStatement pstmt = null;
try
{
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(SET_OFFLINE);
pstmt.setString(1, StringUtils.dateToMillis(logoffDate));
pstmt.setString(2, session.getAddress().getNode());
pstmt.setString(3, session.getAddress().getResource());
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to update user status for " + session.getAddress(), e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
// write history entry
if (historyDays != 0)
{
try
{
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(ADD_USER_STATUS_HISTORY);
pstmt.setLong(1, SequenceManager.nextID(SEQ_ID));
pstmt.setString(2, session.getAddress().getNode());
pstmt.setString(3, session.getAddress().getResource());
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to add user status history for " + session.getAddress(), e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
deleteOldHistoryEntries();
}
public void setPresence(Session session, String presenceText)
{
Connection con = null;
PreparedStatement pstmt = null;
try
{
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(SET_PRESENCE);
pstmt.setString(1, presenceText);
pstmt.setString(2, session.getAddress().getNode());
pstmt.setString(3, session.getAddress().getResource());
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to update presence for " + session.getAddress(), e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
public void deleteOldHistoryEntries()
{
Connection con = null;
PreparedStatement pstmt = null;
if (historyDays > 0)
{
final Date deleteBefore;
deleteBefore = new Date(System.currentTimeMillis() - historyDays * 24L * 60L * 60L * 1000L);
try
{
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(DELETE_OLD_USER_STATUS_HISTORY);
pstmt.setString(1, StringUtils.dateToMillis(deleteBefore));
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to delete old user status history", e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
}
private String getHostAddress(Session session)
{
try
{
return session.getHostAddress();
}
catch (UnknownHostException e)
{
return "";
}
}
}
package com.reucon.openfire.plugins.userstatus;
import org.jivesoftware.openfire.session.Session;
import java.util.Date;
/**
*
*/
public interface PersistenceManager
{
void setHistoryDays(int historyDays);
void setAllOffline();
void setOnline(Session session);
void setOffline(Session session, Date logoffDate);
void setPresence(Session session, String presenceText);
void deleteOldHistoryEntries();
}
package com.reucon.openfire.plugins.userstatus;
import org.jivesoftware.database.DbConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.openfire.session.Session;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.util.Date;
/**
* Implementation of the PersistenceManager interface for phpBB3 integration.
*/
public class PhpBB3PersistenceManager implements PersistenceManager
{
private static final Logger Log = LoggerFactory.getLogger(PhpBB3PersistenceManager.class);
private static final String UPDATE_USER_STATUS =
"UPDATE users SET user_jabber_online = 1 WHERE user_jid = ?";
private static final String SET_PRESENCE =
"UPDATE users SET user_jabber_presence = ? WHERE user_jid = ?";
private static final String SET_OFFLINE =
"UPDATE users SET user_jabber_online = 0 WHERE user_jid = ?";
private static final String SET_ALL_OFFLINE =
"UPDATE users SET user_jabber_online = 0 WHERE user_jabber_online = 1";
private String connectionString = null;
public PhpBB3PersistenceManager()
{
connectionString = JiveGlobals.getProperty("jdbcProvider.connectionString");
}
public void setHistoryDays(int historyDays)
{
// history not supported
}
public void setAllOffline()
{
Connection con = null;
PreparedStatement pstmt = null;
try
{
con = getConnection();
pstmt = con.prepareStatement(SET_ALL_OFFLINE);
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to clean up user status", e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
public void setOnline(Session session)
{
Connection con = null;
PreparedStatement pstmt = null;
try
{
con = getConnection();
pstmt = con.prepareStatement(UPDATE_USER_STATUS);
pstmt.setString(1, session.getAddress().getNode());
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to update user status for " + session.getAddress(), e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
public void setOffline(Session session, Date logoffDate)
{
Connection con = null;
PreparedStatement pstmt = null;
try
{
con = getConnection();
pstmt = con.prepareStatement(SET_OFFLINE);
pstmt.setString(1, session.getAddress().getNode());
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to update user status for " + session.getAddress(), e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
public void setPresence(Session session, String presenceText)
{
Connection con = null;
PreparedStatement pstmt = null;
try
{
con = getConnection();
pstmt = con.prepareStatement(SET_PRESENCE);
pstmt.setString(1, presenceText);
pstmt.setString(2, session.getAddress().getNode());
pstmt.executeUpdate();
}
catch (SQLException e)
{
Log.error("Unable to update presence for " + session.getAddress(), e);
}
finally
{
DbConnectionManager.closeConnection(pstmt, con);
}
}
private Connection getConnection() throws SQLException
{
if (connectionString == null)
{
return DbConnectionManager.getConnection();
}
else
{
return DriverManager.getConnection(connectionString);
}
}
public void deleteOldHistoryEntries()
{
// history not supported
}
}
\ No newline at end of file
package com.reucon.openfire.plugins.userstatus;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.event.SessionEventDispatcher;
import org.jivesoftware.openfire.event.SessionEventListener;
import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.user.PresenceEventDispatcher;
import org.jivesoftware.openfire.user.PresenceEventListener;
import org.jivesoftware.util.*;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Date;
import java.util.Map;
import java.util.Collection;
import java.util.ArrayList;
/**
* UserStatus plugin for Openfire.
*/
public class UserStatusPlugin implements Plugin, PropertyEventListener, SessionEventListener, PresenceEventListener, PersistenceManager
{
public static final String HISTORY_DAYS_PROPERTY = "user-status.historyDays";
public static final int DEFAULT_HISTORY_DAYS = -1;
private Collection<PersistenceManager> persistenceManagers;
public void initializePlugin(PluginManager manager, File pluginDirectory)
{
int historyDays = JiveGlobals.getIntProperty(HISTORY_DAYS_PROPERTY, DEFAULT_HISTORY_DAYS);
PropertyEventDispatcher.addListener(this);
persistenceManagers = new ArrayList<PersistenceManager>();
persistenceManagers.add(new DefaultPersistenceManager());
try
{
Class.forName("com.reucon.openfire.phpbb3.PhpBB3AuthProvider");
persistenceManagers.add(new PhpBB3PersistenceManager());
}
catch (ClassNotFoundException e)
{
// ignore
}
setAllOffline();
setHistoryDays(historyDays);
for (ClientSession session : SessionManager.getInstance().getSessions())
{
sessionCreated(session);
}
SessionEventDispatcher.addListener(this);
PresenceEventDispatcher.addListener(this);
}
public void destroyPlugin()
{
PresenceEventDispatcher.removeListener(this);
SessionEventDispatcher.removeListener(this);
}
public void sessionCreated(Session session)
{
if (!XMPPServer.getInstance().getUserManager().isRegisteredUser(session.getAddress()))
{
return;
}
setOnline(session);
}
public void sessionDestroyed(Session session)
{
if (!XMPPServer.getInstance().getUserManager().isRegisteredUser(session.getAddress()))
{
return;
}
setOffline(session, new Date());
}
public void anonymousSessionCreated(Session session)
{
// we are not interested in anonymous sessions
}
public void anonymousSessionDestroyed(Session session)
{
// we are not interested in anonymous sessions
}
public void resourceBound(Session session)
{
// not interested
}
public void availableSession(ClientSession session, Presence presence)
{
updatePresence(session, presence);
}
public void unavailableSession(ClientSession session, Presence presence)
{
updatePresence(session, presence);
}
public void presencePriorityChanged(ClientSession session, Presence presence)
{
// we are not interested in priority changes
}
public void presenceChanged(ClientSession session, Presence presence)
{
updatePresence(session, presence);
}
public void subscribedToPresence(JID subscriberJID, JID authorizerJID)
{
// we are not interested in subscription updates
}
public void unsubscribedToPresence(JID unsubscriberJID, JID recipientJID)
{
// we are not interested in subscription updates
}
public void propertySet(String property, Map<String, Object> params)
{
if (HISTORY_DAYS_PROPERTY.equals(property))
{
final Object value = params.get("value");
if (value != null)
{
try
{
setHistoryDays(Integer.valueOf(value.toString()));
}
catch (NumberFormatException e)
{
setHistoryDays(DEFAULT_HISTORY_DAYS);
}
deleteOldHistoryEntries();
}
}
}
public void propertyDeleted(String property, Map<String, Object> params)
{
if (HISTORY_DAYS_PROPERTY.equals(property))
{
setHistoryDays(DEFAULT_HISTORY_DAYS);
deleteOldHistoryEntries();
}
}
public void xmlPropertySet(String property, Map<String, Object> params)
{
// we don't use xml properties
}
public void xmlPropertyDeleted(String property, Map<String, Object> params)
{
// we don't use xml properties
}
private void updatePresence(ClientSession session, Presence presence)
{
Connection con = null;
PreparedStatement pstmt = null;
final String presenceText;
if (!XMPPServer.getInstance().getUserManager().isRegisteredUser(session.getAddress()))
{
return;
}
if (Presence.Type.unavailable.equals(presence.getType()))
{
presenceText = presence.getType().toString();
}
else if (presence.getShow() != null)
{
presenceText = presence.getShow().toString();
}
else if (presence.isAvailable())
{
presenceText = "available";
}
else
{
return;
}
setPresence(session, presenceText);
}
// implementation of PersistenceManager
public void setHistoryDays(int historyDays)
{
for (PersistenceManager pm : persistenceManagers)
{
pm.setHistoryDays(historyDays);
}
}
public void setAllOffline()
{
for (PersistenceManager pm : persistenceManagers)
{
pm.setAllOffline();
}
}
public void setOnline(Session session)
{
for (PersistenceManager pm : persistenceManagers)
{
pm.setOnline(session);
}
}
public void setOffline(Session session, Date logoffDate)
{
for (PersistenceManager pm : persistenceManagers)
{
pm.setOffline(session, logoffDate);
}
}
public void setPresence(Session session, String presenceText)
{
for (PersistenceManager pm : persistenceManagers)
{
pm.setPresence(session, presenceText);
}
}
public void deleteOldHistoryEntries()
{
for (PersistenceManager pm : persistenceManagers)
{
pm.deleteOldHistoryEntries();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
</web-app>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
<%@ page import="com.reucon.openfire.plugins.userstatus.UserStatusPlugin" %>
<%@ page import="org.jivesoftware.util.ParamUtils" %>
<%@ page import="org.jivesoftware.util.JiveGlobals" %>
<% // Get parameters
boolean update = request.getParameter("update") != null;
boolean updateSuccess = false;
Integer historyDays = ParamUtils.getIntParameter(request, "historyDays", UserStatusPlugin.DEFAULT_HISTORY_DAYS);
Integer historyOption = ParamUtils.getIntParameter(request, "historyOption", 1);
if (historyOption == -1 || historyOption == 0)
{
historyDays = historyOption;
}
// Perform update if requested
if (update)
{
if (historyDays >= -1)
{
JiveGlobals.setProperty(UserStatusPlugin.HISTORY_DAYS_PROPERTY, historyDays.toString());
updateSuccess = true;
}
}
historyDays = JiveGlobals.getIntProperty(UserStatusPlugin.HISTORY_DAYS_PROPERTY, UserStatusPlugin.DEFAULT_HISTORY_DAYS);
%>
<html>
<head>
<title>
<fmt:message key="user-status.settings.title"/>
</title>
<meta name="pageID" content="user-status-settings"/>
</head>
<body>
<p>
<fmt:message key="user-status.settings.intro"/>
</p>
<% if (updateSuccess)
{ %>
<div id="updateSuccessMessage" class="success">
<fmt:message key="user-status.settings.update.success"/>
</div>
<script type="text/javascript">
setTimeout("Effect.Fade('updateSuccessMessage')", 3000)
</script>
<% } %>
<form action="user-status-settings.jsp" method="post">
<div class="jive-contentBoxHeader">
<fmt:message key="user-status.settings.basic.title"/>
</div>
<div class="jive-contentBox">
<table cellpadding="3" cellspacing="0" border="0">
<tbody>
<tr>
<td width="1%" valign="top" nowrap>
<input type="radio" name="historyOption" value="0" id="rb01" onchange="historyOptionChanged()"
<%= (historyDays == 0 ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb01">
<fmt:message key="user-status.settings.basic.history.disabled"/>
</label>
</td>
</tr>
<tr>
<td width="1%" valign="top" nowrap>
<input type="radio" name="historyOption" value="-1" id="rb02" onchange="historyOptionChanged()"
<%= (historyDays == -1 ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb02">
<fmt:message key="user-status.settings.basic.history.forever"/>
</label>
</td>
</tr>
<tr>
<td width="1%" valign="top" nowrap>
<input type="radio" name="historyOption" value="1" id="rb03" onchange="historyOptionChanged()"
<%= (historyDays > 0 ? "checked" : "") %>>
</td>
<td width="99%">
<fmt:message key="user-status.settings.basic.historyDays">
<fmt:param><input type="text" name="historyDays" size="3" maxlength="6" id="historyDays"
value="<%= historyDays > 0 ? historyDays : "" %>"
<%= historyDays > 0 ? "" : "disabled=\"disabled\"" %>/>
</fmt:param>
</fmt:message>
</td>
</tr>
</tbody>
</table>
</div>
<input type="submit" name="update" value="<fmt:message key="user-status.settings.save"/>"/>
</form>
<script type="text/javascript">
function historyOptionChanged()
{
if ($('rb01').checked || $('rb02').checked)
{
$('historyDays').value = '';
$('historyDays').disabled = true;
}
else
{
$('historyDays').disabled = false;
}
}
</script>
</body>
</html>
\ No newline at end of file
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