This commit is contained in:
parent
b9357194a3
commit
ce8f97b55f
|
@ -1,192 +0,0 @@
|
||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>User Import/Export Plugin Changelog</title>
|
|
||||||
<style type="text/css">
|
|
||||||
/* global font and body settings */
|
|
||||||
body {
|
|
||||||
font-size: 100%;
|
|
||||||
background-color: #d3d6d9;
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px 0px 30px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body,td,th {
|
|
||||||
font-family: arial, helvetica, sans-serif;
|
|
||||||
font-size: 10pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre,tt,code {
|
|
||||||
font-family: courier new, monospaced;
|
|
||||||
font-size: 9pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pageContainer {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
clear: both;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid #999;
|
|
||||||
padding: 40px;
|
|
||||||
margin: 30px;
|
|
||||||
-moz-border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pageHeader {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
height: 80px;
|
|
||||||
background-color: #e7eaee;
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
border-bottom: none;
|
|
||||||
-moz-border-radius: 5px 5px 0px 0px;
|
|
||||||
margin: 10px 0px 0px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pageBody {
|
|
||||||
margin: 0px 18px 0px 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: 0px 0px 0px 0px;
|
|
||||||
margin: 0px 0px 25px 0px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation a {
|
|
||||||
margin: 0px 20px 0px 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: 0px;
|
|
||||||
margin: 30px 0px 0px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.3em;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 40px 0px 6px 0px;
|
|
||||||
padding: 0px;
|
|
||||||
color: #335588;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.0em;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 25px 0px 3px 0px;
|
|
||||||
padding: 0px;
|
|
||||||
color: #334466;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* general elements */
|
|
||||||
p {
|
|
||||||
margin: 0px 0px 15px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
margin: 5px 0px 15px 35px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
padding-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
tt {
|
|
||||||
font-family: courier new;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #060;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
display: block;
|
|
||||||
height: 1px;
|
|
||||||
background-color: #999999;
|
|
||||||
border: none;
|
|
||||||
margin: 40px 0px 20px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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>User Import/Export XEP-0227 compliant Plugin Changelog</h1>
|
|
||||||
</div>
|
|
||||||
<div id="pageBody">
|
|
||||||
<br/>
|
|
||||||
<p><b>Note:</b> Openfire plugin improved to export to XEP-227
|
|
||||||
format. There is also old code to import users, but using a custom Openfire
|
|
||||||
format. If you are interested you can improve it to also support XEP-227
|
|
||||||
import.</p>
|
|
||||||
|
|
||||||
<h2>0.0.1 -- <span style="font-weight: normal;">August 3,
|
|
||||||
2009</span></h2>
|
|
||||||
<ul>
|
|
||||||
<li>Initial release.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,79 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
|
|
||||||
<xs:element name="Openfire">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="User" maxOccurs="unbounded" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="User">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:all>
|
|
||||||
<xs:element ref="Username"/>
|
|
||||||
<xs:element ref="Password"/>
|
|
||||||
<xs:element ref="Email" />
|
|
||||||
<xs:element ref="Name" />
|
|
||||||
<xs:element ref="CreationDate" />
|
|
||||||
<xs:element ref="ModifiedDate" />
|
|
||||||
<xs:element ref="Roster" />
|
|
||||||
</xs:all>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="Username" type="xs:string" />
|
|
||||||
<xs:element name="Password" type="xs:string" />
|
|
||||||
<xs:element name="Email" type="xs:string" />
|
|
||||||
<xs:element name="Name" type="xs:string" />
|
|
||||||
<xs:element name="CreationDate" type="jive-date" />
|
|
||||||
<xs:element name="ModifiedDate" type="jive-date" />
|
|
||||||
<xs:element name="Roster">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="Item" minOccurs="0" maxOccurs="unbounded" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="Item">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref="Group" maxOccurs="unbounded" />
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute ref="jid" use="required" />
|
|
||||||
<xs:attribute name="askstatus" use="required" />
|
|
||||||
<xs:attribute name="recvstatus" use="required" />
|
|
||||||
<xs:attribute name="substatus" use="required" />
|
|
||||||
<xs:attribute name="name" />
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="Group" type="xs:string" />
|
|
||||||
<xs:attribute name="jid" type="xs:string" />
|
|
||||||
<xs:attribute name="name" type="xs:string" />
|
|
||||||
<xs:attribute name="askstatus">
|
|
||||||
<xs:simpleType>
|
|
||||||
<xs:restriction base="xs:integer">
|
|
||||||
<xs:minInclusive value="-1" />
|
|
||||||
<xs:maxInclusive value="3" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
</xs:attribute>
|
|
||||||
<xs:attribute name="recvstatus">
|
|
||||||
<xs:simpleType>
|
|
||||||
<xs:restriction base="xs:integer">
|
|
||||||
<xs:minInclusive value="-1" />
|
|
||||||
<xs:maxInclusive value="3" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
</xs:attribute>
|
|
||||||
<xs:attribute name="substatus">
|
|
||||||
<xs:simpleType>
|
|
||||||
<xs:restriction base="xs:integer">
|
|
||||||
<xs:minInclusive value="-1" />
|
|
||||||
<xs:maxInclusive value="3" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
</xs:attribute>
|
|
||||||
<xs:simpleType name="jive-date">
|
|
||||||
<xs:restriction base="xs:string"></xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
</xs:schema>
|
|
|
@ -1,47 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
|
|
||||||
<xs:schema
|
|
||||||
xmlns:xs='http://www.w3.org/2001/XMLSchema'
|
|
||||||
targetNamespace='http://www.xmpp.org/extensions/xep-0227.html#ns'
|
|
||||||
xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'
|
|
||||||
elementFormDefault='qualified'>
|
|
||||||
|
|
||||||
<xs:element name='server-data'>
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref='host' maxOccurs='unbounded'/>
|
|
||||||
<xs:any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name='host'>
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref='user' maxOccurs='unbounded'/>
|
|
||||||
<xs:any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name='jid' type='xs:string' use='required'/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name='user'>
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element ref='offline-messages' minOccurs='0' maxOccurs='1'/>
|
|
||||||
<xs:any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name='name' type='xs:string' use='required'/>
|
|
||||||
<xs:attribute name='password' type='xs:string' use='optional'/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
<xs:element name='offline-messages'>
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
</xs:schema>
|
|
Binary file not shown.
|
@ -1,18 +0,0 @@
|
||||||
|
|
||||||
Copy in this directory the following files:
|
|
||||||
|
|
||||||
commons-fileupload-1.0.jar
|
|
||||||
dom4j-1.6.1.jar
|
|
||||||
isorelax.jar
|
|
||||||
msv.jar
|
|
||||||
relaxngDatatype.jar
|
|
||||||
xsdlib.jar
|
|
||||||
|
|
||||||
You can get those files from the original Openfire plugin: userImportExport.jar
|
|
||||||
|
|
||||||
Note: openfire.jar file in this folder must be used if you want to export the
|
|
||||||
private stored info also you will need to comment out lines 332 up to 335 in
|
|
||||||
ExporterXEP227.java class and finally recompile it.
|
|
||||||
Have fun !
|
|
||||||
|
|
||||||
---
|
|
Binary file not shown.
Before Width: | Height: | Size: 977 B |
Binary file not shown.
Before Width: | Height: | Size: 600 B |
|
@ -1,22 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<class>net.processone.plugin.openfire.ExporterXEP227</class>
|
|
||||||
|
|
||||||
<name>User Import Export XEP-0227</name>
|
|
||||||
<description>Enables import and export of user data</description>
|
|
||||||
<author>Vidal Santiago Martinez (original plugin: Ryan Graham)</author>
|
|
||||||
<version>0.0.1</version>
|
|
||||||
<date>03/08/2009</date>
|
|
||||||
<minServerVersion>3.5.0</minServerVersion>
|
|
||||||
|
|
||||||
<adminconsole>
|
|
||||||
<tab id="tab-users">
|
|
||||||
<sidebar id="user-import-export" name="Import & Export XEP-0227 compliant ">
|
|
||||||
<item id="import-export-selection" name="User Import & Export XEP-0227 compliant"
|
|
||||||
url="import-export-selection.jsp"
|
|
||||||
description="Allows the importing and exporting of Openfire user data in a XEP-0227 format." />
|
|
||||||
</sidebar>
|
|
||||||
</tab>
|
|
||||||
</adminconsole>
|
|
||||||
</plugin>
|
|
|
@ -1,262 +0,0 @@
|
||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>User Import/Export XEP-0227 compliant Plugin Readme</title>
|
|
||||||
<style type="text/css">
|
|
||||||
/* global font and body settings */
|
|
||||||
body {
|
|
||||||
font-size : 100%;
|
|
||||||
background-color : #d3d6d9;
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px 0px 30px 0px;
|
|
||||||
}
|
|
||||||
body, td, th {
|
|
||||||
font-family : arial, helvetica, sans-serif;
|
|
||||||
font-size : 10pt;
|
|
||||||
}
|
|
||||||
pre, tt, code {
|
|
||||||
font-family : courier new, monospaced;
|
|
||||||
font-size : 9pt;
|
|
||||||
}
|
|
||||||
#pageContainer {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
clear: both;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid #999;
|
|
||||||
padding: 40px;
|
|
||||||
margin: 30px;
|
|
||||||
-moz-border-radius: 6px;
|
|
||||||
}
|
|
||||||
#pageHeader {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
height: 80px;
|
|
||||||
background-color: #e7eaee;
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
border-bottom: none;
|
|
||||||
-moz-border-radius: 5px 5px 0px 0px;
|
|
||||||
margin: 10px 0px 0px 0px;
|
|
||||||
}
|
|
||||||
#pageBody {
|
|
||||||
margin: 0px 18px 0px 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: 0px 0px 0px 0px;
|
|
||||||
margin: 0px 0px 25px 0px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.navigation a {
|
|
||||||
margin: 0px 20px 0px 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: 0px;
|
|
||||||
margin: 30px 0px 0px 20px;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
font-size : 1.3em;
|
|
||||||
font-weight : bold;
|
|
||||||
margin: 40px 0px 6px 0px;
|
|
||||||
padding: 0px;
|
|
||||||
color: #335588;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size : 1.0em;
|
|
||||||
font-weight : bold;
|
|
||||||
margin: 25px 0px 3px 0px;
|
|
||||||
padding: 0px;
|
|
||||||
color: #334466;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* general elements */
|
|
||||||
p {
|
|
||||||
margin: 0px 0px 15px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
margin: 5px 0px 15px 35px;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
padding-bottom : 4px;
|
|
||||||
}
|
|
||||||
tt {
|
|
||||||
font-family : courier new;
|
|
||||||
font-weight : bold;
|
|
||||||
color : #060;
|
|
||||||
}
|
|
||||||
hr {
|
|
||||||
display: block;
|
|
||||||
height: 1px;
|
|
||||||
background-color: #999999;
|
|
||||||
border: none;
|
|
||||||
margin: 40px 0px 20px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
font-size : 8pt;
|
|
||||||
color : #666;
|
|
||||||
text-align : center;
|
|
||||||
margin-top : 2em;
|
|
||||||
padding-top : 0.5em;
|
|
||||||
border-top : 1px #CCC solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.datatable TH {
|
|
||||||
color : #fff;
|
|
||||||
background-color : #2A448C;
|
|
||||||
text-align : left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.datatable TD {
|
|
||||||
background-color : #FAF6EF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.datatable .name {
|
|
||||||
background-color : #DCE2F5;
|
|
||||||
text-align : center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xmltable TD {
|
|
||||||
background-color : #EFEFEF;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div id="pageContainer">
|
|
||||||
|
|
||||||
<div id="pageHeader">
|
|
||||||
<h1>User Import/Export XEP-0227 compliant Plugin Readme</h1>
|
|
||||||
</div>
|
|
||||||
<div id="pageBody">
|
|
||||||
|
|
||||||
<h2>Overview</h2>
|
|
||||||
<p>The user import/export plugin provides a way to import and export Openfire user data via
|
|
||||||
the Admin Console. This plugin use for its migration the XEP-0227 standard to be able to migrate its
|
|
||||||
list of users from other Jabber/XMPP compliant based systems.</p>
|
|
||||||
|
|
||||||
<p>This plugin is based in the original plugin developed by Ryan Graham.
|
|
||||||
It was modified by Vidal Santiago Martinez (from <a href="http://www.process-one.net/">ProcessOne</a>)
|
|
||||||
to export to a XML file in the XEP-0227 format.
|
|
||||||
If you are migrating to ejabberd, check additional details in:
|
|
||||||
<a href="https://support.process-one.net/doc/display/MESSENGER/ejabberd+migration+kit">ejabberd migration kit</a>.
|
|
||||||
The existing feature to import XML file was not modified, so it is not capable of importing XEP-0227 files.</p>
|
|
||||||
|
|
||||||
<h2>Installation</h2>
|
|
||||||
<p>Copy the OpenfireExporter.jar into the plugins directory of your Openfire installation.
|
|
||||||
The plugin will then be automatically deployed. To upgrade to a new version, copy the new
|
|
||||||
OpenfireExporter.jar file over the existing file.</p>
|
|
||||||
|
|
||||||
<h2>Configuration</h2>
|
|
||||||
<p>Nothing to do</p>
|
|
||||||
|
|
||||||
<h2>Using the Plugin</h2>
|
|
||||||
<p>The plugin is accessed via the "User Import & Export XEP-0227 compliant" sidebar item located under the
|
|
||||||
"Users/Groups" tab in the Admin Console. Note: if you are using a read-only user store such as LDAP
|
|
||||||
or POP3 this plugin will still work with two caveats:
|
|
||||||
<ol>
|
|
||||||
<li>When exporting, the username will be placed in the password element.</li>
|
|
||||||
<li>When importing, no new users will be created but if the user exists in the user store their roster will be loaded.</li>
|
|
||||||
<li><strong>Importing</strong> - Select the "Import User Data" option from the user import/export selection
|
|
||||||
page. On the import page, use the "Browse" button to locate the file that contains the user
|
|
||||||
information you want to locate and then click on the "Import" button. If the plugin is successful
|
|
||||||
in importing all user data, you will be presented with the message: "All users added successfully".
|
|
||||||
If the plugin was not successful in importing all user data you, will receive a message indicating
|
|
||||||
what might have gone wrong. If during the import process, the plugin detects that you are trying to
|
|
||||||
import a user that already exists in the system, it will not import that user or any roster
|
|
||||||
information, except in the case of using a read-only user store.</li>
|
|
||||||
<li><strong>Exporting</strong> - Select the "Export User Data" option from the user import/export selection
|
|
||||||
page. User data can be exported either to a file or directly to the screen. To export to a file,
|
|
||||||
select the "To File" radio button, enter the name you want your export file to be called in the
|
|
||||||
"Export File Name" and then click on the "Export" button. Note: the plugin will automatically append
|
|
||||||
an ".xml" extension to the file name if it is not already present. To export to the screen, select
|
|
||||||
the "To Screen" radio button and then click on the "Export" button. The user data will be placed in
|
|
||||||
the provided text area.</li>
|
|
||||||
<li><strong>Migration</strong> - To import user data from another instant messaging system using the plugin,
|
|
||||||
the import file must conform to the wildfire-user-schema.xsd schema file (located in the classes
|
|
||||||
directory of the OpenfireExporter.jar). When importing a user data file the plugin will first validate
|
|
||||||
the file against the schema file. If the plugin cannot validate the import file the user data will
|
|
||||||
not be imported. During the import process the plugin gives you the ability to update user roster
|
|
||||||
entries domain names to server name of your Openfire installation. For example, say you have a user
|
|
||||||
whose roster looks like:
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
<h2>Example</h2>
|
|
||||||
<p>
|
|
||||||
<div class="xmltable">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?><br/>
|
|
||||||
<server-data xmlns="http://www.xmpp.org/extensions/xep-0227.html#ns"><br/>
|
|
||||||
<host jid="example.org"><br/>
|
|
||||||
<user name="testuser1" password="testuser1"><br/>
|
|
||||||
<query xmlns="jabber:iq:roster"><br/>
|
|
||||||
<item jid="testuser1@example.org" name="testuser1" subscription="both"><br/>
|
|
||||||
<group/><br/>
|
|
||||||
</item><br/>
|
|
||||||
</query><br/>
|
|
||||||
</user><br/>
|
|
||||||
<user name="santiago" password="santiago"><br/>
|
|
||||||
<query xmlns="jabber:iq:roster"><br/>
|
|
||||||
<item jid="smartinez@example.org" name="santiago" subscription="both"><br/>
|
|
||||||
<group/><br/>
|
|
||||||
</item><br/>
|
|
||||||
</query><br/>
|
|
||||||
<vCard xmlns="vcard-temp"><br/>
|
|
||||||
<FN>Vidal Santiago Martinez</FN><br/>
|
|
||||||
<NICKNAME>Santiago</NICKNAME><br/>
|
|
||||||
<EMAIL>smartinez@example.org</EMAIL><br/>
|
|
||||||
<URL>www.process-one.net</URL><br/>
|
|
||||||
</vCard><br/>
|
|
||||||
</user><br/>
|
|
||||||
</host><br/>
|
|
||||||
</server-data><br/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,477 +0,0 @@
|
||||||
package net.processone.plugin.openfire;
|
|
||||||
|
|
||||||
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.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
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.openfire.OfflineMessage;
|
|
||||||
import org.jivesoftware.openfire.OfflineMessageStore;
|
|
||||||
import org.jivesoftware.openfire.PrivateStorage;
|
|
||||||
import org.jivesoftware.openfire.XMPPServer;
|
|
||||||
import org.jivesoftware.openfire.auth.AuthFactory;
|
|
||||||
import org.jivesoftware.openfire.container.Plugin;
|
|
||||||
import org.jivesoftware.openfire.container.PluginManager;
|
|
||||||
import org.jivesoftware.openfire.roster.RosterItem;
|
|
||||||
import org.jivesoftware.openfire.roster.RosterItemProvider;
|
|
||||||
import org.jivesoftware.openfire.user.User;
|
|
||||||
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
|
|
||||||
import org.jivesoftware.openfire.user.UserManager;
|
|
||||||
import org.jivesoftware.openfire.user.UserNotFoundException;
|
|
||||||
import org.jivesoftware.openfire.user.UserProvider;
|
|
||||||
import org.jivesoftware.openfire.vcard.VCardManager;
|
|
||||||
import org.jivesoftware.stringprep.Stringprep;
|
|
||||||
import org.jivesoftware.stringprep.StringprepException;
|
|
||||||
import org.jivesoftware.util.Log;
|
|
||||||
import org.xmpp.packet.JID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* The user import/export plugin provides a way to import and export Openfire
|
|
||||||
* user data via the Admin Console. This plugin is XEP-0227 compliant
|
|
||||||
* </p>
|
|
||||||
* This plugin can export: <li>User data</li> <li>vCard</li> <li>Offline
|
|
||||||
* messages</li> <br/>
|
|
||||||
* <p>
|
|
||||||
* <b>See also:</b> {@link List http://xmpp.org/extensions/xep-0227.html}
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:smartinez@process-one.net">Vidal Santiago
|
|
||||||
* Martinez</a>
|
|
||||||
*/
|
|
||||||
public class ExporterXEP227 implements Plugin {
|
|
||||||
|
|
||||||
private static final String LOAD_ALL_PRIVATE = "SELECT privateData FROM ofPrivate WHERE username=?";
|
|
||||||
|
|
||||||
private UserManager userManager;
|
|
||||||
private UserProvider provider;
|
|
||||||
private String serverName;
|
|
||||||
private OfflineMessageStore offlineMessagesStore;
|
|
||||||
private VCardManager vCardManager;
|
|
||||||
private PrivateStorage privateStorage;
|
|
||||||
|
|
||||||
|
|
||||||
public ExporterXEP227() {
|
|
||||||
userManager = XMPPServer.getInstance().getUserManager();
|
|
||||||
offlineMessagesStore = XMPPServer.getInstance()
|
|
||||||
.getOfflineMessageStore();
|
|
||||||
provider = UserManager.getUserProvider();
|
|
||||||
serverName = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
|
|
||||||
privateStorage = XMPPServer.getInstance().getPrivateStorage();
|
|
||||||
vCardManager = VCardManager.getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initializePlugin(PluginManager manager, File pluginDirectory) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroyPlugin() {
|
|
||||||
userManager = null;
|
|
||||||
provider = null;
|
|
||||||
serverName = null;
|
|
||||||
offlineMessagesStore = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method that returns true if this UserProvider is read-only.
|
|
||||||
*
|
|
||||||
* @return true if the user provider is read-only.
|
|
||||||
*/
|
|
||||||
public boolean isUserProviderReadOnly() {
|
|
||||||
return provider.isReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the user data that is to be exported to a byte[]. If a read-only
|
|
||||||
* user store is being used a user's password will be the same as their
|
|
||||||
* username.
|
|
||||||
*
|
|
||||||
* @return a byte[] of the user data.
|
|
||||||
* @throws IOException
|
|
||||||
* if there's a problem writing to the XMLWriter.
|
|
||||||
*/
|
|
||||||
public byte[] exportUsersToByteArray() throws IOException {
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
|
|
||||||
writer.write(exportUsers());
|
|
||||||
|
|
||||||
return out.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the exported user data to a String. If a read-only user store is
|
|
||||||
* being used a user's password will be the same as their username.
|
|
||||||
*
|
|
||||||
* @return a formatted String representation of the user data.
|
|
||||||
* @throws IOException
|
|
||||||
* if there's a problem writing to the XMLWriter.
|
|
||||||
*/
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of usernames that were unable to be imported or whose
|
|
||||||
* rosters could not imported. Users are not able to be imported for the
|
|
||||||
* following reasons: <li>Their username is not properly formatted. <li>If a
|
|
||||||
* read-only user data store is being used and the user could not be found.
|
|
||||||
* <li>If a writeable user data store is being used and the user already
|
|
||||||
* exists.
|
|
||||||
*
|
|
||||||
* @param file
|
|
||||||
* a FileItem containing the user data to be imported.
|
|
||||||
* @param previousDomain
|
|
||||||
* a String an optional parameter that if supplied will replace
|
|
||||||
* the user roster entries domain names to server name of current
|
|
||||||
* Openfire installation.
|
|
||||||
* @return True if FileItem matches the openfire user schema.
|
|
||||||
* @throws IOException
|
|
||||||
* if there is a problem reading the FileItem.
|
|
||||||
* @throws DocumentException
|
|
||||||
* if an error occurs during parsing.
|
|
||||||
*/
|
|
||||||
public List<String> importUserData(FileItem file, String previousDomain)
|
|
||||||
throws DocumentException, IOException {
|
|
||||||
SAXReader reader = new SAXReader();
|
|
||||||
Document document = reader.read(file.getInputStream());
|
|
||||||
return importUsers(document, previousDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not the supplied FileItem matches the openfire user
|
|
||||||
* schema
|
|
||||||
*
|
|
||||||
* @param file
|
|
||||||
* a FileItem to be validated.
|
|
||||||
* @return True if FileItem matches the openfire user schema.
|
|
||||||
*/
|
|
||||||
public boolean validateImportFile(FileItem file) {
|
|
||||||
try {
|
|
||||||
return new UserSchemaValidator(file, "wildfire-user-schema.xsd")
|
|
||||||
.validate();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adding heading of an user and its parameters
|
|
||||||
*
|
|
||||||
* @param userElement
|
|
||||||
* DOM element
|
|
||||||
* @param user
|
|
||||||
* User object
|
|
||||||
*/
|
|
||||||
private void addUser(Element userElement, User user) {
|
|
||||||
|
|
||||||
String userName = user.getUsername();
|
|
||||||
userElement.addAttribute("name", userName);
|
|
||||||
|
|
||||||
try {
|
|
||||||
userElement.addAttribute("password", AuthFactory
|
|
||||||
.getPassword(userName));
|
|
||||||
|
|
||||||
} catch (UserNotFoundException e) {
|
|
||||||
Log.info("User " + userName
|
|
||||||
+ " not found, setting their password to their username");
|
|
||||||
userElement.addAttribute("password", userName);
|
|
||||||
} catch (UnsupportedOperationException e) {
|
|
||||||
Log.info("Unable to retrieve " + userName
|
|
||||||
+ " password, setting their password to their username");
|
|
||||||
userElement.addAttribute("password", userName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add roster and its groups to a DOM element
|
|
||||||
*
|
|
||||||
* @param userElement
|
|
||||||
* DOM element
|
|
||||||
* @param user
|
|
||||||
* User
|
|
||||||
*/
|
|
||||||
private void addRoster(Element userElement, User user) {
|
|
||||||
Element rosterElement = userElement.addElement("query",
|
|
||||||
"jabber:iq:roster");
|
|
||||||
|
|
||||||
Collection<RosterItem> roster = user.getRoster().getRosterItems();
|
|
||||||
for (RosterItem ri : roster) {
|
|
||||||
Element itemElement = rosterElement.addElement("item");
|
|
||||||
|
|
||||||
itemElement.addAttribute("jid", ri.getJid().toBareJID());
|
|
||||||
itemElement.addAttribute("name", ri.getNickname());
|
|
||||||
itemElement.addAttribute("subscription", ri.getSubStatus()
|
|
||||||
.getName());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adding groups
|
|
||||||
*/
|
|
||||||
Element groupElement = itemElement.addElement("group");
|
|
||||||
List<String> groups = ri.getGroups();
|
|
||||||
for (String group : groups) {
|
|
||||||
groupElement.addText(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adding offline messages, if there are some.
|
|
||||||
*
|
|
||||||
* @param hostname
|
|
||||||
* host name
|
|
||||||
* @param userElement
|
|
||||||
* DOM element
|
|
||||||
* @param userName
|
|
||||||
* user name
|
|
||||||
*/
|
|
||||||
private void addOfflineMessages(String hostname, Element userElement,
|
|
||||||
String userName) {
|
|
||||||
Collection<OfflineMessage> offlineMessages = offlineMessagesStore
|
|
||||||
.getMessages(userName, false);
|
|
||||||
|
|
||||||
if (!offlineMessages.isEmpty()) {
|
|
||||||
Element offlineElement = userElement.addElement("offline-messages");
|
|
||||||
|
|
||||||
for (OfflineMessage offMessage : offlineMessages) {
|
|
||||||
Element messageElement = offlineElement.addElement("message",
|
|
||||||
"jabber:client");
|
|
||||||
messageElement.addAttribute("from", offMessage.getFrom()
|
|
||||||
.toString());
|
|
||||||
messageElement
|
|
||||||
.addAttribute("to", offMessage.getTo().toString());
|
|
||||||
messageElement
|
|
||||||
.addAttribute("type", offMessage.getType().name());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adding text message
|
|
||||||
*/
|
|
||||||
Element bodyElement = messageElement.addElement("body");
|
|
||||||
String body = offMessage.getBody();
|
|
||||||
bodyElement.addText(body != null ? body : "");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adding delay element
|
|
||||||
*/
|
|
||||||
Element delayElement = messageElement.addElement("delay",
|
|
||||||
"urn:xmpp:delay");
|
|
||||||
delayElement.addAttribute("from", hostname);
|
|
||||||
delayElement.addAttribute("stamp", offMessage.getCreationDate()
|
|
||||||
.toString());
|
|
||||||
delayElement.addText("Offline Storage");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adding vcard element
|
|
||||||
*
|
|
||||||
* @param userElement
|
|
||||||
* DOM element
|
|
||||||
* @param userName
|
|
||||||
* user name
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void addVCard(Element userElement, String userName) {
|
|
||||||
Element vCard = vCardManager.getVCard(userName);
|
|
||||||
if (vCard != null) {
|
|
||||||
Element vCardElement = userElement
|
|
||||||
.addElement("vCard", "vcard-temp");
|
|
||||||
for (Iterator<Element> iterator = vCard.elementIterator(); iterator
|
|
||||||
.hasNext();) {
|
|
||||||
Element element = iterator.next();
|
|
||||||
vCardElement.addElement(element.getName()).addText(
|
|
||||||
element.getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add all the private stored information (XEP-0049)
|
|
||||||
* <b>Note: this method is not suported in the available openfire releases,
|
|
||||||
* If you want to use it, you will need to change your openfire.jar file to
|
|
||||||
* openfire.jar file in this projects lib folder, remove comment to this
|
|
||||||
* method and recompile the plugin.
|
|
||||||
*
|
|
||||||
* </b>
|
|
||||||
* @param userName User name
|
|
||||||
* @param userElement User element
|
|
||||||
*/
|
|
||||||
private void addPrivateStorage(String userName, Element userElement) {
|
|
||||||
// Element result = privateStorage.getAll(userName);
|
|
||||||
// if (result.elements().size() > 0) {
|
|
||||||
// userElement.add(result.createCopy());
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export the user list and its, Vcard, Offline mesages and roster list to
|
|
||||||
* an XML representation XEP-0227 compliant
|
|
||||||
*
|
|
||||||
* @return DOM document
|
|
||||||
*/
|
|
||||||
private Document exportUsers() {
|
|
||||||
Document document = DocumentHelper.createDocument();
|
|
||||||
|
|
||||||
Element root = document.addElement("server-data",
|
|
||||||
"http://www.xmpp.org/extensions/xep-0227.html#ns");
|
|
||||||
|
|
||||||
Element host = root.addElement("host");
|
|
||||||
|
|
||||||
host.addAttribute("jid", serverName);
|
|
||||||
|
|
||||||
Collection<User> users = userManager.getUsers();
|
|
||||||
for (User user : users) {
|
|
||||||
|
|
||||||
String userName = user.getUsername();
|
|
||||||
|
|
||||||
Element userElement = host.addElement("user");
|
|
||||||
|
|
||||||
addUser(userElement, user);
|
|
||||||
|
|
||||||
addRoster(userElement, user);
|
|
||||||
|
|
||||||
addVCard(userElement, userName);
|
|
||||||
|
|
||||||
addOfflineMessages(serverName, userElement, userName);
|
|
||||||
|
|
||||||
addPrivateStorage(userName, userElement);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return document;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> importUsers(Document document, String previousDomain) {
|
|
||||||
List<String> invalidUsers = new ArrayList<String>();
|
|
||||||
|
|
||||||
UserManager userManager = UserManager.getInstance();
|
|
||||||
RosterItemProvider rosterItemProvider = RosterItemProvider
|
|
||||||
.getInstance();
|
|
||||||
|
|
||||||
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 {
|
|
||||||
userName = Stringprep.nodeprep(userName);
|
|
||||||
|
|
||||||
if (!isUserProviderReadOnly()) {
|
|
||||||
userManager.createUser(userName, password, name, email);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see user exists before adding their roster, this
|
|
||||||
// is for read-only user providers.
|
|
||||||
userManager.getUser(userName);
|
|
||||||
for (RosterItem ri : rosterItems) {
|
|
||||||
rosterItemProvider.createItem(userName, ri);
|
|
||||||
}
|
|
||||||
} catch (StringprepException se) {
|
|
||||||
Log.info("Invalid username " + userName);
|
|
||||||
invalidUsers.add(userName);
|
|
||||||
} catch (UserAlreadyExistsException e) {
|
|
||||||
Log.info("User already exists " + userName);
|
|
||||||
invalidUsers.add(userName);
|
|
||||||
} catch (UserNotFoundException e) {
|
|
||||||
Log.info("User not found " + userName);
|
|
||||||
invalidUsers.add(userName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return invalidUsers;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package net.processone.plugin.openfire;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import javax.xml.parsers.SAXParserFactory;
|
|
||||||
|
|
||||||
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 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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,326 +0,0 @@
|
||||||
package org.jivesoftware.openfire;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* $RCSfile$
|
|
||||||
* $Revision: 1759 $
|
|
||||||
* $Date: 2005-08-09 19:32:51 -0300 (Tue, 09 Aug 2005) $
|
|
||||||
*
|
|
||||||
* Copyright (C) 2004-2008 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, or a commercial license
|
|
||||||
* agreement with Jive.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import org.dom4j.Document;
|
|
||||||
import org.dom4j.DocumentHelper;
|
|
||||||
import org.dom4j.Element;
|
|
||||||
import org.dom4j.Namespace;
|
|
||||||
import org.dom4j.QName;
|
|
||||||
import org.dom4j.io.SAXReader;
|
|
||||||
import org.jivesoftware.database.DbConnectionManager;
|
|
||||||
import org.jivesoftware.util.JiveGlobals;
|
|
||||||
import org.jivesoftware.util.LocaleUtils;
|
|
||||||
import org.jivesoftware.util.Log;
|
|
||||||
import org.jivesoftware.openfire.container.BasicModule;
|
|
||||||
import org.jivesoftware.openfire.event.UserEventDispatcher;
|
|
||||||
import org.jivesoftware.openfire.event.UserEventListener;
|
|
||||||
import org.jivesoftware.openfire.user.User;
|
|
||||||
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private storage for user accounts (JEP-0049). It is used by some XMPP systems
|
|
||||||
* for saving client settings on the server.
|
|
||||||
*
|
|
||||||
* @author Iain Shigeoka
|
|
||||||
*/
|
|
||||||
public class PrivateStorage extends BasicModule implements UserEventListener {
|
|
||||||
|
|
||||||
private static final String LOAD_PRIVATE = "SELECT privateData FROM ofPrivate WHERE username=? AND namespace=?";
|
|
||||||
private static final String LOAD_ALL_PRIVATE = "SELECT privateData FROM ofPrivate WHERE username=?";
|
|
||||||
private static final String INSERT_PRIVATE = "INSERT INTO ofPrivate (privateData,name,username,namespace) VALUES (?,?,?,?)";
|
|
||||||
private static final String UPDATE_PRIVATE = "UPDATE ofPrivate SET privateData=?, name=? WHERE username=? AND namespace=?";
|
|
||||||
private static final String DELETE_PRIVATES = "DELETE FROM ofPrivate WHERE username=?";
|
|
||||||
|
|
||||||
// Currently no delete supported, we can detect an add of an empty element
|
|
||||||
// and
|
|
||||||
// use that to signal a delete but that optimization doesn't seem necessary.
|
|
||||||
// private static final String DELETE_PRIVATE =
|
|
||||||
// "DELETE FROM ofPrivate WHERE userID=? AND name=? AND namespace=?";
|
|
||||||
|
|
||||||
private boolean enabled = JiveGlobals.getBooleanProperty(
|
|
||||||
"xmpp.privateStorageEnabled", true);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pool of SAX Readers. SAXReader is not thread safe so we need to have a
|
|
||||||
* pool of readers.
|
|
||||||
*/
|
|
||||||
private BlockingQueue<SAXReader> xmlReaders = new LinkedBlockingQueue<SAXReader>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new PrivateStore instance.
|
|
||||||
*/
|
|
||||||
public PrivateStorage() {
|
|
||||||
super("Private user data storage");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if private storage is enabled.
|
|
||||||
*
|
|
||||||
* @return true if private storage is enabled.
|
|
||||||
*/
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether private storage is enabled.
|
|
||||||
*
|
|
||||||
* @param enabled
|
|
||||||
* true if this private store is enabled.
|
|
||||||
*/
|
|
||||||
public void setEnabled(boolean enabled) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
JiveGlobals.setProperty("xmpp.privateStorageEnabled", Boolean
|
|
||||||
.toString(enabled));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores private data. If the name and namespace of the element matches
|
|
||||||
* another stored private data XML document, then replace it with the new
|
|
||||||
* one.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* the data to store (XML element)
|
|
||||||
* @param username
|
|
||||||
* the username of the account where private data is being stored
|
|
||||||
*/
|
|
||||||
public void add(String username, Element data) {
|
|
||||||
if (enabled) {
|
|
||||||
java.sql.Connection con = null;
|
|
||||||
PreparedStatement pstmt = null;
|
|
||||||
try {
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
data.write(writer);
|
|
||||||
con = DbConnectionManager.getConnection();
|
|
||||||
pstmt = con.prepareStatement(LOAD_PRIVATE);
|
|
||||||
pstmt.setString(1, username);
|
|
||||||
pstmt.setString(2, data.getNamespaceURI());
|
|
||||||
ResultSet rs = pstmt.executeQuery();
|
|
||||||
boolean update = false;
|
|
||||||
if (rs.next()) {
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
pstmt.close();
|
|
||||||
|
|
||||||
if (update) {
|
|
||||||
pstmt = con.prepareStatement(UPDATE_PRIVATE);
|
|
||||||
} else {
|
|
||||||
pstmt = con.prepareStatement(INSERT_PRIVATE);
|
|
||||||
}
|
|
||||||
pstmt.setString(1, writer.toString());
|
|
||||||
pstmt.setString(2, data.getName());
|
|
||||||
pstmt.setString(3, username);
|
|
||||||
pstmt.setString(4, data.getNamespaceURI());
|
|
||||||
pstmt.executeUpdate();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (pstmt != null) {
|
|
||||||
pstmt.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (con != null) {
|
|
||||||
con.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the data stored under a key corresponding to the name and
|
|
||||||
* namespace of the given element. The Element must be in the form:
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* <code><name xmlns='namespace'/></code>
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* If no data is currently stored under the given key, an empty element will
|
|
||||||
* be returned.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* an XML document who's element name and namespace is used to
|
|
||||||
* match previously stored private data.
|
|
||||||
* @param username
|
|
||||||
* the username of the account where private data is being
|
|
||||||
* stored.
|
|
||||||
* @return the data stored under the given key or the data element.
|
|
||||||
*/
|
|
||||||
public Element get(String username, Element data) {
|
|
||||||
if (enabled) {
|
|
||||||
Connection con = null;
|
|
||||||
PreparedStatement pstmt = null;
|
|
||||||
SAXReader xmlReader = null;
|
|
||||||
try {
|
|
||||||
// Get a sax reader from the pool
|
|
||||||
xmlReader = xmlReaders.take();
|
|
||||||
con = DbConnectionManager.getConnection();
|
|
||||||
pstmt = con.prepareStatement(LOAD_PRIVATE);
|
|
||||||
pstmt.setString(1, username);
|
|
||||||
pstmt.setString(2, data.getNamespaceURI());
|
|
||||||
ResultSet rs = pstmt.executeQuery();
|
|
||||||
if (rs.next()) {
|
|
||||||
data.clearContent();
|
|
||||||
String result = rs.getString(1).trim();
|
|
||||||
Document doc = xmlReader.read(new StringReader(result));
|
|
||||||
data = doc.getRootElement();
|
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
|
|
||||||
} finally {
|
|
||||||
// Return the sax reader to the pool
|
|
||||||
if (xmlReader != null) {
|
|
||||||
xmlReaders.add(xmlReader);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (pstmt != null) {
|
|
||||||
pstmt.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (con != null) {
|
|
||||||
con.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Element getAll(String username) {
|
|
||||||
QName qName = new QName("", new Namespace("","jabber:iq:private"), "query");
|
|
||||||
Element data = DocumentHelper.createElement(qName);
|
|
||||||
|
|
||||||
if (enabled) {
|
|
||||||
Connection con = null;
|
|
||||||
PreparedStatement pstmt = null;
|
|
||||||
SAXReader xmlReader = null;
|
|
||||||
try {
|
|
||||||
// Get a sax reader from the pool
|
|
||||||
xmlReader = xmlReaders.take();
|
|
||||||
con = DbConnectionManager.getConnection();
|
|
||||||
pstmt = con.prepareStatement(LOAD_ALL_PRIVATE);
|
|
||||||
pstmt.setString(1, username);
|
|
||||||
|
|
||||||
ResultSet rs = pstmt.executeQuery();
|
|
||||||
while (rs.next()) {
|
|
||||||
String result = rs.getString(1).trim();
|
|
||||||
Document doc = xmlReader.read(new StringReader(result));
|
|
||||||
data.add(doc.getRootElement());
|
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
|
|
||||||
} finally {
|
|
||||||
// Return the sax reader to the pool
|
|
||||||
if (xmlReader != null) {
|
|
||||||
xmlReaders.add(xmlReader);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (pstmt != null) {
|
|
||||||
pstmt.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (con != null) {
|
|
||||||
con.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userCreated(User user, Map params) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userDeleting(User user, Map params) {
|
|
||||||
// Delete all private properties of the user
|
|
||||||
java.sql.Connection con = null;
|
|
||||||
PreparedStatement pstmt = null;
|
|
||||||
try {
|
|
||||||
con = DbConnectionManager.getConnection();
|
|
||||||
pstmt = con.prepareStatement(DELETE_PRIVATES);
|
|
||||||
pstmt.setString(1, user.getUsername());
|
|
||||||
pstmt.executeUpdate();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (pstmt != null) {
|
|
||||||
pstmt.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (con != null) {
|
|
||||||
con.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void userModified(User user, Map params) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() throws IllegalStateException {
|
|
||||||
super.start();
|
|
||||||
// Initialize the pool of sax readers
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
SAXReader xmlReader = new SAXReader();
|
|
||||||
xmlReader.setEncoding("UTF-8");
|
|
||||||
xmlReaders.add(xmlReader);
|
|
||||||
}
|
|
||||||
// Add this module as a user event listener so we can delete
|
|
||||||
// all user properties when a user is deleted
|
|
||||||
UserEventDispatcher.addListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
super.stop();
|
|
||||||
// Clean up the pool of sax readers
|
|
||||||
xmlReaders.clear();
|
|
||||||
// Remove this module as a user event listener
|
|
||||||
UserEventDispatcher.removeListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
<%@ page import="java.io.OutputStream,
|
|
||||||
org.jivesoftware.openfire.XMPPServer,
|
|
||||||
net.processone.plugin.openfire.ExporterXEP227"
|
|
||||||
contentType="application/x-download" %>
|
|
||||||
|
|
||||||
<!--NOTE: This JSP file should be implemented with JSTL and Servlet,
|
|
||||||
Is not a good idea to call your self pages and add scriplet to handle -->
|
|
||||||
|
|
||||||
<%String fileName = request.getParameter("fileName");
|
|
||||||
response.setContentType("application/x-download");
|
|
||||||
response.setHeader("Content-Disposition","attachment;filename="+fileName+".xml");
|
|
||||||
ExporterXEP227 plugin = (ExporterXEP227) XMPPServer.getInstance().getPluginManager().getPlugin("openfireexporter");
|
|
||||||
byte[] content = plugin.exportUsersToByteArray();
|
|
||||||
OutputStream os = response.getOutputStream();
|
|
||||||
os.write(content);
|
|
||||||
os.flush();
|
|
||||||
os.close();%>
|
|
|
@ -1,137 +0,0 @@
|
||||||
<%@ page
|
|
||||||
import="java.io.IOException,java.util.*,
|
|
||||||
net.processone.plugin.openfire.ExporterXEP227,
|
|
||||||
org.jivesoftware.openfire.XMPPServer,
|
|
||||||
org.jivesoftware.util.ParamUtils"%>
|
|
||||||
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
|
|
||||||
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt"%>
|
|
||||||
|
|
||||||
<!--NOTE: This JSP file should be implemented with JSTL and Servlet,
|
|
||||||
Is not a good idea to call your self pages and add scriplet to handle -->
|
|
||||||
|
|
||||||
<%
|
|
||||||
boolean exportUsers = request.getParameter("exportUsers") != null;
|
|
||||||
boolean success = request.getParameter("success") != null;
|
|
||||||
boolean exportToFile = ParamUtils.getBooleanParameter(request,
|
|
||||||
"exporttofile", true);
|
|
||||||
|
|
||||||
ExporterXEP227 plugin = (ExporterXEP227) XMPPServer.getInstance()
|
|
||||||
.getPluginManager().getPlugin("openfireexporter");
|
|
||||||
|
|
||||||
String exportText = "";
|
|
||||||
|
|
||||||
Map<String, String> errors = new HashMap<String, String>();
|
|
||||||
if (exportUsers) {
|
|
||||||
if (exportToFile) {
|
|
||||||
String file = ParamUtils
|
|
||||||
.getParameter(request, "exportFile");
|
|
||||||
if ((file == null) || (file.length() <= 0)) {
|
|
||||||
errors.put("missingFile", "missingFile");
|
|
||||||
} else {
|
|
||||||
response.sendRedirect("export-file.jsp?fileName="
|
|
||||||
+ file);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
exportText = plugin.exportUsersToString();
|
|
||||||
} catch (IOException e) {
|
|
||||||
errors.put("IOException", "IOException");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Export User Data</title>
|
|
||||||
<meta name="pageID" content="import-export-selection" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<%
|
|
||||||
if (errors.size() > 0) {
|
|
||||||
%>
|
|
||||||
|
|
||||||
<div class="jive-error">
|
|
||||||
<table cellpadding="0" cellspacing="0" border="0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="jive-icon"><img src="images/error-16x16.gif"
|
|
||||||
width="16" height="16" border="0"></td>
|
|
||||||
<td class="jive-icon-label">
|
|
||||||
<%
|
|
||||||
if (errors.containsKey("missingFile")) {
|
|
||||||
%> Missing or bad file
|
|
||||||
name. <%
|
|
||||||
} else if (errors.containsKey("IOException")
|
|
||||||
|| errors.containsKey("fileNotCreated")) {
|
|
||||||
%>
|
|
||||||
Couldn't create export file. <%
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<%
|
|
||||||
} else if (ParamUtils.getBooleanParameter(request, "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">User data successfully exported.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
|
|
||||||
<form action="export-user-data.jsp?exportUsers" method="post">
|
|
||||||
|
|
||||||
<div class="jive-contentBoxHeader">Export Options</div>
|
|
||||||
<div class="jive-contentBox">
|
|
||||||
<p>Select the radio button next to the desired export option and
|
|
||||||
then click on the Export button.</p>
|
|
||||||
|
|
||||||
<table cellpadding="3" cellspacing="0" border="0" width="100%">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="1%"><input type="radio" name="exporttofile"
|
|
||||||
value="true" <%=exportToFile ? "checked" : ""%> id="rb01"></td>
|
|
||||||
<td width="99%"><label for="rb01"><b>To File</b></label> - Save
|
|
||||||
user data to the specified file location.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td width="1%"> </td>
|
|
||||||
<td width="99%">Export File Name: <input type="text"
|
|
||||||
size="30" maxlength="150" name="exportFile"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td width="1%"><input type="radio" name="exporttofile"
|
|
||||||
value="false" <%=!exportToFile ? "checked" : ""%> id="rb02"></td>
|
|
||||||
<td width="99%"><label for="rb02"><b>To Screen</b></label> -
|
|
||||||
Display user data in the text area below.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td width="1%"> </td>
|
|
||||||
<td width="99%"><textarea cols="80" rows="20" wrap=off><%=exportText%></textarea></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input type="submit" value="Export"></form>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 594 B |
Binary file not shown.
Before Width: | Height: | Size: 1016 B |
|
@ -1,42 +0,0 @@
|
||||||
<%@ page import="net.processone.plugin.openfire.ExporterXEP227,
|
|
||||||
org.jivesoftware.openfire.XMPPServer"
|
|
||||||
%>
|
|
||||||
|
|
||||||
<!--NOTE: This JSP file should be implemented with JSTL and Servlet,
|
|
||||||
Is not a good idea to call your self pages and add scriplet to handle -->
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Import/Export Selection</title>
|
|
||||||
<meta name="pageID" content="import-export-selection"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<jsp:useBean id="pageinfo" scope="request" class="org.jivesoftware.admin.AdminPageBean" />
|
|
||||||
<%
|
|
||||||
ExporterXEP227 plugin = (ExporterXEP227) XMPPServer.getInstance().getPluginManager().getPlugin("openfireexporter");
|
|
||||||
%>
|
|
||||||
<p>
|
|
||||||
Openfire plugin improved to export to XEP-227 format.
|
|
||||||
There is also old code to import, but using a custom Openfire format.
|
|
||||||
If you are interested you can improve it to also support XEP-227 import.
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="import-user-data.jsp">Import User Data</a></li>
|
|
||||||
<li><a href="export-user-data.jsp">Export User Data</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<%
|
|
||||||
if (plugin.isUserProviderReadOnly()) {
|
|
||||||
%>
|
|
||||||
|
|
||||||
Note: because you are using a read-only user data store such as LDAP or POP3 you will only be able to import user roster data, not users themselves.
|
|
||||||
Please see the <a href="../../plugin-admin.jsp?plugin=openfireexporter&showReadme=true&decorator=none">readme</a> for details.
|
|
||||||
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,168 +0,0 @@
|
||||||
<%@ page import="java.net.MalformedURLException,
|
|
||||||
java.util.*,
|
|
||||||
org.dom4j.DocumentException,
|
|
||||||
org.apache.commons.fileupload.DiskFileUpload,
|
|
||||||
org.apache.commons.fileupload.FileItem,net.processone.plugin.openfire.ExporterXEP227,
|
|
||||||
org.jivesoftware.openfire.XMPPServer,
|
|
||||||
org.jivesoftware.util.ParamUtils"
|
|
||||||
%>
|
|
||||||
|
|
||||||
<!--NOTE: This JSP file should be implemented with JSTL and Servlet,
|
|
||||||
Is not a good idea to call your self pages and add scriplet to handle -->
|
|
||||||
|
|
||||||
<%
|
|
||||||
boolean importUsers = request.getParameter("importUsers") != null;
|
|
||||||
|
|
||||||
ExporterXEP227 plugin = (ExporterXEP227) XMPPServer.getInstance().getPluginManager().getPlugin("openfireexporter");
|
|
||||||
List<String> duplicateUsers = new ArrayList<String>();
|
|
||||||
|
|
||||||
Map<String, String> errors = new HashMap<String, String>();
|
|
||||||
if (importUsers) {
|
|
||||||
DiskFileUpload dfu = new DiskFileUpload();
|
|
||||||
|
|
||||||
List fileItems = dfu.parseRequest(request);
|
|
||||||
Iterator i = fileItems.iterator();
|
|
||||||
FileItem fi = (FileItem) i.next();
|
|
||||||
FileItem pd = (FileItem) i.next();
|
|
||||||
String previousDomain = pd.getString();
|
|
||||||
|
|
||||||
if (plugin.validateImportFile(fi)) {
|
|
||||||
try {
|
|
||||||
if (isEmpty(previousDomain)) {
|
|
||||||
duplicateUsers.addAll(plugin.importUserData(fi, null));
|
|
||||||
}
|
|
||||||
else if (!isEmpty(previousDomain)) {
|
|
||||||
duplicateUsers.addAll(plugin.importUserData(fi, previousDomain));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
errors.put("missingDomain", "missingDomain");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duplicateUsers.size() == 0) {
|
|
||||||
response.sendRedirect("import-user-data.jsp?success=true");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.put("invalidUser", "invalidUser");
|
|
||||||
}
|
|
||||||
catch (MalformedURLException e) {
|
|
||||||
errors.put("IOException", "IOException");
|
|
||||||
}
|
|
||||||
catch (DocumentException e) {
|
|
||||||
errors.put("DocumentException", "DocumentException");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
errors.put("invalidUserFile", "invalidUserFile");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Import User Data</title>
|
|
||||||
<meta name="pageID" content="import-export-selection"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<% if (errors.size() > 0) { %>
|
|
||||||
|
|
||||||
<div class="jive-error">
|
|
||||||
<table cellpadding="0" cellspacing="0" border="0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="jive-icon"><img src="images/error-16x16.gif" width="16" height="16" border="0"></td>
|
|
||||||
<td class="jive-icon-label">
|
|
||||||
<% if (errors.containsKey("missingDomain")) { %>
|
|
||||||
You must supply both a existing and new domain name.
|
|
||||||
<% } else if (errors.containsKey("IOException")) { %>
|
|
||||||
Missing or bad file name.
|
|
||||||
<% } else if (errors.containsKey("DocumentException")) { %>
|
|
||||||
Import failed.
|
|
||||||
<% } else if (errors.containsKey("invalidUserFile")) { %>
|
|
||||||
The import file does not match the user schema.
|
|
||||||
<% } else if (errors.containsKey("invalidUser")) { %>
|
|
||||||
|
|
||||||
<% if (plugin.isUserProviderReadOnly()) { %>
|
|
||||||
The following users did not exist in the system or have invalid username so their roster was not loaded:<br>
|
|
||||||
<% } else { %>
|
|
||||||
The following users already exist in the system or have invalid username and were not loaded:<br>
|
|
||||||
<% } %>
|
|
||||||
<%
|
|
||||||
Iterator iter = duplicateUsers.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
String username = (String) iter.next();
|
|
||||||
%><%= username %><%
|
|
||||||
if (iter.hasNext()) {
|
|
||||||
%>, <%
|
|
||||||
} else {
|
|
||||||
%>.<%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<% } else if (ParamUtils.getBooleanParameter(request, "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>
|
|
||||||
<% if (plugin.isUserProviderReadOnly()) { %>
|
|
||||||
<td class="jive-icon-label">User roster data added successfully.</td>
|
|
||||||
<% } else { %>
|
|
||||||
<td class="jive-icon-label">All users added successfully.</td>
|
|
||||||
<% } %>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
Use the form below to import a user data XML file.
|
|
||||||
|
|
||||||
|
|
||||||
<form action="import-user-data.jsp?importUsers" method="post" enctype="multipart/form-data">
|
|
||||||
|
|
||||||
<div class="jive-contentBoxHeader">Import</div>
|
|
||||||
<div class="jive-contentBox">
|
|
||||||
<p>
|
|
||||||
Choose a file to import:</p>
|
|
||||||
<input type="file" name="thefile">
|
|
||||||
|
|
||||||
<br><br><br>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<b>Optional</b> - Use the field below to replace the domain name of user roster entries with the current hostname.
|
|
||||||
See the migration section of the <a href="../../plugin-admin.jsp?plugin=openfireexporter&showReadme=true&decorator=none">readme</a> for details.
|
|
||||||
</p>
|
|
||||||
Replace Domain: <input type="text" size="20" maxlength="150" name="previousDomain" value=""/>
|
|
||||||
</div>
|
|
||||||
<input type="submit" value="Import">
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
<%!
|
|
||||||
public boolean isEmpty(String s) {
|
|
||||||
if (s == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.trim().length() == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
%>
|
|
Loading…
Reference in New Issue