smack_1_5_1

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@2639 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Gaston Dombiak 2005-08-12 21:09:32 +00:00 committed by gato
parent aa32e12164
commit 7ae75258be
276 changed files with 40430 additions and 0 deletions

View File

@ -0,0 +1,42 @@
#! /bin/sh
# //--------------------------------------------------------------------------//
# // $RCSfile$
# // $Revision$
# // $Date$
# //
# // Standard Jive Software ant file. Do not change this file. If you do,
# // you will have seven years of bad luck and bad builds.
# //--------------------------------------------------------------------------//
# //--------------------------------------------------------------------------//
# // Uncomment the following lines if you wish to set JAVA_HOME in this script
# //--------------------------------------------------------------------------//
# JAVA_HOME=
# EXPORT JAVA_HOME
# //--------------------------------------------------------------------------//
# // Check for the JAVA_HOME environment variable //
# //--------------------------------------------------------------------------//
if [ "$JAVA_HOME" != "" ] ; then
# //----------------------------------------------------------------------//
# // Create Ant's classpath //
# //----------------------------------------------------------------------//
CP=$JAVA_HOME/lib/tools.jar:../../../build/ant.jar
# //----------------------------------------------------------------------//
# // Run ant //
# //----------------------------------------------------------------------//
$JAVA_HOME/bin/java -classpath $CP -Dant.home=. org.apache.tools.ant.Main $@
else
# //----------------------------------------------------------------------//
# // No JAVA_HOME error message //
# //----------------------------------------------------------------------//
echo "Jive Forums Build Error:"
echo ""
echo "The JAVA_HOME environment variable is not set. JAVA_HOME should point"
echo "to your java directory, ie: /usr/local/bin/jdk1.3. You can set"
echo "this via the command line like so:"
echo " export JAVA_HOME=/usr/local/bin/jdk1.3"
fi

View File

@ -0,0 +1,52 @@
@echo off
rem //------------------------------------------------------------------------//
rem // $RCSfile$
rem // $Revision$
rem // $Date$
rem //
rem // Standard Jive Software ant.bat file. Do not change this file. If you do,
rem // you will have seven years of bad luck and bad builds.
rem //------------------------------------------------------------------------//
rem //------------------------------------------------------------------------//
rem // Uncomment the following if you wish to set JAVA_HOME in this bat file:
rem //------------------------------------------------------------------------//
rem SET JAVA_HOME=
rem //------------------------------------------------------------------------//
rem // Check for the JAVA_HOME environment variable
rem //------------------------------------------------------------------------//
if "%JAVA_HOME%" == "" goto noJavaHome
rem //------------------------------------------------------------------------//
rem // Make the correct classpath (should include the java jars and the
rem // Ant jars)
rem //------------------------------------------------------------------------//
SET CP=%JAVA_HOME%\lib\tools.jar;..\..\..\build\ant.jar
rem //------------------------------------------------------------------------//
rem // Run Ant
rem // Note for Win 98/95 users: You need to change "%*" in the following
rem // line to be "%1 %2 %3 %4 %5 %6 %7 %8 %9"
rem //------------------------------------------------------------------------//
%JAVA_HOME%\bin\java -Xms32m -Xmx128m -classpath %CP% -Dant.home=. org.apache.tools.ant.Main %*
goto end
rem //------------------------------------------------------------------------//
rem // Error message for missing JAVA_HOME
rem //------------------------------------------------------------------------//
:noJavaHome
echo.
echo Jive Forums Build Error:
echo.
echo The JAVA_HOME environment variable is not set. JAVA_HOME should point to
echo your java directory, ie: c:\jdk1.3.1. You can set this via the command
echo line like so:
echo SET JAVA_HOME=c:\jdk1.3
echo.
goto end
:end

View File

@ -0,0 +1,91 @@
<?xml version="1.0"?>
<!--
$RCSfile$
$Revision$
$Date$
-->
<project name="WebChat" default="all" basedir="..">
<property file="${basedir}/build/webchat-build.properties" />
<property name="smack.home" value="${basedir}/../../../smack" />
<property name="compile.dir" value="${basedir}/build/temp" />
<property name="jar.dest.dir" value="${basedir}/build/WEB-INF/lib" />
<property name="jar.name" value="webchat" />
<property name="war.dest.dir" value="${basedir}" />
<property name="war.name" value="webchat" />
<path id="dependencies">
<!-- build jars -->
<fileset dir="${smack.home}" includes="smack.jar" />
<fileset dir="${basedir}/build/lib" includes="*.jar" />
</path>
<patternset id="web.filetypes">
<include name="**/*.jsp" />
<include name="**/*.js" />
<include name="**/*.html" />
<include name="**/*.gif" />
<include name="**/*.css" />
</patternset>
<target name="init">
<mkdir dir="${compile.dir}" />
<mkdir dir="${jar.dest.dir}" />
<!-- call smack jar process -->
<ant antfile="build/build.xml" dir="${smack.home}" target="jar" inheritAll="false" />
</target>
<target name="clean">
<delete dir="${compile.dir}" />
<delete dir="${jar.dest.dir}" />
<!-- call smack jar process -->
<ant antfile="build/build.xml" dir="${smack.home}" target="clean" inheritAll="false" />
</target>
<target name="compile" depends="init">
<javac
destdir="${compile.dir}"
includeAntRuntime="no"
debug="on"
classpathref="dependencies"
>
<src path="${basedir}/source/java" />
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="${jar.dest.dir}/${jar.name}.jar"
basedir="${compile.dir}"
includes="**/*.class"
/>
</target>
<target name="war" depends="jar">
<war warfile="${war.dest.dir}/${war.name}.war"
webxml="${basedir}/source/config/WEB-INF/web.xml"
>
<lib dir="${jar.dest.dir}" includes="*.jar" />
<lib dir="${smack.home}" includes="smack.jar" />
<zipfileset dir="${basedir}/source/web">
<patternset refid="web.filetypes" />
</zipfileset>
</war>
</target>
<target name="deploywar" depends="war">
<copy todir="${deploy.war.dir}" overwrite="${overwrite}">
<fileset dir="${war.dest.dir}" includes="${war.name}.war" />
</copy>
</target>
</project>

Binary file not shown.

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>WebChat</display-name>
<description>Smack-powered WebChat Application</description>
<context-param>
<param-name>host</param-name>
<param-value>jivesoftware.com</param-value>
</context-param>
<!--
*******************
ALL OF THE FOLLOWING context-params are optional, and are listed with their
default values. Since they are optional, they needn't be included in this
file if you're satisfied with the default values; they're listed here
for informational purposes.
*******************
-->
<!-- allow users to logon anonymously? -->
<context-param>
<param-name>allowAnonymous</param-name>
<param-value>true</param-value>
</context-param>
<!-- allow users to create new accounts? -->
<context-param>
<param-name>allowAccountCreation</param-name>
<param-value>true</param-value>
</context-param>
<!-- allow users to login using their username/password? -->
<context-param>
<param-name>allowLogin</param-name>
<param-value>true</param-value>
</context-param>
<!-- the url for the logo image in the chat window (path relative to the .jsp files) -->
<context-param>
<param-name>logoFilename</param-name>
<param-value>images/logo.gif</param-value>
</context-param>
<!-- the color of the text for chat window room announcements -->
<context-param>
<param-name>chat.announcement-color</param-name>
<param-value>#009d00</param-value>
</context-param>
<!-- the color of the text for the dialog label associated with the user of the web client -->
<context-param>
<param-name>chat.owner-label-color</param-name>
<param-value>#aa0000</param-value>
</context-param>
<!-- the color of the text for the dialog label associated with other chat participants -->
<context-param>
<param-name>chat.participant-label-color</param-name>
<param-value>#0000aa</param-value>
</context-param>
<!-- the color of the text for the dialog in the chat window -->
<context-param>
<param-name>chat.text-color</param-name>
<param-value>#434343</param-value>
</context-param>
<!-- the color of error message text -->
<context-param>
<param-name>error.text-color</param-name>
<param-value>#ff0000</param-value>
</context-param>
<!-- the color of the text for unvisited links -->
<context-param>
<param-name>link.color</param-name>
<param-value>#045d30</param-value>
</context-param>
<!-- the color of the text for links with the pointer hovering over them -->
<context-param>
<param-name>link.hover-color</param-name>
<param-value>#350000</param-value>
</context-param>
<!-- the color of the text for already visited links -->
<context-param>
<param-name>link.visited-color</param-name>
<param-value>#3b3757</param-value>
</context-param>
<!-- the color of the background of all pages -->
<context-param>
<param-name>body.background-color</param-name>
<param-value>#ffffff</param-value>
</context-param>
<!-- the default color of the text on all pages -->
<context-param>
<param-name>body.text-color</param-name>
<param-value>#362f2d</param-value>
</context-param>
<!-- the color of the chat window divider between the participant listing and the chat -->
<context-param>
<param-name>frame.divider-color</param-name>
<param-value>#83272b</param-value>
</context-param>
<!-- the color of the form element buttons -->
<context-param>
<param-name>button.color</param-name>
<param-value>#d6dfdf</param-value>
</context-param>
<!-- the color of the text in the form element buttons -->
<context-param>
<param-name>button.text-color</param-name>
<param-value>#333333</param-value>
</context-param>
<!-- the color of the background in the form element text fields -->
<context-param>
<param-name>textfield.color</param-name>
<param-value>#f7f7fb</param-value>
</context-param>
<!-- the color of the text in the form element text fields and textareas -->
<context-param>
<param-name>textfield.text-color</param-name>
<param-value>#333333</param-value>
</context-param>
<!-- Session listener -->
<listener>
<listener-class>org.jivesoftware.webchat.JiveChatServlet</listener-class>
</listener>
<!-- Servlets -->
<servlet>
<servlet-name>ChatServlet</servlet-name>
<servlet-class>org.jivesoftware.webchat.JiveChatServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Servlet mappings -->
<servlet-mapping>
<servlet-name>ChatServlet</servlet-name>
<url-pattern>/ChatServlet/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>3</session-timeout>
</session-config>
<!-- Welcome file list -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

View File

@ -0,0 +1,292 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2003 Jive Software. All rights reserved.
*
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.webchat;
/**
* A Filter that converts ASCII emoticons into image equivalents.
* This filter should only be run after any HTML stripping filters.<p>
*
* The filter must be configured with information about where the image files
* are located. A table containing all the supported emoticons with their
* ASCII representations and image file names is as follows:<p>
*
* <table border=1>
* <tr><td><b>Emotion</b></td><td><b>ASCII</b></td><td><b>Image</b></td></tr>
*
* <tr><td>Happy</td><td>:) or :-)</td><td>happy.gif</td></tr>
* <tr><td>Sad</td><td>:( or :-(</td><td>sad.gif</td></tr>
* <tr><td>Grin</td><td>:D</td><td>grin.gif</td></tr>
* <tr><td>Love</td><td>:x</td><td>love.gif</td></tr>
* <tr><td>Mischief</td><td>;\</td><td>mischief.gif</td></tr>
* <tr><td>Cool</td><td>B-)</td><td>cool.gif</td></tr>
* <tr><td>Devil</td><td>]:)</td><td>devil.gif</td></tr>
* <tr><td>Silly</td><td>:p</td><td>silly.gif</td></tr>
* <tr><td>Angry</td><td>X-(</td><td>angry.gif</td></tr>
* <tr><td>Laugh</td><td>:^O</td><td>laugh.gif</td></tr>
* <tr><td>Wink</td><td>;) or ;-)</td><td>wink.gif</td></tr>
* <tr><td>Blush</td><td>:8}</td><td>blush.gif</td></tr>
* <tr><td>Cry</td><td>:_|</td><td>cry.gif</td></tr>
* <tr><td>Confused</td><td>?:|</td><td>confused.gif</td></tr>
* <tr><td>Shocked</td><td>:O</td><td>shocked.gif</td></tr>
* <tr><td>Plain</td><td>:|</td><td>plain.gif</td></tr>
* </table>
*
* Note: special thanks to August Harrison for implementing an earlier version of this filter.
*/
public class EmoticonFilter {
private static String imageHappy = "happy.gif";
private static String imageSad = "sad.gif";
private static String imageGrin = "grin.gif";
private static String imageLove = "love.gif";
private static String imageMischief = "mischief.gif";
private static String imageCool = "cool.gif";
private static String imageDevil = "devil.gif";
private static String imageSilly = "silly.gif";
private static String imageAngry = "angry.gif";
private static String imageLaugh = "laugh.gif";
private static String imageWink = "wink.gif";
private static String imageBlush = "blush.gif";
private static String imageCry = "cry.gif";
private static String imageConfused = "confused.gif";
private static String imageShocked = "shocked.gif";
private static String imagePlain = "plain.gif";
private static String imageURL = "images/emoticons";
// Placeholders for the built image tags
private static String imgHappy;
private static String imgSad;
private static String imgGrin;
private static String imgLove;
private static String imgMischief;
private static String imgCool;
private static String imgDevil;
private static String imgSilly;
private static String imgAngry;
private static String imgLaugh;
private static String imgWink;
private static String imgBlush;
private static String imgCry;
private static String imgConfused;
private static String imgShocked;
private static String imgPlain;
public EmoticonFilter() {
buildImageTags();
}
public String applyFilter(String string) {
if (string == null || string.length() < 1) {
return string;
}
int length = string.length();
StringBuffer filtered = new StringBuffer(string.length() + 100);
char[] chars = string.toCharArray();
int length1 = length - 1;
int length2 = length - 2;
int index = -1, i = 0, oldend = 0;
String imgTag;
// Replace each of the emoticons, expanded search for performance
while (++index < length1) {
// no tag found yet...
imgTag = null;
switch (chars[i = index]) {
case ']':
// "]:)"
if (i < length2 && chars[++i] == ':' && chars[++i] == ')') {
imgTag = imgDevil;
}
break;
case ':':
switch (chars[++i]) {
case ')':
// ":)"
imgTag = imgHappy;
break;
case '-':
// ":-)"
if (i < length1 && chars[++i] == ')') {
imgTag = imgHappy;
}
// ":-("
else if (chars[i] == '(') {
imgTag = imgSad;
}
break;
case '(':
// ":("
imgTag = imgSad;
break;
case 'D':
// ":D"
imgTag = imgGrin;
break;
case 'x':
// ":x"
imgTag = imgLove;
break;
case 'p':
// ":p"
imgTag = imgSilly;
break;
case '^':
// ":^O"
if (i < length1 && chars[++i] == 'O') {
imgTag = imgLaugh;
}
break;
case '8':
// ":8}"
if (i < length1 && chars[++i] == '}') {
imgTag = imgBlush;
}
break;
case '_':
// ":_|"
if (i < length1 && chars[++i] == '|') {
imgTag = imgCry;
}
break;
case 'O':
// ":O"
imgTag = imgShocked;
break;
case '|':
// ":|"
imgTag = imgPlain;
break;
default:
break;
}
break;
case ';':
switch (chars[++i]) {
case ')':
// ";)"
imgTag = imgWink;
break;
case '-':
// ";-)"
if (i < length1 && chars[++i] == ')') {
imgTag = imgWink;
}
break;
case '\\':
// ";\\"
imgTag = imgMischief;
break;
default:
break;
}
break;
case 'B':
// "B-)"
if (i < length2 && chars[++i] == '-' && chars[++i] == ')') {
imgTag = imgCool;
}
break;
case 'X':
// "X-("
if (i < length2 && chars[++i] == '-' && chars[++i] == '(') {
imgTag = imgAngry;
}
break;
case '?':
// "?:|"
if (i < length2 && chars[++i] == ':' && chars[++i] == '|') {
imgTag = imgConfused;
}
break;
default:
break;
}
// if we found one, replace
if (imgTag != null) {
filtered.append(chars, oldend, index-oldend);
filtered.append(imgTag);
oldend = i + 1;
index = i;
}
}
if (oldend < length) {
filtered.append(chars, oldend, length-oldend);
}
return filtered.toString();
}
/**
* Returns the base URL for emoticon images. This can be specified as
* an absolute or relative path.
*
* @return the base URL for smiley images.
*/
public String getImageURL() {
return imageURL;
}
/**
* Sets the base URL for emoticon images. This can be specified as
* an absolute or relative path.
*
* @param imageURL the base URL for emoticon images.
*/
public void setImageURL(String imageURL) {
if (imageURL != null && imageURL.length() > 0) {
if (imageURL.charAt(imageURL.length()-1) == '/') {
imageURL = imageURL.substring(0, imageURL.length()-1);
}
}
this.imageURL = imageURL;
// rebuild the image tags
buildImageTags();
}
/**
* Build image tags
*/
private void buildImageTags() {
imgHappy = buildURL(imageHappy);
imgSad = buildURL(imageSad);
imgGrin = buildURL(imageGrin);
imgLove = buildURL(imageLove);
imgMischief = buildURL(imageMischief);
imgCool = buildURL(imageCool);
imgDevil = buildURL(imageDevil);
imgSilly = buildURL(imageSilly);
imgAngry = buildURL(imageAngry);
imgLaugh = buildURL(imageLaugh);
imgWink = buildURL(imageWink);
imgBlush = buildURL(imageBlush);
imgCry = buildURL(imageCry);
imgConfused = buildURL(imageConfused);
imgShocked = buildURL(imageShocked);
imgPlain = buildURL(imagePlain);
}
/**
* Returns an HTML image tag using the base image URL and image name.
*/
private String buildURL(String imageName) {
String tag = "<img border='0' src='" + imageURL + "/" + imageName + "'>";
return tag;
}
}

View File

@ -0,0 +1,729 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2003 Jive Software. All rights reserved.
*
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.webchat;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.filter.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.util.StringUtils;
/**
* An extension of HttpServlet customized to handle transactions between N webclients
* and M chats located on a given XMPP server. While N >= M in the case of group chats,
* the code will currently, never the less, hold onto N connections to the XMPP server.<br>
*
* It is assumed that all JSP pages are in the context root. The init params should be:
* <ul>
* <li> host</li>
* <li> port (optional)</li>
* <li> SSLEnabled (optional)</li>
* </ul>
*
* @author Bill Lynch
* @author loki der quaeler
*/
public class JiveChatServlet
extends HttpServlet
implements HttpSessionListener, PacketListener {
static public final String JIVE_WEB_CHAT_RESOURCE_NAME = "WebChat";
static protected long PACKET_RESPONSE_TIMEOUT_MS = 5000;
static protected String CHAT_LAUNCHER_URI_SUFFIX = "/chat-launcher.jsp";
static protected String CREATE_ACCOUNT_URI = "/account_creation.jsp";
static protected String LOGIN_URI = "/index.jsp";
static protected String ERRORS_ATTRIBUTE_STRING = "messenger.servlet.errors";
static protected String NICKNAME_ATTRIBUTE_STRING = "messenger.servlet.nickname";
static protected String ROOM_ATTRIBUTE_STRING = "messenger.servlet.room";
static protected String HOST_PARAM_STRING = "host";
static protected String PORT_PARAM_STRING = "port";
static protected String SSL_PARAM_STRING = "SSLEnabled";
static protected String COMMAND_PARAM_STRING = "command";
static protected String NICKNAME_PARAM_STRING = "nickname";
static protected String PASSWORD_PARAM_STRING = "password";
static protected String RETYPED_PASSWORD_PARAM_STRING = "password_zwei";
static protected String ROOM_PARAM_STRING = "room";
static protected String USERNAME_PARAM_STRING = "username";
static protected String ANON_LOGIN_COMMAND_STRING = "anon_login";
static protected String CREATE_ACCOUNT_COMMAND_STRING = "create_account";
static protected String LOGIN_COMMAND_STRING = "login";
static protected String LOGOUT_COMMAND_STRING = "logout";
static protected String READ_COMMAND_STRING = "read";
static protected String SILENCE_COMMAND_STRING = "silence";
static protected String WRITE_COMMAND_STRING = "write";
static protected String MESSAGE_REQUEST_STRING = "message";
// is this value used elsewhere? (if not, why a string?) PENDING
static protected String ERROR_RETURN_CODE_STRING = "error";
static protected String SUCCESS_RETURN_CODE_STRING = "success";
// k/v :: S(session id) / ChatData
static protected Map SESSION_CHATDATA_MAP = new HashMap();
// k/v :: S(unique root of packet ids) / ChatData
static protected Map PACKET_ROOT_CHATDATA_MAP = new HashMap();
static protected EmoticonFilter EMOTICONFILTER = new EmoticonFilter();
static protected URLTranscoder URLTRANSCODER = new URLTranscoder();
protected String host;
protected int port;
protected boolean sslEnabled;
public void init (ServletConfig config)
throws ServletException {
ServletContext context = null;
String portParameter = null;
super.init(config);
// XMPPConnection.DEBUG_ENABLED = true;
context = config.getServletContext();
this.host = context.getInitParameter(HOST_PARAM_STRING);
if (this.host == null) {
throw new ServletException("Init parameter \"" + HOST_PARAM_STRING + "\" must be set.");
}
this.port = -1;
portParameter = context.getInitParameter(PORT_PARAM_STRING);
if (portParameter != null) {
try {
this.port = Integer.parseInt(portParameter);
} catch (NumberFormatException nfe) {
throw new ServletException("Init parameter \"" + PORT_PARAM_STRING
+ "\" must be a valid number.", nfe);
}
}
this.sslEnabled
= Boolean.valueOf(context.getInitParameter(SSL_PARAM_STRING)).booleanValue();
}
/**
* Take care of closing down everything we're holding on to, then bubble up the destroy
* to our superclass.
*/
public void destroy () {
synchronized (SESSION_CHATDATA_MAP) {
for (Iterator i = SESSION_CHATDATA_MAP.values().iterator(); i.hasNext(); ) {
ChatData chatData = (ChatData)i.next();
if (chatData.groupChat != null) {
chatData.groupChat.leave();
}
chatData.connection.close();
}
}
super.destroy();
}
protected void service (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
String sessionID = session.getId();
String path = request.getContextPath();
String command = request.getParameter(COMMAND_PARAM_STRING);
if (READ_COMMAND_STRING.equals(command)) {
ChatData chatData = (ChatData)SESSION_CHATDATA_MAP.get(sessionID);
StringBuffer reply = null;
boolean foundData = false;
Message message = null;
int i = 0;
if (chatData == null) {
this.writeData("Must login first.", response);
return;
}
reply = new StringBuffer();
reply.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
reply.append("<html><head><title>Chat Read Page</title>\n");
reply.append("<meta http-equiv=\"refresh\" content=\"2\">\n");
reply.append("<script language=\"Javascript\" src=\"common.js\"></script>");
reply.append("<script language=\"JavaScript\" type=\"text/javascript\">\n");
reply.append(" var nickname = \"");
reply.append(request.getSession().getAttribute(NICKNAME_ATTRIBUTE_STRING));
reply.append("\";\n");
message = chatData.groupChat.pollMessage();
while (message != null) {
String from = message.getFrom();
String body = message.getBody();
// Get the the user's nickname
from = StringUtils.parseResource(from);
// PENDING - stop using the replace method
// encode the HTML special characters
body = this.replace(body, "&", "&amp;");
body = this.replace(body, "<", "&lt;");
body = this.replace(body, ">", "&gt;");
// replace newlines in the body:
body = this.replace(body, "\r", "");
body = this.replace(body, "\n", "<br>");
// encode the quotes
body = this.replace(body, "\"", "&quot;");
// encode the embedded urls
body = URLTRANSCODER.encodeURLsInText(body);
// Apply emoticons
body = EMOTICONFILTER.applyFilter(body);
if (from.length() == 0) {
reply.append(" var body").append(i).append(" = \"").append(body);
reply.append("\";\n addChatText(body").append(i).append(", true);\n");
} else {
reply.append(" var from").append(i).append(" = \"").append(from);
reply.append("\";\n var body").append(i).append(" = \"").append(body);
reply.append("\";\n addUserName(from").append(i);
reply.append(");\n addChatText(body").append(i).append(", false);\n");
}
message = chatData.groupChat.pollMessage();
foundData = true;
i++;
}
synchronized (chatData.newJoins) {
synchronized (chatData.newDepartures) {
Iterator it = chatData.newJoins.iterator();
i = 0;
while (it.hasNext()) {
reply.append(" var joined").append(i).append(" = \"").append(it.next());
reply.append("\";\n userJoined(joined").append(i).append(");\n");
i++;
}
i = 0;
it = chatData.newDepartures.iterator();
while (it.hasNext()) {
reply.append(" var departed").append(i).append(" = \"").append(it.next());
reply.append("\";\n userDeparted(departed").append(i).append(");\n");
i++;
}
chatData.newJoins.clear();
chatData.newDepartures.clear();
}
}
reply.append("</script>\n</head><body></body></html>");
this.writeData(reply.toString(), response);
} else if (WRITE_COMMAND_STRING.equals(command)) {
String message = request.getParameter(MESSAGE_REQUEST_STRING);
ChatData chatData = (ChatData)SESSION_CHATDATA_MAP.get(sessionID);
if (message == null) {
this.writeData("Parameter \"" + MESSAGE_REQUEST_STRING + "\" is required.",
response);
return;
} else if (chatData == null) {
this.writeData("Must login first.", response);
return;
}
try {
StringBuffer reply = new StringBuffer();
chatData.groupChat.sendMessage(message.trim());
reply.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
reply.append("<html><head>\n");
reply.append(
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
reply.append("<title>Chat Form</title>");
reply.append("</head><body>\n");
reply.append("<form name=\"chatform\" action=\"").append(path);
reply.append("/ChatServlet\" method=\"post\">\n");
reply.append("<input type=\"hidden\" name=\"command\" value=\"write\">\n");
reply.append("<input type=\"hidden\" name=\"message\" value=\"\">\n");
reply.append("</form></body></html>");
this.writeData(reply.toString(), response);
} catch (XMPPException e) {
// PENDING - better handling
e.printStackTrace();
}
} else if (LOGOUT_COMMAND_STRING.equals(command)) {
ChatData chatData = null;
synchronized (SESSION_CHATDATA_MAP) {
chatData = (ChatData)SESSION_CHATDATA_MAP.remove(sessionID);
}
if (chatData != null) {
if (chatData.groupChat != null) {
chatData.groupChat.leave();
}
synchronized (PACKET_ROOT_CHATDATA_MAP) {
Packet p = new IQ();
String root = this.getPacketIDRoot(p);
PACKET_ROOT_CHATDATA_MAP.remove(root);
}
chatData.connection.close();
}
} else if (ANON_LOGIN_COMMAND_STRING.equals(command)) {
String returnCode = this.handleLogin(request, true);
if (SUCCESS_RETURN_CODE_STRING.equals(returnCode)) {
response.sendRedirect(path + CHAT_LAUNCHER_URI_SUFFIX);
} else {
// error, return to the original page to display errors and allow re-attempts
RequestDispatcher rd = request.getRequestDispatcher(LOGIN_URI);
rd.forward(request, response);
}
} else if (LOGIN_COMMAND_STRING.equals(command)) {
String returnCode = this.handleLogin(request, false);
if (SUCCESS_RETURN_CODE_STRING.equals(returnCode)) {
response.sendRedirect(path + CHAT_LAUNCHER_URI_SUFFIX);
} else {
// error, return to the original page to display errors and allow re-attempts
RequestDispatcher rd = request.getRequestDispatcher(LOGIN_URI);
rd.forward(request, response);
}
} else if (CREATE_ACCOUNT_COMMAND_STRING.equals(command)) {
String returnCode = this.createAccount(request);
if (SUCCESS_RETURN_CODE_STRING.equals(returnCode)) {
response.sendRedirect(path + LOGIN_URI);
} else {
// error, return to the original page to display errors and allow re-attempts
RequestDispatcher rd = request.getRequestDispatcher(CREATE_ACCOUNT_URI);
rd.forward(request, response);
}
} else if (SILENCE_COMMAND_STRING.equals(command)) {
// do nothing
} else if (command != null) {
this.writeData(("Invalid command: " + command), response);
} else {
this.writeData("Jive Messenger Chat Servlet", response);
}
}
protected String getPacketIDRoot (Packet p) {
if (p == null) {
return null;
}
return p.getPacketID().substring(0, 5);
}
/**
* Creates an account for the user data specified.
*/
private String createAccount (HttpServletRequest request) {
String sessionID = request.getSession().getId();
String username = request.getParameter(USERNAME_PARAM_STRING);
String password = request.getParameter(PASSWORD_PARAM_STRING);
String retypedPassword = request.getParameter(RETYPED_PASSWORD_PARAM_STRING);
Map errors = new HashMap();
// PENDING: validate already taken username
if ((username == null) || (username.trim().length() == 0)) {
errors.put("empty_username", "");
}
if ((password == null) || (password.trim().length() == 0)) {
errors.put("empty_password", "");
}
if ((retypedPassword == null) || (retypedPassword.trim().length() == 0)) {
errors.put("empty_password_two", "");
}
if ((retypedPassword != null) && (password != null)
&& (! retypedPassword.equals(password))) {
errors.put("mismatch_password", "");
}
// If there were no errors, continue
if (errors.size() == 0) {
ChatData chatData = (ChatData)SESSION_CHATDATA_MAP.get(sessionID);
// If a connection already exists for this session, close it before creating
// another.
if (chatData != null) {
if (chatData.groupChat != null) {
chatData.groupChat.leave();
}
chatData.connection.close();
}
chatData = new ChatData();
try {
AccountManager am = null;
// Create connection.
if (! this.sslEnabled) {
if (port != -1) {
chatData.connection = new XMPPConnection(this.host, this.port);
} else {
chatData.connection = new XMPPConnection(this.host);
}
} else {
if (port != -1) {
chatData.connection = new SSLXMPPConnection(this.host, this.port);
}
else {
chatData.connection = new SSLXMPPConnection(this.host);
}
}
am = chatData.connection.getAccountManager();
// PENDING check whether the server even supports account creation
am.createAccount(username, password);
} catch (XMPPException e) {
errors.put("general", "The server reported an error in account creation: "
+ e.getXMPPError().getMessage());
}
}
if (errors.size() > 0) {
request.setAttribute(ERRORS_ATTRIBUTE_STRING, errors);
return ERROR_RETURN_CODE_STRING;
}
return SUCCESS_RETURN_CODE_STRING;
}
/**
* Handles login logic.
*/
private String handleLogin (HttpServletRequest request, boolean anonymous) {
String sessionID = request.getSession().getId();
String username = request.getParameter(USERNAME_PARAM_STRING);
String password = request.getParameter(PASSWORD_PARAM_STRING);
String room = request.getParameter(ROOM_PARAM_STRING);
String nickname = request.getParameter(NICKNAME_PARAM_STRING);
Map errors = new HashMap();
// Validate parameters
if ((! anonymous) && ((username == null) || (username.trim().length() == 0))) {
errors.put(USERNAME_PARAM_STRING, "");
}
if ((! anonymous) && ((password == null) || (password.trim().length() == 0))) {
errors.put(PASSWORD_PARAM_STRING, "");
}
if ((room == null) || (room.trim().length() == 0)) {
errors.put(ROOM_PARAM_STRING, "");
}
if ((nickname == null) || (nickname.trim().length() == 0)) {
errors.put(NICKNAME_PARAM_STRING, "");
}
// If there were no errors, continue
if (errors.size() == 0) {
ChatData chatData = (ChatData)SESSION_CHATDATA_MAP.get(sessionID);
// If a connection already exists for this session, close it before creating
// another.
if (chatData != null) {
if (chatData.groupChat != null) {
chatData.groupChat.leave();
}
chatData.connection.close();
}
chatData = new ChatData();
try {
// Create connection.
if (! this.sslEnabled) {
if (port != -1) {
chatData.connection = new XMPPConnection(this.host, this.port);
} else {
chatData.connection = new XMPPConnection(this.host);
}
} else {
if (port != -1) {
chatData.connection = new SSLXMPPConnection(this.host, this.port);
}
else {
chatData.connection = new SSLXMPPConnection(this.host);
}
}
if (anonymous) {
Authentication a = new Authentication();
PacketCollector pc = chatData.connection.createPacketCollector(
new PacketIDFilter(a.getPacketID()));
Authentication responsePacket = null;
a.setType(IQ.Type.SET);
chatData.connection.sendPacket(a);
responsePacket = (Authentication)pc.nextResult(PACKET_RESPONSE_TIMEOUT_MS);
if (responsePacket == null) {
// throw new XMPPException("No response from the server.");
}
// check for error response
pc.cancel();
// since GroupChat isn't setting the 'from' in it's message sends,
// i can't see a problem in not doing anything with the unique resource
// we've just been given by the server. if GroupChat starts setting the
// from, it would probably grab the information from the XMPPConnection
// instance it holds, and as such we would then need to introduce the
// concept of anonymous logins to XMPPConnection, or tell GroupChat what
// to do what username is null or blank but a resource exists... PENDING
} else {
chatData.connection.login(username, password, JIVE_WEB_CHAT_RESOURCE_NAME);
}
chatData.connection.addPacketListener(this,
new PacketTypeFilter(Presence.class));
synchronized (SESSION_CHATDATA_MAP) {
SESSION_CHATDATA_MAP.put(sessionID, chatData);
}
synchronized (PACKET_ROOT_CHATDATA_MAP) {
Packet p = new IQ();
String root = this.getPacketIDRoot(p);
// PENDING -- we won't do anything with this packet, so it will ultimately look
// to the server as though a packet has disappeared -- is this ok with the
// server?
PACKET_ROOT_CHATDATA_MAP.put(root, chatData);
}
// Join groupChat room.
chatData.groupChat = chatData.connection.createGroupChat(room);
chatData.groupChat.join(nickname);
// Put the user's nickname in the session - this is used by the view to correctly
// display the user's messages in a different color:
request.getSession().setAttribute(NICKNAME_ATTRIBUTE_STRING, nickname);
request.getSession().setAttribute(ROOM_ATTRIBUTE_STRING, room);
} catch (XMPPException e) {
XMPPError err = e.getXMPPError();
errors.put("general", ((err != null) ? err.getMessage() : e.getMessage()));
if (chatData.groupChat != null) {
chatData.groupChat.leave();
}
}
}
if (errors.size() > 0) {
request.setAttribute(ERRORS_ATTRIBUTE_STRING, errors);
return ERROR_RETURN_CODE_STRING;
}
return SUCCESS_RETURN_CODE_STRING;
}
private void writeData (String data, HttpServletResponse response) {
try {
PrintWriter responseWriter = response.getWriter();
response.setContentType("text/html");
responseWriter.println(data);
responseWriter.close();
} catch (IOException ioe) {
// PENDING
}
}
// a hack class to hold a data glom (really hacky)
private class ChatData {
private XMPPConnection connection;
private GroupChat groupChat;
private Set newJoins = new HashSet();
private Set newDepartures = new HashSet();
}
/**
* Replaces all instances of oldString with newString in string.
*
* PENDING - why is this final?
* PENDING - take this out -- it fails under some cases...
*
* @param string the String to search to perform replacements on
* @param oldString the String that should be replaced by newString
* @param newString the String that will replace all instances of oldString
*
* @return a String will all instances of oldString replaced by newString
*/
static public final String replace (String string, String oldString, String newString) {
int i = 0;
// MAY RETURN THIS BLOCK
if (string == null) {
return null;
}
if (newString == null) {
return string;
}
// Make sure that oldString appears at least once before doing any processing.
if (( i=string.indexOf(oldString, i)) >= 0) {
// Use char []'s, as they are more efficient to deal with.
char[] string2 = string.toCharArray();
char[] newString2 = newString.toCharArray();
int oLength = oldString.length();
StringBuffer buf = new StringBuffer(string2.length);
int j = 1;
buf.append(string2, 0, i).append(newString2);
i += oLength;
// Replace all remaining instances of oldString with newString.
while ((i=string.indexOf(oldString, i)) > 0) {
buf.append(string2, j, (i - j)).append(newString2);
i += oLength;
j = i;
}
buf.append(string2, j, (string2.length - j));
return buf.toString();
}
return string;
}
/**
*
* HttpSessionListener implementation
*
*/
public void sessionCreated (HttpSessionEvent event) { }
public void sessionDestroyed (HttpSessionEvent event) {
String sessionID = event.getSession().getId();
ChatData chatData = null;
synchronized (SESSION_CHATDATA_MAP) {
chatData = (ChatData)SESSION_CHATDATA_MAP.remove(sessionID);
}
if (chatData != null) {
if (chatData.groupChat != null) {
chatData.groupChat.leave();
}
synchronized (PACKET_ROOT_CHATDATA_MAP) {
Packet p = new IQ();
String root = this.getPacketIDRoot(p);
PACKET_ROOT_CHATDATA_MAP.remove(root);
}
chatData.connection.close();
}
}
/**
*
* PacketListener implementation
*
*/
public void processPacket (Packet packet) {
Presence presence = (Presence)packet;
String root = null;
ChatData chatData = null;
String userName = null;
// MAY RETURN THIS BLOCK
if (presence.getMode() == Presence.Mode.INVISIBLE) {
return;
}
root = this.getPacketIDRoot(presence);
chatData = (ChatData)PACKET_ROOT_CHATDATA_MAP.get(root);
// MAY RETURN THIS BLOCK
if (chatData == null) {
return;
}
userName = StringUtils.parseResource(packet.getFrom());
if (presence.getType() == Presence.Type.UNAVAILABLE) {
synchronized (chatData.newDepartures) {
synchronized (chatData.newJoins) {
chatData.newJoins.remove(userName);
chatData.newDepartures.add(userName);
}
}
} else if (presence.getType() == Presence.Type.AVAILABLE) {
synchronized (chatData.newJoins) {
synchronized (chatData.newDepartures) {
chatData.newDepartures.remove(userName);
chatData.newJoins.add(userName);
}
}
}
}
}

View File

@ -0,0 +1,126 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 1999-2002 CoolServlets, Inc. All rights reserved.
*
* This software is the proprietary information of CoolServlets, Inc.
* Use is subject to license terms.
*/
package org.jivesoftware.webchat;
/**
* A Filter that replaces [b][/b], [i][/i], [u][/u], [pre][/pre] tags with their HTML
* tag equivalents.
*/
public class TextStyle {
public String applyFilter(String string) {
if (string == null || string.length() == 0) {
return string;
}
// To figure out how many times we've made text replacements, we
// need to pass around integer count objects.
int[] boldStartCount = new int[1];
int[] italicsStartCount = new int[1];
int[] boldEndCount = new int[1];
int[] italicsEndCount = new int[1];
int[] underlineStartCount = new int[1];
int[] underlineEndCount = new int[1];
int[] preformatStartCount = new int[1];
int[] preformatEndCount = new int[1];
// Bold
string = replaceIgnoreCase(string, "[b]", "<b>", boldStartCount);
string = replaceIgnoreCase(string, "[/b]", "</b>", boldEndCount);
int bStartCount = boldStartCount[0];
int bEndCount = boldEndCount[0];
while (bStartCount > bEndCount) {
string = string.concat("</b>");
bEndCount++;
}
// Italics
string = replaceIgnoreCase(string, "[i]", "<i>", italicsStartCount);
string = replaceIgnoreCase(string, "[/i]", "</i>", italicsEndCount);
int iStartCount = italicsStartCount[0];
int iEndCount = italicsEndCount[0];
while (iStartCount > iEndCount) {
string = string.concat("</i>");
iEndCount++;
}
// Underline
string = replaceIgnoreCase(string, "[u]", "<u>", underlineStartCount);
string = replaceIgnoreCase(string, "[/u]", "</u>", underlineEndCount);
int uStartCount = underlineStartCount[0];
int uEndCount = underlineEndCount[0];
while (uStartCount > uEndCount) {
string = string.concat("</u>");
uEndCount++;
}
// Pre
string = replaceIgnoreCase(string, "[pre]", "<pre>", preformatStartCount);
string = replaceIgnoreCase(string, "[/pre]", "</pre>", preformatEndCount);
int preStartCount = preformatStartCount[0];
int preEndCount = preformatEndCount[0];
while (preStartCount > preEndCount) {
string = string.concat("</pre>");
preEndCount++;
}
return string;
}
/**
* Replaces all instances of oldString with newString in line with the
* added feature that matches of newString in oldString ignore case.
* The count paramater is set to the number of replaces performed.
*
* @param line the String to search to perform replacements on
* @param oldString the String that should be replaced by newString
* @param newString the String that will replace all instances of oldString
* @param count a value that will be updated with the number of replaces
* performed.
*
* @return a String will all instances of oldString replaced by newString
*/
private static final String replaceIgnoreCase(String line, String oldString,
String newString, int [] count)
{
if (line == null) {
return null;
}
String lcLine = line.toLowerCase();
String lcOldString = oldString.toLowerCase();
int i=0;
if ((i=lcLine.indexOf(lcOldString, i)) >= 0) {
int counter = 1;
char [] line2 = line.toCharArray();
char [] newString2 = newString.toCharArray();
int oLength = oldString.length();
StringBuffer buf = new StringBuffer(line2.length);
buf.append(line2, 0, i).append(newString2);
i += oLength;
int j = i;
while ((i=lcLine.indexOf(lcOldString, i)) > 0) {
counter++;
buf.append(line2, j, i-j).append(newString2);
i += oLength;
j = i;
}
buf.append(line2, j, line2.length - j);
count[0] = counter;
return buf.toString();
}
return line;
}
}

View File

@ -0,0 +1,312 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 1999-2002 CoolServlets, Inc. All rights reserved.
*
* This software is the proprietary information of CoolServlets, Inc.
* Use is subject to license terms.
*/
package org.jivesoftware.webchat;
import java.util.*;
/**
* A Filter that converts URL's to working HTML web links.<p>
*
* The default set of patterns recognized are <code>ftp://path-of-url</code>,
* <code>http://path-of-url</code>, <code>https://path-of-url</code> but can be expanded upon.<p>
*
* In addition, the following patterns are also recognized.
*
* <code>[url path-of-url]descriptive text[/url]</code> and
* <code>[url=path-of-url]descriptive text[/url]</code>.<p>
*
* The <code>[url]</code> allows any path to be defined as link.
*/
public class URLFilter{
private ArrayList schemes = new ArrayList();
// define a preset default set of schemes
public URLFilter() {
schemes.add("http://");
schemes.add("https://");
schemes.add("ftp://");
}
public String applyFilter(String string) {
if (string == null || string.length() == 0) {
return string;
}
int length = string.length();
StringBuffer filtered = new StringBuffer((int) (length * 1.5));
ArrayList urlBlocks = new ArrayList(5);
// search for url's such as [url=..]text[/url] or [url ..]text[/url]
int start = string.indexOf("[url");
while (start != -1 && (start + 5 < length)) {
// check to verify we're not in another block
if (withinAnotherBlock(urlBlocks, start)) {
start = string.indexOf("[url", start + 5);
continue;
}
int end = string.indexOf("[/url]", start + 5);
if (end == -1 || end >= length) {
// went past end of string, skip
break;
}
String u = string.substring(start, end + 6);
int startTagClose = u.indexOf(']');
String url;
String description;
if (startTagClose > 5) {
url = u.substring(5, startTagClose);
description = u.substring(startTagClose + 1, u.length() - 6);
// Check the user entered URL for a "javascript:" or "file:" link. Only
// append the user entered link if it doesn't contain 'javascript:' and 'file:'
String lcURL = url.toLowerCase();
if (lcURL.indexOf("javascript:") == -1 && lcURL.indexOf("file:") == -1) {
URLBlock block = new URLBlock(start, end + 5, url, description);
urlBlocks.add(block);
}
}
else {
url = description = u.substring(startTagClose + 1, u.length() - 6);
// Check the user entered URL for a "javascript:" or "file:" link. Only
// append the user entered link if it doesn't contain 'javascript:' and 'file:'
String lcURL = url.toLowerCase();
if (lcURL.indexOf("javascript:") == -1 && lcURL.indexOf("file:") == -1) {
URLBlock block = new URLBlock(start, end + 5, url);
urlBlocks.add(block);
}
}
start = string.indexOf("[url", end + 6);
}
// now handle all the other urls
Iterator iter = schemes.iterator();
while (iter.hasNext()) {
String scheme = (String) iter.next();
start = string.indexOf(scheme, 0);
while (start != -1) {
int end = start;
// check context, don't handle patterns preceded by any of '"<=
if (start > 0) {
char c = string.charAt(start - 1);
if (c == '\'' || c == '"' || c == '<' || c == '=') {
start = string.indexOf(scheme, start + scheme.length());
continue;
}
}
// check to verify we're not in another block
if (withinAnotherBlock(urlBlocks, start)) {
start = string.indexOf(scheme, start + scheme.length());
continue;
}
// find the end of the url
int cur = start + scheme.length();
while (end == start && cur < length) {
char c = string.charAt(cur);
switch (c) {
case ' ':
end = cur;
break;
case '\t':
end = cur;
break;
case '\'':
end = cur;
break;
case '\"':
end = cur;
break;
case '<':
end = cur;
break;
case '[':
end = cur;
break;
case '\n':
end = cur;
break;
case '\r':
end = cur;
break;
default:
// acceptable character
}
cur++;
}
// if this is true it means the url goes to the end of the string
if (end == start) {
end = length - 1;
}
URLBlock block = new URLBlock(start, end-1, string.substring(start, end));
urlBlocks.add(block);
start = string.indexOf(scheme, end);
}
}
// sort the blocks so that they are in start index order
sortBlocks(urlBlocks);
// now, markup the urls and pass along the filter chain the rest
Iterator blocks = urlBlocks.iterator();
int last = 0;
while (blocks.hasNext()) {
URLBlock block = (URLBlock) blocks.next();
if (block.getStart() > 0) {
filtered.append(string.substring(last, block.getStart()));
}
last = block.getEnd() + 1;
filtered.append("<a href='").append(block.getUrl()).append("' target='_blank'>");
if (block.getDescription().length() > 0) {
filtered.append(block.getDescription());
}
else {
filtered.append(block.getUrl());
}
filtered.append("</a>");
}
if (last < string.length() - 1) {
filtered.append(string.substring(last));
}
return filtered.toString();
}
/**
* Returns the current supported uri schemes as a comma seperated string.
*
* @return the current supported uri schemes as a comma seperated string.
*/
public String getSchemes() {
StringBuffer buf = new StringBuffer(50);
for (int i = 0; i < schemes.size(); i++) {
buf.append((String) schemes.get(i)).append(",");
}
buf.deleteCharAt(buf.length() - 1);
return buf.toString();
}
/**
* Sets the current supported uri schemes as a comma seperated string.
*
* @param schemes a comma seperated string of uri schemes.
*/
public void setSchemes(String schemes) {
if (schemes == null) {
return;
}
// enpty the current list
this.schemes.clear();
StringTokenizer st = new StringTokenizer(schemes, ",");
while (st.hasMoreElements()) {
this.schemes.add(st.nextElement());
}
}
private void sortBlocks(ArrayList blocks) {
Collections.sort(blocks, new Comparator() {
public int compare(Object object1, Object object2) {
URLBlock b1 = (URLBlock) object1;
URLBlock b2 = (URLBlock) object2;
return (b1.getStart() > b2.getStart()) ? 1 : -1;
}
});
}
private boolean withinAnotherBlock(List blocks, int start) {
for (int i = 0; i < blocks.size(); i++) {
URLBlock block = (URLBlock) blocks.get(i);
if (start >= block.getStart() && start < block.getEnd()) {
return true;
}
}
return false;
}
class URLBlock {
int start = 0;
int end = 0;
String description = "";
String url = "";
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
URLBlock(int start, int end, String url) {
this.start = start;
this.end = end;
this.url = url;
}
URLBlock(int start, int end, String url, String description) {
this.start = start;
this.end = end;
this.description = description;
this.url = url;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
}
}

View File

@ -0,0 +1,188 @@
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 1999-2003 Jive Software. All rights reserved.
*
* This software is the proprietary information of Jive Software.
* Use is subject to license terms.
*/
package org.jivesoftware.webchat;
import java.util.*;
/**
* This is a really good example of why software development projects have frameworks, and the
* other apps in their own modules that sit on top of the frameworks... this class should not
* be confused with com.jivesoftware.messenger.operator.util.URLTranscoder, which does a
* variant of the functionality found here.<br>
*
* The default set of patterns recognized are <code>ftp://path-of-url</code>,
* <code>http://path-of-url</code>, <code>https://path-of-url</code> but can be expanded upon.</br>
*
* This was originally URLTranscoder, from CoolServlets, but that class did basically nothing that
* i wanted, so i kept the schemes collection and that was about it.<br>
*
* @author loki der quaeler
*/
public class URLTranscoder {
static protected final String A_HREF_PREFIX = "<a href='";
static protected final String A_HREF_SUFFIX = "' target=_new>";
static protected final String A_HREF_CLOSING_TAG = "</a>";
protected ArrayList schemes;
public URLTranscoder () {
super();
this.schemes = new ArrayList();
this.schemes.add("http://");
this.schemes.add("https://");
this.schemes.add("ftp://");
}
/**
* Sets the current supported uri schemes.
*
* @param schemeCollection a collection of String instances of uri schemes.
*/
public synchronized void setSchemes (Collection schemeCollection) {
// MAY EXIT THIS BLOCK
if (schemes == null) {
return;
}
this.schemes.clear();
this.schemes.addAll(schemeCollection);
}
/**
* Returns a String based off the original text, but now with any a.href blocks html-ized
* inside. (for example, supplying the string "this: http://dict.leo.org/ is a cool url"
* returns "this: <a href='http://dict.leo.org/' target=_new>http://dict.leo.org/</a>
* is a cool url"
*/
public String encodeURLsInText (String text) {
StringBuffer rhett = null;;
List runs = this.getURLRunsInString(text);
Iterator it = null;
int lastStart = 0;
// MAY RETURN THIS BLOCK
if (runs.size() == 0) {
return text;
}
rhett = new StringBuffer();
it = runs.iterator();
while (it.hasNext()) {
URLRun run = (URLRun)it.next();
String url = text.substring(run.getStartIndex(), run.getEndIndex());
if (lastStart < run.getStartIndex()) {
rhett.append(text.substring(lastStart, run.getStartIndex()));
lastStart += run.getEndIndex();
}
rhett.append(A_HREF_PREFIX).append(url).append(A_HREF_SUFFIX).append(url);
rhett.append(A_HREF_CLOSING_TAG);
}
if (lastStart < text.length()) {
rhett.append(text.substring(lastStart, text.length()));
}
return rhett.toString();
}
protected List getURLRunsInString (String text) {
ArrayList rhett = new ArrayList();
Vector vStarts = new Vector();
Iterator sIt = this.schemes.iterator();
Integer[] iStarts = null;
char[] tArray = null;
while (sIt.hasNext()) {
String scheme = (String)sIt.next();
int index = text.indexOf(scheme);
while (index != -1) {
vStarts.add(new Integer(index));
index = text.indexOf(scheme, (index + 1));
}
}
// MAY RETURN THIS BLOCK
if (vStarts.size() == 0) {
return rhett;
}
iStarts = (Integer[])vStarts.toArray(new Integer[0]);
Arrays.sort(iStarts);
tArray = text.toCharArray();
for (int i = 0; i < iStarts.length; i++) {
int start = iStarts[i].intValue();
int end = start + 1;
while ((end < tArray.length) && (! this.characterIsURLTerminator(tArray[end]))) {
end++;
}
if (end == tArray.length) {
end--;
}
rhett.add(new URLRun(start, end));
}
return rhett;
}
protected boolean characterIsURLTerminator (char c) {
switch (c) {
case ' ':
case '\n':
case '(':
case ')':
case '>':
case '\t':
case '\r': return true;
}
return false;
}
protected class URLRun {
protected int start;
protected int end;
protected URLRun (int s, int e) {
super();
this.start = s;
this.end = e;
}
protected int getStartIndex () {
return this.start;
}
protected int getEndIndex () {
return this.end;
}
}
}

View File

@ -0,0 +1,116 @@
<%--
-
-
--%>
<%@ page import="java.util.*" %>
<% // Get error map as a request attribute:
Map errors = (Map)request.getAttribute("messenger.servlet.errors");
if (errors == null) { errors = new HashMap(); }
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Create an account</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/style_sheet.jsp"
type="text/css">
</head>
<body class="deffr">
<table width="100%" height="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="center" valign="middle">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<h3>Jive Account Creation</h3>
<% if (errors.get("general") != null) { %>
<p>
<span class="error-text">
Error creating account. <%= errors.get("general") %>
</span>
</p>
<br>
<% } %>
</td>
</tr>
<tr>
<td align="center">
<form action="<%= request.getContextPath() %>/ChatServlet"
method="post" name="createform">
<input type="hidden" name="command" value="create_account">
<table cellpadding="2" cellspacing="0" border="0">
<tr>
<td>Desired username:</td>
<td>
<input type="text" size="40" name="username"
class="text">
<% if (errors.get("empty_username") != null) { %>
<span class="error-text"><br>
Please enter a username.
</span>
<% } %>
</td>
</tr>
<tr>
<td>Desired password:</td>
<td>
<input type="password" size="40" name="password"
class="text">
<% if (errors.get("empty_password") != null) { %>
<span class="error-text"><br>
Please enter a password.
</span>
<% } %>
<% if (errors.get("mismatch_password") != null) { %>
<span class="error-text"><br>
Your passwords did not match.
</span>
<% } %>
</td>
</tr>
<tr>
<td>Retype your password:</td>
<td>
<input type="password" size="40" name="password_zwei"
class="text">
<% if (errors.get("empty_password_two") != null) { %>
<span class="error-text"><br>
You must retype your password.
</span>
<% } %>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="center">
<br>
<input type="submit" name="" value="Create account"
class="submit">
</form>
</td>
</tr>
<tr>
<td align="center">
<br><a href="index.jsp">Click here to return to the login page.</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
<script language="JavaScript" type="text/javascript">
document.createform.username.focus();
</script>
</body>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Chat Form</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/style_sheet.jsp"
type="text/css">
</head>
<body>
<form name="chatform" action="<%= request.getContextPath() %>/ChatServlet" method="post">
<input type="hidden" name="command" value="write">
<input type="hidden" name="message" value="">
</form>
</body>
</html>

View File

@ -0,0 +1,39 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Web Chat Session</title>
<script language="JavaScript" type="text/javascript">
function launchWin() {
var newWin = window.open("frame_master.jsp", "chatWin",
"location=no,status=no,toolbar=no,personalbar=no,menubar=no,width=650,height=430");
}
</script>
<link rel="stylesheet" href="<%= request.getContextPath() %>/style_sheet.jsp"
type="text/css">
</head>
<body class="deffr" onload="launchWin();">
<h3>Chat Session Options</h3>
Your chat session should have already started. If for some reason it did
not, click <a href="#" onclick="launchWin(); return false;">this link</a>
to start your chat session.
<br><br>
Other options:
<ul>
<li><a href="email" onclick="alert('Coming soon'); return false;">Email Transcript</a>
<li><a href="index.jsp">Return to the login page.</a>
</ul>
</body>
</html>

View File

@ -0,0 +1,182 @@
function addChatText (someText, isAnnouncement) {
var yakDiv = window.parent.frames['yak'].document.getElementById('ytext');
var children = yakDiv.childNodes.length;
var appendFailed = false;
var spanElement = document.createElement("span");
if (! isAnnouncement) {
spanElement.setAttribute("class", "chat_text");
} else {
spanElement.setAttribute("class", "chat_announcement");
}
// it's easier to dump the possibily html-containing text into the innerHTML
// of the span element than deciphering and building sub-elements.
spanElement.innerHTML = someText;
try {
// various versions of IE crash out on this, and safari
yakDiv.appendChild(spanElement);
} catch (exception) {
appendFailed = true;
}
if (! appendFailed) {
// really make sure the browser appended
appendFailed = (children == yakDiv.childNodes.length);
}
if (appendFailed) {
// try this, the only way left
var inn = yakDiv.innerHTML;
inn += "<span class=\"";
inn += (isAnnouncement ? "chat_announcement\">" : "chat_text\">");
inn += someText + "</span><br>";
yakDiv.innerHTML = inn;
} else {
yakDiv.appendChild(document.createElement("br"));
}
scrollYakToEnd();
}
function addUserName (userName) {
var yakDiv = window.parent.frames['yak'].document.getElementById('ytext');
var children = yakDiv.childNodes.length;
var appendFailed = false;
var spanElement = document.createElement("span");
var userIsClientOwner = false;
var announcement = false;
if (userName == "") {
announcement = true;
spanElement.setAttribute("class", "chat_announcement");
userName = "room announcement";
} else if (userName == nickname) {
userIsClientOwner = true;
spanElement.setAttribute("class", "chat_owner");
} else {
spanElement.setAttribute("class", "chat_participant");
}
try {
spanElement.appendChild(document.createTextNode(userName + ": "));
// various versions of IE crash out on this, and safari
yakDiv.appendChild(spanElement);
} catch (exception) {
appendFailed = true;
}
if (! appendFailed) {
// really make sure the browser appended
appendFailed = (children == yakDiv.childNodes.length);
}
if (appendFailed) {
// try this, the only way left
var inn = yakDiv.innerHTML
inn += "<span class=\"";
if (announcement) {
inn += "chat_announcement"
} else if (userIsClientOwner) {
inn += "chat_owner";
} else {
inn += "chat_participant";
}
inn += "\">" + userName + ": </span>";
yakDiv.innerHTML = inn;
}
}
function scrollYakToEnd () {
var endDiv = window.parent.frames['yak'].document.getElementById('enddiv');
window.parent.frames['yak'].window.scrollTo(0, endDiv.offsetTop);
}
function userJoined (username) {
var parentDIV = window.parent.frames['participants'].document.getElementById('par__list');
var children = parentDIV.childNodes.length;
var appendFailed = false;
var divElement = document.createElement("div");
divElement.setAttribute("id", username);
try {
divElement.appendChild(document.createTextNode(username));
divElement.appendChild(document.createElement("br"));
parentDIV.appendChild(divElement);
} catch (exception) {
appendFailed = true;
}
if (! appendFailed) {
// really make sure the browser appended
appendFailed = (children == parentDIV.childNodes.length);
}
if (appendFailed) {
// try this, the only way left
var inn = parentDIV.innerHTML;
inn += "<div id=\"" + username + "\"> &middot; " + username + "<br></div>";
parentDIV.innerHTML = inn;
}
}
function userDeparted (username) {
var partDoc = window.parent.frames['participants'].document;
var parentDIV = partDoc.getElementById('par__list');
var userDIV = partDoc.getElementById(username);
var children = parentDIV.childNodes.length;
var removeFailed = false;
// MAY RETURN THIS BLOCK
if (userDIV == null) {
return;
}
try {
parentDIV.removeChild(userDIV);
} catch (exception) {
removeFailed = true;
}
if (! removeFailed) {
// really make sure the browser appended
removeFailed = (children == parentDIV.childNodes.length);
}
if (removeFailed) {
// try this, the only way left
var inn = parentDIV.innerHTML;
var openingTag = "<div id=\"" + username + "\">";
var index = inn.toLowerCase().indexOf(openingTag);
var patchedHTML = inn.substring(0, index);
var secondIndex = openingTag.length + username.length + 13;
patchedHTML += inn.substring(secondIndex, (inn.length));
parentDIV.innerHTML = inn;
}
}
function writeDate () {
var msg = "This frame loaded at: ";
var now = new Date();
msg += now + "<br><hr>";
document.write(msg);
}

View File

@ -0,0 +1,33 @@
<html>
<head>
<title><%= request.getSession().getAttribute("messenger.servlet.room") %>
- Jive Web Chat Client</title>
<script>
function frameSetLoaded () {
window.frames['poller'].location.href
= "<%= request.getContextPath() %>/ChatServlet?command=read";
}
function attemptLogout () {
window.frames['participants'].document.logout.submit();
}
</script>
<link rel="stylesheet" href="<%= request.getContextPath() %>/style_sheet.jsp"
type="text/css">
</head>
<frameset cols="*, 125" border="0" frameborder="0" framespacing="0"
onLoad="frameSetLoaded();" onUnload="attemptLogout();">
<frameset rows="0, 200, *, 0" border="0" frameborder="0" framespacing="0">
<frame name="submitter" src="chat-hiddenform.jsp" frameborder="0">
<frame name="yak" src="transcript_frame.html" frameborder="0">
<frame name="input" src="input_frame.jsp" frameborder="0">
<frame name="poller" src="" frameborder="0">
</frameset>
<frame name="participants" src="participants_frame.jsp" class="bordered_left">
</frameset>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

View File

@ -0,0 +1,164 @@
<%--
-
-
--%>
<%@ page import="java.util.*" %>
<% // Get error map as a request attribute:
Map errors = (Map)request.getAttribute("messenger.servlet.errors");
boolean allowAnonymous = true;
boolean allowAccountCreate = true;
boolean allowLogin = true;
String param = null;
if (errors == null) { errors = new HashMap(); }
param = application.getInitParameter("allowAnonymous");
if ((param != null) && (param.equalsIgnoreCase("false"))) {
allowAnonymous = false;
}
param = application.getInitParameter("allowAccountCreation");
if ((param != null) && (param.equalsIgnoreCase("false"))) {
allowAccountCreate = false;
}
param = application.getInitParameter("allowLogin");
if ((param != null) && (param.equalsIgnoreCase("false"))) {
allowLogin = false;
}
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Jive Web Chat Client Login</title>
<script language="JavaScript" type="text/javascript">
function submitForm (el) {
el.form.submit();
}
function anonClick () {
document.loginform.command.value = "anon_login";
return true;
}
</script>
<link rel="stylesheet" href="<%= request.getContextPath() %>/style_sheet.jsp"
type="text/css">
</head>
<body class="deffr">
<table width="100%" height="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="center" valign="middle">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<h3>Welcome to the Jive Web Chat Client - Please Login</h3>
<% if (errors.get("general") != null) { %>
<p class="error-text">
Error logging in. Make sure your username and
password are correct. <%= errors.get("general") %>
</p>
<% } %>
</td>
</tr>
<tr>
<td align="center">
<form action="<%= request.getContextPath() %>/ChatServlet"
method="post" name="loginform">
<input type="hidden" name="command" value="login">
<table cellpadding="2" cellspacing="0" border="0">
<% if (allowLogin) { %>
<tr>
<td>Username:</td>
<td>
<input type="text" size="40" name="username"
class="text">
<% if (errors.get("username") != null) { %>
<span class="error-text"><br>
Please enter a valid username.
</span>
<% } %>
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<input type="password" size="40" name="password"
class="text">
<% if (errors.get("password") != null) { %>
<span class="error-text"><br>
Please enter a valid password.
</span>
<% } %>
</td>
</tr>
<% } %>
<tr>
<td>Nickname:</td>
<td>
<input type="text" size="40" name="nickname"
class="text">
<% if (errors.get("nickname") != null) { %>
<span class="error-text"><br>
Please enter a nickname.
</span>
<% } %>
</td>
</tr>
<tr>
<td>Room:</td>
<td>
<input type="text" size="40" name="room"
value="test@chat.jivesoftware.com" class="text">
<% if (errors.get("room") != null) { %>
<span class="error-text"><br>
Please enter a valid room.
</span>
<% } %>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="center">
<br>
<% if (allowLogin) { %>
<input type="submit" name="" value="Login and Chat"
class="submit">
<% } %>
<% if (allowAnonymous) { %>
<input type="submit" name="" value="Anonymously Chat"
onClick="return anonClick();" class="submit">
<% } %>
</form>
</td>
</tr>
<% if (allowAccountCreate) { %>
<tr>
<td align="center">
<br>Don't have an account and would like to create one?
<a href="account_creation.jsp">Click here.</a>
</td>
</tr>
<% } %>
</table>
</td>
</tr>
</table>
<script language="JavaScript" type="text/javascript">
<% if (allowLogin) { %>
document.loginform.username.focus();
<% } else { %>
document.loginform.nickname.focus();
<% } %>
</script>
</body>
</html>

View File

@ -0,0 +1,75 @@
<%@ page import="javax.servlet.*" %>
<% // Get error map as a request attribute:
String logoFilename = application.getInitParameter("logoFilename");
if (logoFilename == null) {
logoFilename = "images/logo.gif";
}
%>
<html>
<head>
<meta http-equiv="expires" content="0">
<script>
function updateButtonState (textAreaElement) {
if (textAreaElement.value != '') {
textAreaElement.form.send.disabled = false;
} else {
textAreaElement.form.send.disabled = true;
}
}
function handleKeyEvent (event, textAreaElement) {
var form = textAreaElement.form;
var keyCode = event.keyCode;
if (keyCode == null) {
keyCode = event.which;
}
if (keyCode == 13) {
submitForm(form);
form.message.value = '';
}
updateButtonState(textAreaElement);
}
function submitForm (formElement) {
var textAreaElement = formElement.message;
var text = textAreaElement.value;
var sForm = window.parent.frames['submitter'].document.chatform;
sForm.message.value = text;
sForm.submit();
textAreaElement.value = '';
updateButtonState(textAreaElement);
return false;
}
</script>
<link rel="stylesheet" href="<%= request.getContextPath() %>/style_sheet.jsp"
type="text/css">
</head>
<body class="deffr">
<center>
<form name="chat" onsubmit="return submitForm(this);">
<textarea name="message"
onkeyup="handleKeyEvent(event, this);"
onchange="updateButtonState(this);"></textarea>
<br>
<input type="submit" name="send" value="Send" class="submit_right" disabled>
</form>
</center>
<img src="<%= logoFilename %>" class="logo">
</body>
</html>

View File

@ -0,0 +1,46 @@
<html>
<head>
<meta http-equiv="expires" content="0">
<script>
function verifyLogout () {
if (confirm("Are you sure you'd like to logout")) {
// hacky solution to avoid logging out twice due to parent frame's onUnload
try {
document.logout.command.value = "silence";
} catch (e) { }
window.parent.close();
return true;
}
return false;
}
</script>
<link rel="stylesheet" href="<%= request.getContextPath() %>/style_sheet.jsp"
type="text/css">
</head>
<body class="deffr">
<center>In the room:</center>
<br>
<hr width=67%>
<div id="par__list"> </div>
<form name="logout" action="<%= request.getContextPath() %>/ChatServlet" method="post">
<input type="hidden" name="command" value="logout">
</form>
<span class="logout">
<a href="<%= request.getContextPath() %>/ChatServlet?command=logout"
onclick="return verifyLogout();" >
<img src="images/logout-16x16.gif" border="0" class="logout"> Logout</a></span>
</body>
</html>

View File

@ -0,0 +1,132 @@
<% // Set the content type of the this page to be CSS
String contentType = "text/css";
String chatAnnouncementColor = application.getInitParameter("chat.announcement-color");
String chatOwnerLabelColor = application.getInitParameter("chat.owner-label-color");
String chatParticipantLabelColor = application.getInitParameter("chat.participant-label-color");
String chatTextColor = application.getInitParameter("chat.text-color");
String errorTextColor = application.getInitParameter("error.text-color");
String linkColor = application.getInitParameter("link.color");
String linkHoverColor = application.getInitParameter("link.hover-color");
String linkVisitedColor = application.getInitParameter("link.visited-color");
String bodyBGColor = application.getInitParameter("body.background-color");
String bodyTextColor = application.getInitParameter("body.text-color");
String frameDividerColor = application.getInitParameter("frame.divider-color");
String buttonColor = application.getInitParameter("button.color");
String buttonTextColor = application.getInitParameter("button.text-color");
String textFieldColor = application.getInitParameter("textfield.color");
String textFieldTextColor = application.getInitParameter("textfield.text-color");
response.setContentType(contentType);
if (chatAnnouncementColor == null) {
chatAnnouncementColor = "#009d00";
}
if (chatOwnerLabelColor == null) {
chatOwnerLabelColor = "#aa0000";
}
if (chatParticipantLabelColor == null) {
chatParticipantLabelColor = "#0000aa";
}
if (chatTextColor == null) {
chatTextColor = "#434343";
}
if (errorTextColor == null) {
errorTextColor = "#ff0000";
}
if (linkColor == null) {
linkColor = "#045d30";
}
if (linkHoverColor == null) {
linkHoverColor = "#350000";
}
if (linkVisitedColor == null) {
linkVisitedColor = "#3b3757";
}
if (bodyBGColor == null) {
bodyBGColor = "#ffffff";
}
if (bodyTextColor == null) {
bodyTextColor = "#362f2d";
}
if (frameDividerColor == null) {
frameDividerColor = "#83272b";
}
if (buttonColor == null) {
buttonColor = "#d6dfdf";
}
if (buttonTextColor == null) {
buttonTextColor = "#333333";
}
if (textFieldColor == null) {
textFieldColor = "#f7f7fb";
}
if (textFieldTextColor == null) {
textFieldTextColor = "#333333";
}
%>
BODY, TD, TH { font-family : Tahoma, Arial, Verdana, sans serif; font-size: 13px; }
H3 { font-size : 1.2em; }
.error-text { color : <%= errorTextColor %>; }
/* default unvisited, visited and hover link presentation */
A:link { background: transparent; color: <%= linkColor %>;
text-decoration: none; }
A:visited { background: transparent; color: <%= linkVisitedColor %>;
text-decoration: none; }
A:hover { background: transparent; color: <%= linkHoverColor %>;
text-decoration: underline; }
/**
* site wide BODY style rule; the scrollbar stuff only works in IE for windows,
* but doesn't seem to hurt on other browsers..
*/
BODY.deffr { background-color: <%= bodyBGColor %>; color: <%= bodyTextColor %>;
scrollbar-face-color: <%= bodyBGColor %>;
scrollbar-shadow-color: <%= bodyTextColor %>;
scrollbar-highlight-color: <%= bodyBGColor %>;
scrollbar-darkshadow-color: <%= bodyBGColor %>;
scrollbar-track-color: <%= bodyBGColor %>;
scrollbar-arrow-color: <%= bodyTextColor %>; }
FRAME.bordered_left { border-left: 3px solid <%= frameDividerColor %>; }
IMG.logo { position: absolute; bottom: 12px; left: 10px; }
IMG.logout { vertical-align: middle; }
INPUT.submit { background-color: <%= buttonColor %>; color: <%= buttonTextColor %>;
font-size: 12px; font-family: Arial, Verdana, sans serif;
border-style: ridge; margin: 1px 5px 1px 5px; }
INPUT.submit_right { background-color: <%= buttonColor %>; color: <%= buttonTextColor %>;
font-size: 12px; font-family: Arial, Verdana, sans serif;
border-style: ridge; margin: 1px 5px 1px 5px;
position: absolute; right: 10px; }
INPUT.text { background-color: <%= textFieldColor %>; color: <%= textFieldTextColor %>;
font: normal 12px Arial, Verdana, sans serif; height: 20px; width: 271px;
border-style: groove; margin-left: 10px; }
SPAN.chat_text { font: normal 11px Arial, Verdana, sans serif;
color: <%= chatTextColor %>; }
SPAN.chat_announcement { font: italic 11px Arial, Verdana, sans serif;
color: <%= chatAnnouncementColor %>; }
SPAN.chat_owner { font: bold 11px Arial, Verdana, sans serif;
color: <%= chatOwnerLabelColor %>; }
SPAN.chat_participant { font: bold 11px Arial, Verdana, sans serif;
color: <%= chatParticipantLabelColor %>; }
SPAN.logout { position: absolute; bottom: 12px; right: 15px; }
TEXTAREA { color: <%= textFieldTextColor %>; font: normal 12px Arial, Verdana, sans serif;
width: 500px; height: 130px; }

View File

@ -0,0 +1,13 @@
<html>
<head>
<meta http-equiv="expires" content="0">
<link rel="stylesheet" href="style_sheet.jsp" type="text/css" media="screen">
</head>
<body class="deffr">
<div id="ytext"> <br></div><div id="enddiv"></div>
</body>
</html>

View File

@ -0,0 +1,309 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Smack Source Distribution</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
A:hover {
text-decoration : none;
}
.pageheader {
font-family : arial, helvetica, sans-serif;
font-size : 14pt;
font-weight: bold;
}
.header {
font-family : arial, helvetica, sans-serif;
font-size : 12pt;
font-weight: bold;
}
.subheader {
font-weight: bold;
color: #600;
}
.path {
color : #3333cc;
}
.question {
font-style : italic;
}
.answer {
padding-left : 15px;
}
.code {
font-family : courier new;
border : 1px #ccc solid;
padding : 6px;
margin : 5px 20px 5px 20px;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE, CODE {
font-family : courier new;
font-size : 100%;
}
.footer {
font-size : 0.8em;
color : #666;
text-align : center;
}
</style>
</head>
<body bgcolor="#ffffff">
<font size=4>
Smack Source Distribution<br>
</font><br>
<p>
This document provides detailed information for developers that wish to
compile and make changes to the Smack source code.
<p>For additional developer resources, please visit:
<a href="http://www.jivesoftware.org/smack/">
http://www.jivesoftware.org/smack/</a>. The Smack build process is based on Ant. Visit the
<a href="http://jakarta.apache.org/ant/index.html">Ant website</a>
for more information. There is no need to download and install Ant - a version of it is included
in this distribution.
<p>
This documentation is divided into two sections:
<ol>
<li> <a href="#setup">Setup</a> -- how to setup your environment for Smack development.
<li> <a href="#tasks">Build tasks</a> -- tasks that can be performed using the build program.
</ol>
<p><a name="setup"><b><font color="#0066cc">1.</font> Setup Your Environment</b></a><p>
Getting your machine ready for Smack development requires a few steps. Wherever
possible, instructions are provided for both Unix/Linux and Windows users.
<p>
<b><a name="javaSetup">Configure Java</a></b>
<ul>
Java 2 (JDK 1.2 or later) must be installed and setup on your machine. To test the installation,
open a shell in a Unix or a MS-DOS prompt in Windows. Check your version of
Java with "java -version" -- it must version 1.2 or greater.
If Java isn't installed, download a copy from the
<a href="http://java.sun.com/">Java website</a>.
<p>
<font color="red">Important!</font> -- the Smack build tool needs to know
where Java is installed on your system. You must configure the "JAVA_HOME"
environment variable to point to the correct directory. Instructions on
how to set this variable for various platforms are as follows:
<p>
<ul>
<li> Unix/Linux
<ol>
<li>Edit the ".profile" file in your home directory (or
corresponding file for your shell).
<li>Set the JAVA_HOME environment variable by adding the
following line to the file:
<p></font><code>
export JAVA_HOME=/usr/local/jdk1.3
</code><font face="verdana, arial, helvetica" size=2>
<p>
The value "/usr/local/jdk1.3" should be replaced with your actual
Java directory. Be sure there are no spaces after the end of
the directory name. Do not add an extra slash after the directory name.
<li>Save changes to the file and then "source" it:
<p></font><code>
source .profile
</code><font face="verdana, arial, helvetica" size=2>
<p>
The JAVA_HOME variable should now be configured correctly.
</ol>
<p>
<li> WindowsNT/2000
<ol>
<li>Navigate to your desktop and right click on "My Computer";
choose properties.
<li>Select the "Advanced" tab and click on the
"Environment Variables" button.
<li>Click the "New..." button in the System variables section.
Enter the variable name "JAVA_HOME" and set the variable
value to the full path of your Java installation. For example,
"c:\jdk1.3". Be sure to not add an extra slash to the end
of the directory name.
<li>Click "OK" in all of the menus to accept the changes.
<li>Close any open command prompt windows. The next time you
open a command prompt, the "JAVA_HOME" variable will be set
correctly.
</ol>
<p>
<li> Windows95/98
<ol>
<li>Open your autoexec.bat file (often at "c:\autoexec.bat") using Notepad.
<li>Add a line to the end of the file that resembles the following:
<p></font><code>
set JAVA_HOME=c:\jdk1.3
</code><font face="verdana, arial, helvetica" size=2>
<p>
The value "c:\jdk1.3" should be replaced with your actual
Java directory. Be sure there are no spaces between
the "=" sign or after the end of the directory name. Do
not add an extra slash after the directory name.
<li>Save changes to autoexec.bat and restart your computer.
</ol>
</ul>
</ul>
<p><b><a name="checkout">Test the Build Script</a></b><p>
<ul>
Navigate into the subdirectory of this distribution named "build" via the command-line.<p>
<table boder=0 cellpadding=2 cellspacing=0><td bgcolor="#EEEEEE">
<font face="verdana, arial, helvetica" size=2>
<font color="red">Linux/Unix users only:</font>You must make the ant script
executable. From the build directory, type:
<p></font><code>
chmod u+x ant
</code><font face="verdana, arial, helvetica" size=2>
</td></table>
<p>
Now, invoke the build tool to compile the Smack source code
<p>
Windows:</font><code> ant <br>
</code><font face="verdana, arial, helvetica" size=2>
Unix/Linux:</font><code> ./ant
</code><font face="verdana, arial, helvetica" size=2>
<p>
If the build tool is invoked correctly and Smack compiles, you've correctly
configured your copy of the Smack developer distribution.
</ul>
<p><b>Finished!</b><p>
<ul>
If you've gotten this far, you've finished setting up the Smack developer
distribution. Now, read below to learn about all of the tasks that you can perform
with the build tool.
</ul>
<br><br>
<p><b><a name="tasks"><font color="#0066cc">2.</font> Build Tasks</a></b><p>
The list of build tasks is below. All build commands should be
run from the "build" directory of your Smack distribution.
<br><br>
For a list of the commands and a brief description from the command line, type
<code>ant -projecthelp</code>. For more complete help, read the documentation below.
<br><br>
To execute a build task, type <code>ant [options] targetname</code> where "targetname" is
one of the targets listed below:
<ul>
<li><a href="#noparams"><i>Default</i></a>
<li><a href="#compile">compile</a>
<li><a href="#jar">jar</a>
<li><a href="#javadoc">javadoc</a>
<li><a href="#clean">clean</a>
</ul>
<p>
Each task is documented with a syntax guide and description. Optional paramaters
for each task are enclosed with braces.
<!--COMPILE-->
<p><b><a name="noparams"><i>Default</i></a></b>
<ul>
<i>Syntax:</i><p>
</font><code>
ant<br>
</code><font face="verdana, arial, helvetica" size=2>
<p><i>Description:</i></p>
Equivalent of calling "ant <a href="#jar">jar</a>".
<p>[<a href="#tasks">return to task list</a>]
</ul>
<!--COMPILE-->
<p><b><a name="compile">compile</a></b>
<ul>
<i>Syntax:</i><p>
</font><code>
ant compile <br>
</code><font face="verdana, arial, helvetica" size=2>
<p><i>Description:</i></p>
Compiles all the Smack source code.
The build directory is the "classes" directory under your Smack source distribution.
<p>[<a href="#tasks">return to task list</a>]
</ul>
<!--JAR-->
<p><b><a name="jar">jar</a></b>
<ul>
<i>Syntax:</i><p>
</font><code>
ant jar <br>
</code><font face="verdana, arial, helvetica" size=2>
<p><i>Description:</i></p>
Bundles the Smack class files into a JAR file (smack.jar)
that is suitable for adding
into the classpath of an application server.
<p>[<a href="#tasks">return to task list</a>]
</ul>
<!--JAVADOC-->
<p><b><a name="javadoc">javadoc</a></b>
<ul>
<i>Syntax:</i><p>
</font><code>
ant javadoc <br>
</code><font face="verdana, arial, helvetica" size=2>
<p><i>Description:</i></p>
JavaDocs all Smack source code in the source directory.
<p>[<a href="#tasks">return to task list</a>]
</ul>
<!--CLEAN-->
<p><b><a name="clean">clean</a></b>
<ul>
<i>Syntax:</i><p>
</font><code>
ant clean<br>
</code><font face="verdana, arial, helvetica" size=2>
<p><i>Description:</i></p>
Cleans your Smack distribution directory by deleting compiled class files, the
smack.jar file and Javadoc files.<p>
<p>[<a href="#tasks">return to task list</a>]
</ul>
</body>
</html>

42
CopyOftrunk/build/ant Normal file
View File

@ -0,0 +1,42 @@
#! /bin/sh
# //--------------------------------------------------------------------------//
# // $RCSfile$
# // $Revision$
# // $Date$
# //
# // Standard Jive Software ant file. Do not change this file. If you do,
# // you will have seven years of bad luck and bad builds.
# //--------------------------------------------------------------------------//
# //--------------------------------------------------------------------------//
# // Uncomment the following lines if you wish to set JAVA_HOME in this script
# //--------------------------------------------------------------------------//
# JAVA_HOME=
# EXPORT JAVA_HOME
# //--------------------------------------------------------------------------//
# // Check for the JAVA_HOME environment variable //
# //--------------------------------------------------------------------------//
if [ "$JAVA_HOME" != "" ] ; then
# //----------------------------------------------------------------------//
# // Create Ant's classpath //
# //----------------------------------------------------------------------//
CP=$JAVA_HOME/lib/tools.jar:./ant.jar:./junit.jar
# //----------------------------------------------------------------------//
# // Run ant //
# //----------------------------------------------------------------------//
$JAVA_HOME/bin/java -classpath $CP -Dant.home=. org.apache.tools.ant.Main $@
else
# //----------------------------------------------------------------------//
# // No JAVA_HOME error message //
# //----------------------------------------------------------------------//
echo "Jive Forums Build Error:"
echo ""
echo "The JAVA_HOME environment variable is not set. JAVA_HOME should point"
echo "to your java directory, ie: /usr/local/bin/jdk1.3. You can set"
echo "this via the command line like so:"
echo " export JAVA_HOME=/usr/local/bin/jdk1.3"
fi

Binary file not shown.

51
CopyOftrunk/build/ant.bat Normal file
View File

@ -0,0 +1,51 @@
@echo off
rem //------------------------------------------------------------------------//
rem // $RCSfile$
rem // $Revision$
rem // $Date$
rem //
rem // Standard Jive Software ant.bat file. Do not change this file. If you do,
rem // you will have seven years of bad luck and bad builds.
rem //------------------------------------------------------------------------//
rem //------------------------------------------------------------------------//
rem // Uncomment the following if you wish to set JAVA_HOME in this bat file:
rem //------------------------------------------------------------------------//
rem SET JAVA_HOME=
rem //------------------------------------------------------------------------//
rem // Check for the JAVA_HOME environment variable
rem //------------------------------------------------------------------------//
if "%JAVA_HOME%" == "" goto noJavaHome
rem //------------------------------------------------------------------------//
rem // Make the correct classpath (should include the java jars and the
rem // Ant jars)
rem //------------------------------------------------------------------------//
SET CP=%JAVA_HOME%\lib\tools.jar;.\ant.jar;.\junit.jar
rem //------------------------------------------------------------------------//
rem // Run Ant
rem // Note for Win 98/95 users: You need to change "%*" in the following
rem // line to be "%1 %2 %3 %4 %5 %6 %7 %8 %9"
rem //------------------------------------------------------------------------//
%JAVA_HOME%\bin\java -Xms32m -Xmx128m -classpath %CP% -Dant.home=. org.apache.tools.ant.Main %*
goto end
rem //------------------------------------------------------------------------//
rem // Error message for missing JAVA_HOME
rem //------------------------------------------------------------------------//
:noJavaHome
echo.
echo Jive Forums Build Error:
echo.
echo The JAVA_HOME environment variable is not set. JAVA_HOME should point to
echo your java directory, ie: c:\jdk1.3.1. You can set this via the command
echo line like so:
echo SET JAVA_HOME=c:\jdk1.3
echo.
goto end
:end

BIN
CopyOftrunk/build/ant.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,15 @@
#
# $RCSfile$
# $Revision$
# $Date$
#
# Test properties. Uncomment these to override default values declared
# in the build.xml file.
# test.host=
# test.port=
# test.admin.username=
# test.admin.password=
# test.admin.resource=
# test.smack.debug=

311
CopyOftrunk/build/build.xml Normal file
View File

@ -0,0 +1,311 @@
<?xml version="1.0"?>
<!-- Smack Build Script ========================================== -->
<!-- Jive Software ============================================== -->
<!--
$RCSfile$
$Revision$
$Date$
-->
<project name="Smack" default="all" basedir="..">
<!-- TASKDEFS -->
<!-- ======================================================================================= -->
<!-- ======================================================================================= -->
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="${basedir}/build/ant-contrib.jar"/>
</classpath>
</taskdef>
<!-- PROPERTIES -->
<!-- ======================================================================================= -->
<property file="${basedir}/build/build.properties" />
<property name="compile.dir" value="${basedir}/classes" />
<property name="compile.test.dir" value="${basedir}/classes-test" />
<property name="jar.dest.dir" value="${basedir}" />
<property name="javadoc.dest.dir" value="${basedir}/javadoc" />
<property name="build.lib.dir" value="${basedir}/build/lib" />
<property name="merge.lib.dir" value="${basedir}/build/merge" />
<property name="version.major" value="1" />
<property name="version.minor" value="5" />
<property name="version.revision" value="1" />
<property name="version.name" value="${version.major}.${version.minor}.${version.revision}" />
<!-- Test props - override these defaults in the properties file or in command line -->
<property name="test.host" value="localhost" />
<property name="test.port" value="5222" />
<property name="test.admin.username" value="admin" />
<property name="test.admin.password" value="admin" />
<property name="test.admin.resource" value="Test" />
<property name="test.smack.debug" value="false" />
<!-- PATHS, DEPENDIENCIES, PATTERNS -->
<!-- ======================================================================================= -->
<!-- ======================================================================================= -->
<patternset id="test.cases">
<include name="org/jivesoftware/smack/**/*Test.java" />
<exclude name="org/jivesoftware/smack/**/Messenger*Test.java" />
</patternset>
<patternset id="messenger.test.cases">
<include name="org/jivesoftware/smack/**/Messenger*Test.java" />
</patternset>
<!-- TARGETS -->
<!-- ======================================================================================= -->
<!-- all -->
<!-- ======================================================================================= -->
<target name="all" depends="jar" description="Calls 'jar' target by default">
</target>
<!-- compile -->
<!-- ======================================================================================= -->
<target name="compile" description="Compiles all source to ${compile.dir}.">
<!-- make target dir -->
<mkdir dir="${compile.dir}" />
<javac
destdir="${compile.dir}"
includeAntRuntime="no"
debug="on"
source="1.3"
target="1.2"
>
<src path="${basedir}/source" />
<classpath>
<fileset dir="${build.lib.dir}">
<include name="*.jar"/>
</fileset>
<fileset dir="${merge.lib.dir}">
<include name="*.jar"/>
</fileset>
</classpath>
</javac>
</target>
<!-- compile-test -->
<!-- ======================================================================================= -->
<target name="compile-test" description="Compiles all source to ${compile.dir}.">
<!-- make target dir -->
<mkdir dir="${compile.test.dir}" />
<javac
destdir="${compile.test.dir}"
includeAntRuntime="no"
debug="on"
source="1.3"
target="1.2"
>
<src path="${basedir}/test" />
<classpath>
<fileset dir="${build.lib.dir}">
<include name="*.jar"/>
</fileset>
<fileset dir="${merge.lib.dir}">
<include name="*.jar"/>
</fileset>
<fileset dir="${basedir}/build">
<include name="junit.jar"/>
<include name="xmlunit.jar"/>
</fileset>
<pathelement location="${compile.dir}" />
</classpath>
</javac>
</target>
<!-- jar -->
<!-- ======================================================================================= -->
<target name="jar" depends="compile" unless="jar.uptodate" description="Produces smack.jar">
<copy todir="${compile.dir}/META-INF" file="${basedir}/build/resources/META-INF/smack-config.xml" />
<jar destfile="${jar.dest.dir}/smack.jar"
basedir="${compile.dir}"
includes="org/jivesoftware/smack/**/*.class, **/smack-config.xml"
>
<zipfileset src="${merge.lib.dir}/xpp.jar"/>
</jar>
<copy todir="${compile.dir}/META-INF" file="${basedir}/build/resources/META-INF/smack.providers" />
<jar destfile="${jar.dest.dir}/smackx.jar"
basedir="${compile.dir}"
includes="org/jivesoftware/smackx/**/*.class, **/*.providers"
excludes="org/jivesoftware/smackx/debugger/*.class"
>
<manifest>
<attribute name="Class-Path" value="smack.jar" />
</manifest>
</jar>
<copy todir="${compile.dir}/images">
<fileset dir="${basedir}/build/resources/images">
<include name="*.png"/>
</fileset>
</copy>
<jar destfile="${jar.dest.dir}/smackx-debug.jar"
basedir="${compile.dir}"
includes="org/jivesoftware/smackx/debugger/*.class, **/*.png"
>
<manifest>
<attribute name="Class-Path" value="smack.jar" />
</manifest>
</jar>
<delete file="${compile.dir}/META-INF/smack-config.xml" />
<delete file="${compile.dir}/META-INF/smack.providers" />
<delete>
<fileset dir="${compile.dir}/images">
<include name="*.png"/>
</fileset>
</delete>
</target>
<!-- jar -->
<!-- ======================================================================================= -->
<target name="jar-test" depends="compile-test" description="Produces jar of test code">
<jar destfile="${jar.dest.dir}/smack-test.jar"
basedir="${compile.test.dir}"
includes="org/jivesoftware/smack/**/*.class"
/>
</target>
<!-- javadoc -->
<!-- ======================================================================================= -->
<target name="javadoc" description="JavaDocs the Smack source code">
<mkdir dir="${javadoc.dest.dir}" />
<javadoc
packagenames="org.jivesoftware.smack.*, org.jivesoftware.smackx.*"
sourcepath="${basedir}/source"
destdir="${javadoc.dest.dir}"
author="true"
windowtitle="Smack ${version.name} Documentation"
overview="${basedir}/source/overview.html"
>
<classpath>
<fileset dir="${build.lib.dir}">
<include name="*.jar"/>
</fileset>
<fileset dir="${merge.lib.dir}">
<include name="*.jar"/>
</fileset>
</classpath>
<doctitle><![CDATA[<font face="arial,helvetica">Smack ${version.name}</font>]]></doctitle>
<header><![CDATA[<b>Smack</b>]]></header>
<bottom><![CDATA[<i>Copyright &copy; 2003 Jive Software. </i>]]></bottom>
<link href="http://java.sun.com/j2se/1.3/docs/api/" />
<link href="http://java.sun.com/j2ee/sdk_1.2.1/techdocs/api/" />
</javadoc>
</target>
<!-- test -->
<!-- ======================================================================================= -->
<target name="test" depends="compile, jar-test" unless="no.test">
<echo>
**** no.test: ${no.test}
</echo>
<property name="test.messenger" value="false" />
<if>
<not><equals arg1="test.messenger" arg2="true" /></not>
<then>
<property name="test.classes" value="test.cases" />
</then>
</if>
<junit printsummary="on"
fork="false"
haltonfailure="false"
failureproperty="tests.failed"
showoutput="true">
<sysproperty key="smack.test.host" value="${test.host}" />
<sysproperty key="smack.test.port" value="${test.port}" />
<sysproperty key="smack.test.admin.username" value="${test.admin.username}" />
<sysproperty key="smack.test.admin.password" value="${test.admin.password}" />
<sysproperty key="smack.test.admin.resource" value="${test.admin.resource}" />
<sysproperty key="smack.debug" value="${test.smack.debug}" />
<classpath>
<fileset dir="${build.lib.dir}">
<include name="*.jar"/>
</fileset>
<fileset dir="${basedir}/build">
<include name="xmlunit.jar"/>
</fileset>
<fileset dir="${merge.lib.dir}">
<include name="*.jar"/>
</fileset>
<fileset dir="${basedir}">
<include name="smack-test.jar"/>
</fileset>
<pathelement location="${compile.dir}" />
</classpath>
<formatter type="brief" usefile="false"/>
<batchtest>
<fileset dir="${basedir}/test">
<patternset refid="${test.classes}" />
</fileset>
</batchtest>
</junit>
<fail if="tests.failed" message="** Tests failed, see test log. **" />
</target>
<!-- test -->
<!-- ======================================================================================= -->
<target name="test.messenger" depends="compile, jar-test" unless="no.test">
<antcall target="test" inheritall="true" inheritrefs="true">
<param name="test.messenger" value="true" />
<param name="test.classes" value="messenger.test.cases" />
</antcall>
</target>
<!-- release -->
<!-- ======================================================================================= -->
<target name="release" if="release.exists" depends="release-exists">
<antcall target="jar">
<param name="no.test" value="true" />
</antcall>
<antcall target="javadoc">
<param name="no.test" value="true" />
</antcall>
<ant antfile="${basedir}/build/release.xml" />
</target>
<!-- release-exists -->
<!-- ======================================================================================= -->
<target name="release-exists" >
<available file="${basedir}/build/release.xml" property="release.exists"/>
</target>
<!-- clean -->
<!-- ======================================================================================= -->
<target name="clean" description="Deletes all generated content.">
<delete dir="${javadoc.dest.dir}" />
<delete dir="${compile.dir}" />
<delete dir="${compile.test.dir}" />
<delete file="${basedir}/smack.jar" />
<delete file="${basedir}/smackx.jar" />
<delete file="${basedir}/smackx-debug.jar" />
<delete file="${basedir}/smack-test.jar" />
<delete dir="${basedir}/release" />
</target>
</project>

BIN
CopyOftrunk/build/junit.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4" relativePaths="true" type="JAVA_MODULE">
<component name="ModuleRootManager" />
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/../../classes" />
<exclude-output />
<exclude-exploded />
<content url="file://$MODULE_DIR$/../..">
<sourceFolder url="file://$MODULE_DIR$/../../source" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../test" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../lib/jsse.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../merge/xpp.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../lib/jcert.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../lib/jnet.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../ant.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../ant-contrib.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../junit.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntryProperties />
</component>
</module>

View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4" relativePaths="true">
<component name="AntConfiguration">
<defaultAnt bundledAnt="true" />
</component>
<component name="CodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="WHILE_ON_NEW_LINE" value="true" />
<option name="CATCH_ON_NEW_LINE" value="true" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="RIGHT_MARGIN" value="100" />
</value>
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</component>
<component name="CompilerConfiguration">
<option name="DEFAULT_COMPILER" value="Javac" />
<option name="CLEAR_OUTPUT_DIRECTORY" value="false" />
<option name="DEPLOY_AFTER_MAKE" value="0" />
<resourceExtensions>
<entry name=".+\.(properties|xml|html|dtd|tld)" />
<entry name=".+\.(gif|png|jpeg|jpg)" />
</resourceExtensions>
</component>
<component name="DataSourceManagerImpl" />
<component name="DependencyValidationManager" />
<component name="EntryPointsManager">
<entry_points />
</component>
<component name="ExportToHTMLSettings">
<option name="PRINT_LINE_NUMBERS" value="false" />
<option name="OPEN_IN_BROWSER" value="false" />
<option name="OUTPUT_DIRECTORY" />
</component>
<component name="GUI Designer component loader factory" />
<component name="JavacSettings">
<option name="DEBUGGING_INFO" value="true" />
<option name="GENERATE_NO_WARNINGS" value="false" />
<option name="DEPRECATION" value="true" />
<option name="ADDITIONAL_OPTIONS_STRING" value="" />
<option name="MAXIMUM_HEAP_SIZE" value="128" />
<option name="USE_GENERICS_COMPILER" value="false" />
</component>
<component name="JavadocGenerationManager">
<option name="OUTPUT_DIRECTORY" />
<option name="OPTION_SCOPE" value="protected" />
<option name="OPTION_HIERARCHY" value="true" />
<option name="OPTION_NAVIGATOR" value="true" />
<option name="OPTION_INDEX" value="true" />
<option name="OPTION_SEPARATE_INDEX" value="true" />
<option name="OPTION_DOCUMENT_TAG_USE" value="false" />
<option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
<option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
<option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
<option name="OPTION_DEPRECATED_LIST" value="true" />
<option name="OTHER_OPTIONS" value="" />
<option name="HEAP_SIZE" />
<option name="OPEN_IN_BROWSER" value="true" />
</component>
<component name="JikesSettings">
<option name="JIKES_PATH" value="" />
<option name="DEBUGGING_INFO" value="true" />
<option name="DEPRECATION" value="true" />
<option name="GENERATE_NO_WARNINGS" value="false" />
<option name="IS_EMACS_ERRORS_MODE" value="true" />
<option name="ADDITIONAL_OPTIONS_STRING" value="" />
</component>
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
</group>
</component>
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Smack.iml" filepath="$PROJECT_DIR$/Smack.iml" />
</modules>
</component>
<component name="ProjectRootManager" version="2" assert-keyword="false" jdk-15="false" project-jdk-name="JDK 1.2.2" />
<component name="RmicSettings">
<option name="IS_EANABLED" value="false" />
<option name="DEBUGGING_INFO" value="true" />
<option name="GENERATE_NO_WARNINGS" value="false" />
<option name="GENERATE_IIOP_STUBS" value="false" />
<option name="ADDITIONAL_OPTIONS_STRING" value="" />
</component>
<component name="libraryTable">
<library name="Smack">
<CLASSES>
<root url="jar://$PROJECT_DIR$/../lib/jcert.jar!/" />
<root url="jar://$PROJECT_DIR$/../lib/jnet.jar!/" />
<root url="jar://$PROJECT_DIR$/../lib/jsse.jar!/" />
<root url="jar://$PROJECT_DIR$/../merge/xpp.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
<component name="uidesigner-configuration">
<option name="INSTRUMENT_CLASSES" value="true" />
<option name="COPY_FORMS_RUNTIME_TO_OUTPUT" value="true" />
</component>
</project>

View File

@ -0,0 +1,188 @@
<?xml version="1.0"?>
<!-- Smack Build Script ========================================== -->
<!-- Jive Software ============================================== -->
<!--
$RCSfile$
$Revision$
$Date$
-->
<project name="Smack Release Script" default="all" basedir="..">
<!-- Include Ant Optional Tasks -->
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="${basedir}/build/ant-contrib.jar"/>
</classpath>
</taskdef>
<!-- PROPERTIES -->
<!-- ======================================================================================= -->
<!-- TARGETS -->
<!-- ======================================================================================= -->
<!-- all -->
<!-- ======================================================================================= -->
<target name="all">
<!-- create release properties -->
<if>
<equals arg1="${dailybuild}" arg2="true" />
<then>
<tstamp>
<format property="build.date" pattern="yyyy-MM-dd" locale="en"/>
</tstamp>
<property name="release.name" value="smack-${build.date}" />
<property name="release-dev.name" value="smack-dev-${build.date}" />
</then>
<else>
<property name="release.name" value="smack-${version.name}" />
<property name="release-dev.name" value="smack-dev-${version.name}" />
</else>
</if>
<property name="release.dir" value="${basedir}/release/${release.name}" />
<property name="release-dev.dir" value="${basedir}/release/${release-dev.name}" />
<!-- create release dirs -->
<mkdir dir="${release.dir}" />
<mkdir dir="${release-dev.dir}" />
<!-- Copy smack.jar -->
<copy todir="${release.dir}">
<fileset dir="${jar.dest.dir}" includes="smack.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx-debug.jar" />
</copy>
<copy todir="${release-dev.dir}">
<fileset dir="${jar.dest.dir}" includes="smack.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx.jar" />
<fileset dir="${jar.dest.dir}" includes="smackx-debug.jar" />
</copy>
<!-- Copy build dir -->
<copy todir="${release-dev.dir}/build">
<fileset dir="${basedir}/build">
<include name="ant*" />
<include name="junit.jar" />
<include name="build.xml" />
<include name="README.html" />
<include name="lib/*.jar" />
<include name="merge/*.jar" />
</fileset>
</copy>
<!-- Copy Javadocs -->
<copy todir="${release.dir}/javadoc">
<fileset dir="${basedir}/javadoc" includes="**/*.*" />
</copy>
<copy todir="${release-dev.dir}/javadoc">
<fileset dir="${basedir}/javadoc" includes="**/*.*" />
</copy>
<!-- Copy documentation -->
<copy todir="${release.dir}/documentation">
<fileset dir="${basedir}/documentation" includes="**/*.*" />
</copy>
<copy todir="${release-dev.dir}/documentation">
<fileset dir="${basedir}/documentation" includes="**/*.*" />
</copy>
<!-- Copy source -->
<copy todir="${release-dev.dir}/source">
<fileset dir="${basedir}/source" includes="**/*.java" />
<fileset dir="${basedir}/source" includes="**/*.html" />
</copy>
<copy todir="${release-dev.dir}/test">
<fileset dir="${basedir}/test" includes="**/*.java" />
</copy>
<!-- Copy resources -->
<copy todir="${release-dev.dir}/build/resources">
<fileset dir="${basedir}/build/resources" includes="META-INF/smack.providers" />
<fileset dir="${basedir}/build/resources" includes="META-INF/smack-config.xml" />
</copy>
<copy todir="${release-dev.dir}/build/resources/images">
<fileset dir="${basedir}/build/resources/images">
<include name="*.png"/>
</fileset>
</copy>
<!-- Copy readme.html and changelog.html -->
<copy todir="${release.dir}">
<fileset dir="${basedir}/build/resources/releasedocs" includes="*.html" />
</copy>
<copy todir="${release-dev.dir}">
<fileset dir="${basedir}/build/resources/releasedocs" includes="*.html" />
</copy>
<!-- Package -->
<if>
<equals arg1="${dailybuild}" arg2="true" />
<then>
<zip destfile="${basedir}/release/${release-dev.name}.zip"
basedir="${release-dev.dir}/.."
includes="${release-dev.name}/**/*.*"
/>
<tar destfile="${basedir}/release/${release-dev.name}.tar.gz"
basedir="${release-dev.dir}/.."
includes="${release-dev.name}/**/*.*"
compression="gzip"
/>
</then>
<else>
<zip destfile="${basedir}/release/${release.name}.zip"
basedir="${release.dir}/.."
includes="${release.name}/**/*.*"
/>
<tar destfile="${basedir}/release/${release.name}.tar.gz"
basedir="${release.dir}/.."
includes="${release.name}/**/*.*"
compression="gzip"
/>
<zip destfile="${basedir}/release/${release-dev.name}.zip"
basedir="${release-dev.dir}/.."
includes="${release-dev.name}/**/*.*"
/>
<tar destfile="${basedir}/release/${release-dev.name}.tar.gz"
basedir="${release-dev.dir}/.."
includes="${release-dev.name}/**/*.*"
compression="gzip"
/>
</else>
</if>
<echo>
-----------------------------------------------
Release made, testing Ant targets of release...
-----------------------------------------------
</echo>
<!-- call the release tester -->
<antcall target="test" />
</target>
<!-- test -->
<!-- ======================================================================================= -->
<target name="test">
<property name="testdir" value="${release-dev.dir}/.test" />
<!-- copy the build to a temp dir so we can run sanity tests -->
<mkdir dir="${testdir}" />
<copy todir="${testdir}">
<fileset dir="${release-dev.dir}">
<exclude name=".test/**/*.*" />
</fileset>
</copy>
<!-- run sanity tests -->
<ant dir="${testdir}" antfile="build/build.xml" target="jar" inheritAll="false">
<property name="no.test" value="true" />
</ant>
<ant dir="${testdir}" antfile="build/build.xml" target="javadoc" inheritAll="false">
<property name="no.test" value="true" />
</ant>
<ant dir="${testdir}" antfile="build/build.xml" target="clean" inheritAll="false">
<property name="no.test" value="true" />
</ant>
<echo>
----------------------------
...release tests pass, done.
----------------------------
</echo>
</target>
</project>

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!-- Smack configuration file. -->
<smack>
<!-- Classes that will be loaded when Smack starts -->
<startupClasses>
<className>org.jivesoftware.smackx.ServiceDiscoveryManager</className>
<className>org.jivesoftware.smackx.XHTMLManager</className>
<className>org.jivesoftware.smackx.muc.MultiUserChat</className>
</startupClasses>
<!-- Paket reply timeout in milliseconds -->
<packetReplyTimeout>5000</packetReplyTimeout>
<!-- Keep-alive interval in milleseconds -->
<keepAliveInterval>30000</keepAliveInterval>
</smack>

View File

@ -0,0 +1,124 @@
<?xml version="1.0"?>
<!-- Providers file for default Smack extensions -->
<smackProviders>
<!-- Private Data Storage -->
<iqProvider>
<elementName>query</elementName>
<namespace>jabber:iq:private</namespace>
<className>org.jivesoftware.smackx.PrivateDataManager$PrivateDataIQProvider</className>
</iqProvider>
<!-- Time -->
<iqProvider>
<elementName>query</elementName>
<namespace>jabber:iq:time</namespace>
<className>org.jivesoftware.smackx.packet.Time</className>
</iqProvider>
<!-- Roster Exchange -->
<extensionProvider>
<elementName>x</elementName>
<namespace>jabber:x:roster</namespace>
<className>org.jivesoftware.smackx.provider.RosterExchangeProvider</className>
</extensionProvider>
<!-- Message Events -->
<extensionProvider>
<elementName>x</elementName>
<namespace>jabber:x:event</namespace>
<className>org.jivesoftware.smackx.provider.MessageEventProvider</className>
</extensionProvider>
<!-- XHTML -->
<extensionProvider>
<elementName>html</elementName>
<namespace>http://jabber.org/protocol/xhtml-im</namespace>
<className>org.jivesoftware.smackx.provider.XHTMLExtensionProvider</className>
</extensionProvider>
<!-- Group Chat Invitations -->
<extensionProvider>
<elementName>x</elementName>
<namespace>jabber:x:conference</namespace>
<className>org.jivesoftware.smackx.GroupChatInvitation$Provider</className>
</extensionProvider>
<!-- Service Discovery # Items -->
<iqProvider>
<elementName>query</elementName>
<namespace>http://jabber.org/protocol/disco#items</namespace>
<className>org.jivesoftware.smackx.provider.DiscoverItemsProvider</className>
</iqProvider>
<!-- Service Discovery # Info -->
<iqProvider>
<elementName>query</elementName>
<namespace>http://jabber.org/protocol/disco#info</namespace>
<className>org.jivesoftware.smackx.provider.DiscoverInfoProvider</className>
</iqProvider>
<!-- Data Forms-->
<extensionProvider>
<elementName>x</elementName>
<namespace>jabber:x:data</namespace>
<className>org.jivesoftware.smackx.provider.DataFormProvider</className>
</extensionProvider>
<!-- MUC User -->
<extensionProvider>
<elementName>x</elementName>
<namespace>http://jabber.org/protocol/muc#user</namespace>
<className>org.jivesoftware.smackx.provider.MUCUserProvider</className>
</extensionProvider>
<!-- MUC Admin -->
<iqProvider>
<elementName>query</elementName>
<namespace>http://jabber.org/protocol/muc#admin</namespace>
<className>org.jivesoftware.smackx.provider.MUCAdminProvider</className>
</iqProvider>
<!-- MUC Owner -->
<iqProvider>
<elementName>query</elementName>
<namespace>http://jabber.org/protocol/muc#owner</namespace>
<className>org.jivesoftware.smackx.provider.MUCOwnerProvider</className>
</iqProvider>
<!-- Delayed Delivery -->
<extensionProvider>
<elementName>x</elementName>
<namespace>jabber:x:delay</namespace>
<className>org.jivesoftware.smackx.provider.DelayInformationProvider</className>
</extensionProvider>
<!-- Version -->
<iqProvider>
<elementName>query</elementName>
<namespace>jabber:iq:version</namespace>
<className>org.jivesoftware.smackx.packet.Version</className>
</iqProvider>
<!-- VCard -->
<iqProvider>
<elementName>vCard</elementName>
<namespace>vcard-temp</namespace>
<className>org.jivesoftware.smackx.provider.VCardProvider</className>
</iqProvider>
<!-- Offline Message Requests -->
<iqProvider>
<elementName>offline</elementName>
<namespace>http://jabber.org/protocol/offline</namespace>
<className>org.jivesoftware.smackx.packet.OfflineMessageRequest$Provider</className>
</iqProvider>
<!-- Offline Message Indicator -->
<extensionProvider>
<elementName>offline</elementName>
<namespace>http://jabber.org/protocol/offline</namespace>
<className>org.jivesoftware.smackx.packet.OfflineMessageInfo$Provider</className>
</extensionProvider>
</smackProviders>

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 B

View File

@ -0,0 +1,120 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Smack Readme</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
A:hover {
text-decoration : none;
}
.pageheader {
font-family : arial, helvetica, sans-serif;
font-size : 14pt;
font-weight: bold;
}
.header {
font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
.subheader {
font-weight: bold;
color: #600;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE {
font-family : courier new;
font-size : 100%;
}
.footer {
font-size : 0.8em;
color : #666;
text-align : center;
}
</style>
</head>
<body>
<div class="header">
Smack Readme
</div>
<p>
<table boder=0>
<tr>
<td>version:</td>
<td><b>1.5.1</b></td>
</tr><tr>
<td>released:</td>
<td><b>August 12, 2005</b></td>
</tr>
</table>
<p>
Thank you for downloading Smack!
<p>
Start off by viewing the <a href="documentation/index.html">documentation</a>
that can be found in the "documentation" directory included with this distribution.
<p>
Further information can be found on the <a href="http://www.jivesoftware.org/smack">
Smack website</a>. If you need help using or would like to make contributions or
fixes to the code, please visit the
<a href="http://www.jivesoftware.org/forums/forum.jspa?forumID=39">online forum</a>.
<p><b>About the Distribution</b><p>
The <tt>smack.jar</tt> file in the main distribution folder is the only binary file
required for embedding XMPP functionality into client applications. The optional
<tt>smackx.jar</tt> contains the <a href="documentation/extensions/index.html">Smack extensions</a>
while <tt>smackx-debug.jar</tt> contains an enhanced debugger.<p>
If you downloaded the developer release, the full source of the library is included in
the <tt>source</tt> directory and can be compiled using the build scripts found in the
<tt>build</tt> directory (please see the README file in the build directory for further details).
<p><b>Changelog and Upgrading</b><p>
View the <a href="changelog.html">changelog</a> for a list of changes since the
last release.
<p><b>License Agreements</b><p>
<ul>
<li>Use of thie Smack source code is governed by the Apache License:
<pre>
Copyright 2002-2005 Jive Software.
All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
</pre></li>
<li>Smack contains icons and images licensed from INCORS GmbH. You are not licensed
to use these icons outside of Smack.</li>
<li>Third-party source code is licensed as noted in their source files.
</ul>
</body>
</html>

View File

@ -0,0 +1,296 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Smack Changelog</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
A:hover {
text-decoration : none;
}
.pageheader {
font-family : arial, helvetica, sans-serif;
font-size : 14pt;
font-weight: bold;
}
.header {
font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
.bugNum {
color: #666;
}
.subheader {
font-weight: bold;
color: #600;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE {
font-family : courier new;
font-size : 100%;
}
.footer {
font-size : 0.8em;
color : #666;
text-align : center;
}
</style>
</head>
<body>
<div class="header">
Smack Changelog
</div>
<p>
<b>1.5.1</b> -- August 12, 2005
<p>
<ul>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-60'>SMACK-60</a>] - Presence priorities out of range were crashing the connection.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-63'>SMACK-63</a>] - Sometimes XMPPConnection#getRoster() was taking too long.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-66'>SMACK-66</a>] - Wrong attribute name and date format when requesting history since a given date.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-70'>SMACK-70</a>] - IQ Time now uses a 0-23 hour format.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-25'>SMACK-25</a>] - Added support for JEP-13: Flexible Offline Message Retrieval.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-58'>SMACK-58</a>] - Added support for JEP-54: vCards. Thanks to Kirill Maximov.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-53'>SMACK-53</a>] - Added support for JEP-92: Software Version.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-61'>SMACK-61</a>] - Added new debugger that prints on the stdout.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-71'>SMACK-71</a>] - Created new FromMatchesFilter that checks for exact matching.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-52'>SMACK-52</a>] - Added constructor to XMPPConnection for better connection control.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-56'>SMACK-56</a>] - Reported data can now hold more than one value.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-57'>SMACK-57</a>] - RoomInfo now includes the room JID.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-59'>SMACK-59</a>] - Date format for delayed dates is configurable.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-62'>SMACK-62</a>] - The username and password fields are now optional in Registration.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-67'>SMACK-67</a>] - Parsing of delayed dates was improved to be smarter.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-68'>SMACK-68</a>] - PacketParserUtils#parseProperties is now public.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-69'>SMACK-69</a>] - Adding or removing entries from a group can now throw an XMPPException.</li>
</ul>
<p>
<b>1.5.0</b> -- March 30, 2005
<p>
<ul>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-7'>SMACK-7</a>] - Fixed issue that caused Smack to fail when X11 was not installed on Unix.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-32'>SMACK-32</a>] - Getting the system classloader could raise a security exception.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-33'>SMACK-33</a>] - MUCOwner.Item now includes the "role" attribute.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-37'>SMACK-37</a>] - Fixing timing issue that could make logins slow.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-42'>SMACK-42</a>] - The pretty print of the EnhancedDebugger was not working well with Java 1.5.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-43'>SMACK-43</a>] - Occupant#getNick() answers null when the info is available.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-46'>SMACK-46</a>] - Support for cancelling notifications in message events was missing.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-48'>SMACK-48</a>] - PacketListeners were not being removed from the connection when the chat finishes.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-50'>SMACK-50</a>] - XML representation of Presence packets did not include error element.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-4'>SMACK-4</a>] - Implemented room management in batch mode.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-11'>SMACK-11</a>] - Implemented discovery of extended information of MUC rooms.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-13'>SMACK-13</a>] - Implemented discovery of MUC rooms hosted by a service.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-38'>SMACK-38</a>] - Notify when an occupant joins or leaves a group chat room.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-39'>SMACK-39</a>] - Added support for discovering MUC services.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-41'>SMACK-41</a>] - Added support for JEP-91: Delayed Delivery.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-49'>SMACK-49</a>] - Modified Smack to use latest minimal version of XPP.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-40'>SMACK-40</a>] - Packet extensions can now be sent when inviting a user to a room.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-44'>SMACK-44</a>] - PacketReader can now parse errors that follow XMPP 1.0.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-45'>SMACK-45</a>] - Sorted the list of providers in the EnhancedDebugger window.</li>
<li>[<a href='http://www.jivesoftware.org/issues/browse/SMACK-47'>SMACK-47</a>] - Added a public API for parsing Messages and Presences.</li>
</ul>
<p>
<b>1.4.1</b> - November 15, 2004
<p>
<ul>
<li><font color="#777777">(SMACK-21)</font> The reader and listener threads in PacketReader are now stopped if an error occurs while starting up PacketReader. Thanks to Steve Reichert.
<li><font color="#777777">(SMACK-22)</font> XMPP addresses are now treated as case insensitive.
<li><font color="#777777">(SMACK-3)</font> Fixed possible NullPointerException when parsing invalid XHTML text.
<li><font color="#777777">(SMACK-8)</font> Answer an item-not-found error when Smack receives a service discovery for information and node is not null.
<li><font color="#777777">(SMACK-17)</font> An incorrect namespace was being used for granting and revoking admin/owner privileges.
<li><font color="#777777">(SMACK-19)</font> The roster should be able to hold any valid JID format. Thanks to Adam Olsen.
<li><font color="#777777">(SMACK-20</font> Parsing MUCOwner packets could freeze the client.
<li><font color="#777777">(SMACK-18)</font> Implemented JEP-128. A service discovery for information can now include a dataform or any possible packet extension.
<li><font color="#777777">(SMACK-15)</font> Allow registration entries with blank values.
<li><font color="#777777">(SMACK-16)</font> Added <tt>String getAccountAttribute(String)</tt> method to AccountManager class.
<li><font color="#777777">(SMACK-23)</font> Connection listeners can now be removed while notifying that the connection is being closed. Fixes ConcurrentModificationException triggered on close.
</ul>
<p>
<b>1.4.0</b> - August 10, 2004
<p>
<ul>
<li><font color="#777777">(SMACK-99)</font> Added support for Multi User Chat (JEP 45) as a Smack Extension.
<li><font color="#777777">(SMACK-125)</font> Added support for Data Forms (JEP 04) as a Smack Extension.
<li><font color="#777777">(SMACK-143)</font> Fixed memory leak problem by closing ObjectOutputStream while writing out Object properties.
<li><font color="#777777">(SMACK-145)</font> Fixed memory leak problem by cancelling unused collectors.
<li><font color="#777777">(SMACK-138)</font> Fixed error parsing properties of Messages.
<li><font color="#777777">(SMACK-135)</font> Invalid characters in the TO and FROM fields of any packet were escaped in order to
prevent the connection from closing. Thanks to Ian Sollars.
<li><font color="#777777">(SMACK-140)</font> Added new constructor to XMPPConnection <tt>XMPPConnection(String host, int port,
SocketFactory socketFactory)</tt> that allows a user to pass in the SocketFactory to use.
<li><font color="#777777">(SMACK-131)</font> Remove cached presence info when user was deleted from roster.
<li><font color="#777777">(SMACK-123)</font> TimerTask was removed to make Smack JDK 1.2 compatible again.
<li><font color="#777777">(SMACK-130)</font> Use notifyAll() instead of notify() in PacketWriter.
<li><font color="#777777">(SMACK-137)</font> Fixed security exception with unsigned applets using try/catch around System.getProperty.
<li><font color="#777777">(SMACK-127)</font> IQ packets can now have extensions.
<li><font color="#777777">(SMACK-128)</font> Registration can now include a registration data form.
<li><font color="#777777">(SMACK-136)</font> Keep-alive process should flush stream.
<li><font color="#777777">(SMACK-121)</font> Delay of keep-alive is now configurable.
<li><font color="#777777">(SMACK-149)</font> A disco info request directed to a Smack client didn't answer the client's identity.
<li><font color="#777777">(SMACK-150)</font> Added <tt>canPublishItems(String entityID)</tt> method to ServiceDiscoveryManager in
order to discover whether a server supports publishing of items or not.
<li><font color="#777777">(SMACK-133)</font> Node attribute was missing in DiscoverInfo and DiscoverItems XML representations.
<li><font color="#777777">(SMACK-134)</font> Added <tt>setNodeInformationProvider(String node, NodeInformationProvider listener)</tt>
method to ServiceDiscoveryManager and created new <tt>NodeInformationProvider</tt> interface in order to provide information about
nodes defined in the client.
<li><font color="#777777">(SMACK-139)</font> Added new menu option to the enhanced debugger in order to close all the tabs of which
their connections are not active anymore.
<li><font color="#777777">(SMACK-124)</font> Don't set L&F in debuggers.
<li><font color="#777777">(SMACK-122)</font> Added documentation about the new enhanced debugger.
<li><font color="#777777">(SMACK-142)</font> Base class for existing test cases was created.
</ul>
<p>
<b>1.3.0</b> - March 11, 2004
<p>
<ul>
<li><font color="#777777">(SMACK-103, SMACK-105)</font> Fixed bugs with error packets (sending and receiving).
<li><font color="#777777">(SMACK-109)</font> Renaming RosterGroups fails.
<li><font color="#777777">(SMACK-91)</font> Add support for Service Discovery (JEP 30) as a Smack Extension.
<li><font color="#777777">(SMACK-94)</font> Host name as reported by server should be used in the Connection object.
<li><font color="#777777">(SMACK-97)</font> SUBSCRIPTION_* constants are misspelled in the Roster class.
<li><font color="#777777">(SMACK-107)</font> Allow packet reply timeout to be set.
<li><font color="#777777">(SMACK-41)</font> Unrecognized IQs should generate a "not implemented" error.
<li><font color="#777777">(SMACK-116)</font> Roster entries are not being removed from the group immediately when deleted.
<li><font color="#777777">(SMACK-100)</font> Incoming packets should only have ID's if they are set.
<li><font color="#777777">(SMACK-104)</font> Fixed bug parsing server information.
<li><font color="#777777">(SMACK-112)</font> Add a mechanism to set the roster's subscription mode before login.
<li><font color="#777777">(SMACK-117)</font> PacketWriter never terminates daemon threads.
<li><font color="#777777">(SMACK-113)</font> Once a debugger gets closed it still collects packets - OutOfMemory problem.
<li><font color="#777777">(SMACK-102)</font> Add methods to get all packet providers.
<li><font color="#777777">(SMACK-95)</font> Add group chat invitation support as a Smack Extension.
<li><font color="#777777">(SMACK-93)</font> New debug window with many enhancements.
<li><font color="#777777">(SMACK-110)</font> Added keep-alives so the TCP-IP timeouts wouldn't break connections to a server.
<li><font color="#777777">(SMACK-101)</font> Add version number information to API.
<li><font color="#777777">(SMACK-96)</font> Make AndFilter and OrFilter chainable.
<li><font color="#777777">(SMACK-108)</font> Handle multiple presences when a user is connected from different resources.
<li><font color="#777777">(SMACK-111)</font> Add listener support for new connections.
<li><font color="#777777">(SMACK-92)</font> Add support for "Discovering Support for XHTML-IM".
<li><font color="#777777">(SMACK-106)</font> Chat objects no longer have to depend on a threadID (this is settable).
<li><font color="#777777">(SMACK-120)</font> Chat.getChatID() is now Chat.getThreadID().
</ul>
<p>
<b>1.2.1</b> - September 28, 2003
<p>
<ul>
<li><font color="#777777">(SMACK-79)</font> Added XHTML message support as a Smack extension, which allows sending
richly formatted messages.
<li><font color="#777777">(SMACK-88)</font> Fixed bug with parsing registation packets that contain extra data.
<li><font color="#777777">(SMACK-90)</font> Added support for getting registration instructions.
<li><font color="#777777">(SMACK-85)</font> Exceptions in the PacketWriter now correctly generates a connection
error event.
<li><font color="#777777">(SMACK-84)</font> Added <tt>isSecureConnection()</tt> method to XMPPConnection class.
<li><font color="#777777">(SMACK-86)</font> Added <tt>isJoined()</tt> method to GroupChat class.
<li><font color="#777777">(SMACK-87, SMACK-82)</font> Added the following methods related to rosters:
<tt>Roster.contains(String user)</tt>, <tt>Roster.getEntry(String user)</tt>,
<tt>RosterGroup.getEntry(String user)</tt>, <tt>Roster.removeEntry(RosterEntry entry)</tt>.
<li><font color="#777777">(SMACK-73)</font> Fixed bugs handling roster remove and update operations.
</ul>
<p>
<b>1.2.0</b> - August 29, 2003
<p>
<ul>
<li><font color="red"><b>!</b></font> A package structure and documentation has been added for Smack extensions,
which cover extensions to the XMPP protocol. The initial extensions are
for message events (JEP 22), roster item exchange (JEP 93), entity
time (JEP 90), and private data storage (JEP 49).
<li><font color="red"><b>!</b></font> The smack.providers file is now loaded from META-INF/smack.providers
rather than WEB-INF/smack.providers. This location makes much more sense
for generic JAR files, but may break existing provider implementations
until the provider file is moved.
<li>Fixed IQ error sub-packets.
<li>The default packet extension handler didn't deal with empty
elements well and also had a bug with attribute handling.
<li>Added a ConnectionListener feature which allows clients
to be notified of normally closed connections, and connections
closed due to errors.
<li>Fixed bug where the roster list could become corrupted after
moving a user back and forther between groups.
<li>Fixed bug where in some cases presence packets were not getting
tracked by the Roster class correctly.
<li>RosterListener has a new notification method that is called every time
the presence of a user in the roster is updated.
<li>Added Roster.getEntries() method to return all entries in the roster.
<li>Added RosterGroup.contains(String) method to check to see if an XMPP
address is part of the group.
<li>Minor fixes to Javadocs.
<li>Content can be copied and cleared from the debug window using
a pop-up menu.
<li>The Chat constructor that took an existing chatID as an argument
did not propertly initialize support for message listeners.
<li>Added support for anonymous logins.
<li>IQ is now an abstract class.
<li>Fixed bug where XHTML messgaes could cause parsing errors.
</ul>
<p>
<b>1.1.1</b> - June 25, 2003
<p>
<ul>
<li>Setting Object packet properties was broken.
<li>Added getRoom() method to GroupChat.
</ul>
<p>
<b>1.1.0</b> - June 19, 2003
<p>
<ul>
<li>New system to handle custom IQ packets and custom packet extensions through
the new provider sub-package.
<li>Added packet filters for packet extensions.
<li>Added additional options for responding to subscription requests.
<li>Added method to retrieve the roster item count from roster packets.
<li>Added ability to set the ItemStatus on a roster packet.
<li>Added remove option to roster packet.
<li>Various documentation fixes/improvements.
<li>Fixed NullPointer exception on the setName method of the RosterEntry class.
<li>Groupchat class was listening for wrong message types -- fixed.
<li>Changed properties element name to "properties" instead of "x". <b>Note:</b> this will
break compatability between earlier versions if they are trying to send packet
properties back and forth. However, we thought it was best to make this change now.
<li>Turning on debugging via a system property wasn't working.
<li>Fixed spelling error in Roster class method name.
<li>Fixed stream not being closed properly.
<li>The "to contains" and "from contains" filters now ignore case.
</ul>
<p>
<b>1.0.1</b> - April 30, 2003
<p>
<ul>
<li>Fixed bug that caused applets using Smack to crash with a security exception.
</ul>
<p>
<b>1.0.0</b> - April 25, 2003
<p>
<ul>
<li>Initial official release.
</ul>
</body>
</html>

View File

@ -0,0 +1,116 @@
<html>
<head>
<title>Smack: Debugging - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">
Debugging with Smack
</div>
<div class="nav">
&laquo; <a href="index.html">Table of Contents</a>
</div>
<p>
Smack includes two built-in debugging consoles that will let you track all XML traffic between
the client and server. A <a href="#lite">lite debugger</a> which is part of the <tt>smack.jar</tt>
and an <a href="#enhanced">enhanced debugger</a> contained in <tt>smackx-debug.jar</tt>.
</p>
<p>
Debugging mode can be enabled in two different ways:
</p>
<ol>
<li>Add the following line of code <b>before</b> creating new connections:<p>
<tt>XMPPConnection.DEBUG_ENABLED = true;</tt><p>
<li>Set the Java system property <tt>smack.debugEnabled</tt> to true. The
system property can be set on the command line such as:<p>
<tt>java -Dsmack.debugEnabled=true SomeApp </tt>
</ol>
<p>
If you wish to explicitly disable debug mode in your application, including using the command-line parameter,
add the following line to your application before opening new connections:
</p>
<p>
<tt>XMPPConnection.DEBUG_ENABLED = false;</tt>
</p>
<p>
Smack uses the following logic to decide the debugger console to use:
</p>
<ol>
<li>It will first try use the debugger class specified in the Java system property
<tt>smack.debuggerClass</tt>. If you need to develop your own debugger,
implement the <tt>SmackDebugger</tt> interface and then set the system property
on the command line such as:<p>
<tt>java -Dsmack.debuggerClass=my.company.com.MyDebugger SomeApp </tt><p>
<li>If step 1 fails then Smack will try to use the enhanced debugger. The
file <tt>smackx-debug.jar</tt> contains the enhanced debugger. Therefore you will need
to place the jar file in the classpath. For situations where space is an issue you
may want to only deploy <tt>smack.jar</tt> in which case the enhanced debugger won't be
available.<p>
<li>The last option if the previous two steps fail is to use the lite debugger. The lite
debugger is a very good option for situations where you need to have low memory footprint.
</ol>
<p class="subheader">
<a name="enhanced">Enhanced Debugger</a>
</p>
<img src="images/enhanceddebugger.png" width="479" height="400" alt="Full Debug Window" border="0" align="right">
When debugging mode is enabled, a debug window will appear containing tabs for each new created connection.
The window will contain the following information:
<ul>
<li>Connection tabs -- each tab shows debugging information related to the connection.
<li>Smack info tab -- shows information about Smack (e.g. Smack version, installed components, etc.).
</ul>
The connection tab will contain the following information:
<ul>
<li>All Packets -- shows sent and received packets information parsed by Smack.
<li>Raw Sent Packets -- raw XML traffic generated by Smack and sent to the server.
<li>Raw Received Packets -- raw XML traffic sent by the server to the client.
<li>Ad-hoc message -- allows to send ad-hoc packets of any type.
<li>Information -- shows connection state and statistics.
</ul>
<br clear="right">
<p class="subheader">
<a name="lite">Lite Debugger</a>
</p>
<img src="images/debugwindow.gif" width="359" height="399" alt="Lite Debug Window" border="0" align="right">
When debugging mode is enabled, a debug window will appear when each new connection is created.
The window will contain the following information:
<ul>
<li>Client Traffic (red text) -- raw XML traffic generated by Smack and sent to the server.
<li>Server Traffic (blue text) -- raw XML traffic sent by the server to the client.
<li>Interpreted Packets (green text) -- shows XML packets from the server as parsed by Smack.
</ul>
Right click on any of the panes to bring up a menu with the choices to copy of the contents
to the system clipboard or to clear the contents of the pane.
<br clear="all" /><br><br>
<div class="footer">
Copyright &copy; Jive Software 2002-2005
</div>
</body>
</html>

View File

@ -0,0 +1,137 @@
<html>
<head>
<title>Data Forms</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Data Forms</div><p>
Allows to exchange structured data between users and applications for common
tasks such as registration and searching using Forms.
<ul>
<li><a href="#gather">Create a Form to fill out</a></li>
<li><a href="#fillout">Answer a Form</a></li>
</ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0004.html">JEP-4</a>
<hr>
<div class="subheader"><a name="gather">Create a Form to fill out</a></div><p>
<b>Description</b><p>
An XMPP entity may need to gather data from another XMPP entity. Therefore, the data-gathering
entity will need to create a new Form, specify the fields that will conform the Form and finally
send the Form to the data-providing entity.</p>
<b>Usage</b><p>
In order to create a Form to fill out use the <i><b>Form</b></i>'s constructor passing the constant
<b>Form.TYPE_FORM</b> as the parameter. The next step is to create the form fields and add them to
the form. In order to create and customize a <i><b>FormField</b></i> use the <i><b>FormField</b></i>'s
constructor specifying the variable name of the field as the parameter. Then use <b>setType(String type)</b>
to set the field's type (e.g. FormField.TYPE_HIDDEN, FormField.TYPE_TEXT_SINGLE). Once we have the
<i><b>Form</b></i> instance and the <i><b>FormFields</b></i> the last step is to send <b>addField(FormField field)</b>
for each field that we want to add to the form.</p><p>
Once the form to fill out is finished we will want to send it in a message. Send <b>getDataFormToSend()</b> to
the form and add the answer as an extension to the message to send.</p>
<b>Examples</b><p>
In this example we can see how to create and send a form to fill out: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Create a new form to gather data</font>
Form formToSend = new Form(Form.TYPE_FORM);
formToSend.setInstructions(
"Fill out this form to report your case.\nThe case will be created automatically.");
formToSend.setTitle("Case configurations");
<font color="#3f7f5f">// Add a hidden variable to the form</font>
FormField field = new FormField("hidden_var");
field.setType(FormField.TYPE_HIDDEN);
field.addValue("Some value for the hidden variable");
formToSend.addField(field);
<font color="#3f7f5f">// Add a fixed variable to the form</font>
field = new FormField();
field.addValue("Section 1: Case description");
formToSend.addField(field);
<font color="#3f7f5f">// Add a text-single variable to the form</font>
field = new FormField("name");
field.setLabel("Enter a name for the case");
field.setType(FormField.TYPE_TEXT_SINGLE);
formToSend.addField(field);
<font color="#3f7f5f">// Add a text-multi variable to the form</font>
field = new FormField("description");
field.setLabel("Enter a description");
field.setType(FormField.TYPE_TEXT_MULTI);
formToSend.addField(field);
<font color="#3f7f5f">// Create a chat with "user2@host.com"</font>
Chat chat = conn1.createChat("user2@host.com" );
Message msg = chat.createMessage();
msg.setBody("To enter a case please fill out this form and send it back to me");
<font color="#3f7f5f">// Add the form to fill out to the message to send</font>
msg.addExtension(formToSend.getDataFormToSend());
<font color="#3f7f5f">// Send the message with the form to fill out</font>
chat.sendMessage(msg);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="fillout">Answer a Form</a></div><p>
<b>Description</b><p>
Under many situations an XMPP entity could receive a form to fill out. For example, some hosts
may require to fill out a form in order to register new users. Smack lets the data-providing entity
to complete the form in an easy way and send it back to the data-gathering entity.</p>
<b>Usage</b><p>
The form to fill out contains useful information that could be used for rendering the form. But it
cannot be used to actually complete it. Instead it's necessary to create a new form based on the original
form whose purpose is to hold all the answers.</p><p>
In order to create a new <i><b>Form</b></i> to complete based on the original <i><b>Form</b></i> just send
<b>createAnswerForm()</b> to the original <i><b>Form</b></i>. Once you have a valid form that could be actually
completed all you have to do is send <b>setAnswer(String variable, String value)</b> to the form where variable
is the variable of the <i><b>FormField</b></i> that you want to answer and value is the String representation
of the answer. If the answer consist of several values you could then use <b>setAnswer(String variable, List values)</b>
where values is a List of Strings.</p><p>
Once the form has been completed we will want to send it back in a message. Send <b>getDataFormToSend()</b> to
the form and add the answer as an extension to the message to send back.</p>
<b>Examples</b><p>
In this example we can see how to retrieve a form to fill out, complete the form and send it back: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Get the message with the form to fill out</font>
Message msg2 = chat2.nextMessage();
<font color="#3f7f5f">// Retrieve the form to fill out from the message</font>
Form formToRespond = Form.getFormFrom(msg2);
<font color="#3f7f5f">// Obtain the form to send with the replies</font>
Form completedForm = formToRespond.createAnswerForm();
<font color="#3f7f5f">// Add the answers to the form</font>
completedForm.setAnswer("name", "Credit card number invalid");
completedForm.setAnswer(
"description",
"The ATM says that my credit card number is invalid. What's going on?");
msg2 = chat2.createMessage();
msg2.setBody("To enter a case please fill out this form and send it back to me");
<font color="#3f7f5f">// Add the completed form to the message to send back</font>
msg2.addExtension(completedForm.getDataFormToSend());
<font color="#3f7f5f">// Send the message with the completed form</font>
chat2.sendMessage(msg2);
</pre>
</blockquote>
</body>
</html>

View File

@ -0,0 +1,236 @@
<html>
<head>
<title>Service Discovery</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Service Discovery</div><p>
The service discovery extension allows to discover items and information about XMPP
entities. Follow these links to learn how to use this extension.
<ul>
<li><a href="#discoregister">Manage XMPP entity features</a></li>
<li><a href="#disconodeinfo">Provide node information</a></li>
<li><a href="#discoitems">Discover items associated with an XMPP entity</a></li>
<li><a href="#discoinfo">Discover information about an XMPP entity</a></li>
<li><a href="#discopublish">Publish publicly available items</a></li>
</ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0030.html">JEP-30</a>
<hr>
<div class="subheader"><a name="discoregister">Manage XMPP entity features</a></div><p>
<b>Description</b><p>
Any XMPP entity may receive a discovery request and must answer with its associated items or
information. Therefore, your Smack client may receive a discovery request that must respond
to (i.e., if your client supports XHTML-IM). This extension automatically responds to a
discovery request with the information that you previously configured.</p>
<b>Usage</b><p>
In order to configure the supported features by your client you should first obtain the
ServiceDiscoveryManager associated with your XMPPConnection. To get your ServiceDiscoveryManager
send <b>getInstanceFor(connection)</b> to the class <i><b>ServiceDiscoveryManager</b></i> where
connection is your XMPPConnection.<br></p>
<p>Once you have your ServiceDiscoveryManager you will be able to manage the supported features. To
register a new feature send <b>addFeature(feature)</b> to your <i><b>ServiceDiscoveryManager</b></i>
where feature is a String that represents the supported feature. To remove a supported feature send
<b>removeFeature(feature)</b> to your <i><b>ServiceDiscoveryManager</b></i> where feature is a
String that represents the feature to remove.</p>
<b>Examples</b><p>
In this example we can see how to add and remove supported features: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Obtain the ServiceDiscoveryManager associated with my XMPPConnection</font>
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
<font color="#3f7f5f">// Register that a new feature is supported by this XMPP entity</font>
discoManager.addFeature(namespace1);
<font color="#3f7f5f">// Remove the specified feature from the supported features by this XMPP entity</font>
discoManager.removeFeature(namespace2);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="disconodeinfo">Provide node information</a></div><p>
<b>Description</b><p>
Your XMPP entity may receive a discovery request for items non-addressable as a JID such as
the MUC rooms where you are joined. In order to answer the correct information it is necessary
to configure the information providers associated to the items/nodes within the Smack client.</p>
<b>Usage</b><p>
In order to configure the associated nodes within the Smack client you will need to create a
NodeInformationProvider and register it with the <i><b>ServiceDiscoveryManager</b></i>. To get
your ServiceDiscoveryManager send <b>getInstanceFor(connection)</b> to the class <i><b>ServiceDiscoveryManager</b></i>
where connection is your XMPPConnection.<br></p>
<p>Once you have your ServiceDiscoveryManager you will be able to register information providers
for the XMPP entity's nodes. To register a new node information provider send <b>setNodeInformationProvider(String node, NodeInformationProvider listener)</b>
to your <i><b>ServiceDiscoveryManager</b></i> where node is the item non-addressable as a JID and
listener is the <i><b>NodeInformationProvider</b></i> to register. To unregister a <i><b>NodeInformationProvider</b></i>
send <b>removeNodeInformationProvider(String node)</b> to your <i><b>ServiceDiscoveryManager</b></i> where
node is the item non-addressable as a JID whose information provider we want to unregister.</p>
<b>Examples</b><p>
In this example we can see how to register a NodeInformationProvider with a ServiceDiscoveryManager that will provide
information concerning a node named "http://jabber.org/protocol/muc#rooms": <br>
<blockquote>
<pre> <font color="#3f7f5f">// Set the NodeInformationProvider that will provide information about the</font>
<font color="#3f7f5f">// joined rooms whenever a disco request is received </font>
ServiceDiscoveryManager.getInstanceFor(connection).setNodeInformationProvider(
<font color="#0000FF">"http://jabber.org/protocol/muc#rooms"</font>,
new NodeInformationProvider() {
public Iterator getNodeItems() {
ArrayList answer = new ArrayList();
Iterator rooms = MultiUserChat.getJoinedRooms(connection);
while (rooms.hasNext()) {
answer.add(new DiscoverItems.Item((String)rooms.next()));
}
return answer.iterator();
}
});
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="discoitems">Discover items associated with an XMPP entity</a></div><p>
<b>Description</b><p>
In order to obtain information about a specific item you have to first discover the items available
in an XMPP entity.</p>
<b>Usage</b><p>
<p>Once you have your ServiceDiscoveryManager you will be able to discover items associated with
an XMPP entity. To discover the items of a given XMPP entity send <b>discoverItems(entityID)</b>
to your <i><b>ServiceDiscoveryManager</b></i> where entityID is the ID of the entity. The message
<b>discoverItems(entityID)</b> will answer an instance of <i><b>DiscoverItems</b></i> that contains
the discovered items.</p>
<b>Examples</b><p>
In this example we can see how to discover the items associated with an online catalog service: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Obtain the ServiceDiscoveryManager associated with my XMPPConnection</font>
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
<font color="#3f7f5f">// Get the items of a given XMPP entity</font>
<font color="#3f7f5f">// This example gets the items associated with online catalog service</font>
DiscoverItems discoItems = discoManager.discoverItems("plays.shakespeare.lit");
<font color="#3f7f5f">// Get the discovered items of the queried XMPP entity</font>
Iterator it = discoItems.getItems();
<font color="#3f7f5f">// Display the items of the remote XMPP entity</font>
while (it.hasNext()) {
DiscoverItems.Item item = (DiscoverItems.Item) it.next();
System.out.println(item.getEntityID());
System.out.println(item.getNode());
System.out.println(item.getName());
}
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="discoinfo">Discover information about an XMPP entity</a></div><p>
<b>Description</b><p>
Once you have discovered the entity ID and name of an item, you may want to find out more
about the item. The information desired generally is of two kinds: 1) The item's identity
and 2) The features offered by the item.</p>
<p>This information helps you determine what actions are possible with regard to this
item (registration, search, join, etc.) as well as specific feature types of interest, if
any (e.g., for the purpose of feature negotiation).</p>
<b>Usage</b><p>
<p>Once you have your ServiceDiscoveryManager you will be able to discover information associated with
an XMPP entity. To discover the information of a given XMPP entity send <b>discoverInfo(entityID)</b>
to your <i><b>ServiceDiscoveryManager</b></i> where entityID is the ID of the entity. The message
<b>discoverInfo(entityID)</b> will answer an instance of <i><b>DiscoverInfo</b></i> that contains
the discovered information.</p>
<b>Examples</b><p>
In this example we can see how to discover the information of a conference room: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Obtain the ServiceDiscoveryManager associated with my XMPPConnection</font>
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
<font color="#3f7f5f">// Get the information of a given XMPP entity</font>
<font color="#3f7f5f">// This example gets the information of a conference room</font>
DiscoverInfo discoInfo = discoManager.discoverInfo("balconyscene@plays.shakespeare.lit");
<font color="#3f7f5f">// Get the discovered identities of the remote XMPP entity</font>
Iterator it = discoInfo.getIdentities();
<font color="#3f7f5f">// Display the identities of the remote XMPP entity</font>
while (it.hasNext()) {
DiscoverInfo.Identity identity = (DiscoverInfo.Identity) it.next();
System.out.println(identity.getName());
System.out.println(identity.getType());
System.out.println(identity.getCategory());
}
<font color="#3f7f5f">// Check if room is password protected</font>
discoInfo.containsFeature("muc_passwordprotected");
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="discopublish">Publish publicly available items</a></div><p>
<b>Description</b><p>
Publish your entity items to some kind of persistent storage. This enables other entities to query
that entity using the disco#items namespace and receive a result even when the entity being queried
is not online (or available).</p>
<b>Usage</b><p>
<p>Once you have your ServiceDiscoveryManager you will be able to publish items to some kind of
persistent storage. To publish the items of a given XMPP entity you have to first create an instance
of <i><b>DiscoverItems</b></i> and configure it with the items to publish. Then you will have to
send <b>publishItems(String entityID, DiscoverItems discoverItems)</b> to your <i><b>ServiceDiscoveryManager</b></i>
where entityID is the address of the XMPP entity that will persist the items and discoverItems contains the items
to publish.</p>
<b>Examples</b><p>
In this example we can see how to publish new items: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Obtain the ServiceDiscoveryManager associated with my XMPPConnection</font>
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
<font color="#3f7f5f">// Create a DiscoverItems with the items to publish</font>
DiscoverItems itemsToPublish = new DiscoverItems();
DiscoverItems.Item itemToPublish = new DiscoverItems.Item("pubsub.shakespeare.lit");
itemToPublish.setName("Avatar");
itemToPublish.setNode("romeo/avatar");
itemToPublish.setAction(DiscoverItems.Item.UPDATE_ACTION);
itemsToPublish.addItem(itemToPublish);
<font color="#3f7f5f">// Publish the new items by sending them to the server</font>
discoManager.publishItems("host", itemsToPublish);
</pre>
</blockquote>
</body>
</html>

View File

@ -0,0 +1,15 @@
<html>
<head>
<title>Smack Extensions User Manual</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<frameset cols="200,*">
<frame src="toc.html" name="navFrame" target="mainFrame">
<frame src="intro.html" name="mainFrame">
</frameset>
<noframes>
<H2>Smack Extensions User Manual</H2>
<a href="toc.html">Smack Extensions User Manual</a></noframes></html>

View File

@ -0,0 +1,70 @@
<html>
<head>
<title>Smack Extensions User Manual</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Smack Extensions Manual</div>
<p>The XMPP protocol includes a base protocol and many optional extensions
typically documented as "JEP's". Smack provides the org.jivesoftware.smack
package for the core XMPP protocol, and the org.jivesoftware.smackx package for
many of the protocol extensions.</p>
<p>This manual provides details about each of the "smackx" extensions, including what
it is, how to use it, and some simple example code.<p>
<div class="subheader">Current Extensions</div><p>
<table border="0" width="85%" cellspacing="0" cellpadding="3" style="border:1px #bbb solid;">
<tr bgcolor="#ddeeff">
<td><b>Name</b></td><td><b>JEP #</b></td><td><b>Description</b></td>
</tr>
<tr>
<td><a href="privatedata.html">Private Data</a></td>
<td><a href="http://www.jabber.org/jeps/jep-0049.html">JEP-49</a></td>
<td>Manages private data.</td>
</tr>
<tr>
<td><a href="xhtml.html">XHTML Messages</a></td>
<td><a href="http://www.jabber.org/jeps/jep-0071.html">JEP-71</a></td>
<td>Allows send and receiving formatted messages using XHTML.</td>
</tr>
<tr>
<td><a href="messageevents.html">Message Events</a></td>
<td><a href="http://www.jabber.org/jeps/jep-0022.html">JEP-22</a></td>
<td>Requests and responds to message events.</td>
</tr>
<tr>
<td><a href="dataforms.html">Data Forms</a></td>
<td><a href="http://www.jabber.org/jeps/jep-0004.html">JEP-4</a></td>
<td>Allows to gather data using Forms.</td>
</tr>
<tr>
<td><a href="muc.html">Multi User Chat</a></td>
<td><a href="http://www.jabber.org/jeps/jep-0045.html">JEP-45</a></td>
<td>Allows configuration of, participation in, and administration of individual text-based conference rooms.</td>
</tr>
<tr>
<td><a href="rosterexchange.html">Roster Item Exchange</a></td>
<td><a href="http://www.jabber.org/jeps/jep-0093.html">JEP-93</a></td>
<td>Allows roster data to be shared between users.</td>
</tr>
<tr>
<td><a href="time.html">Time Exchange</a></td>
<td><a href="http://www.jabber.org/jeps/jep-0090.html">JEP-90</a></td>
<td>Allows local time information to be shared between users.</td>
</tr>
<tr>
<td><a href="invitation.html">Group Chat Invitations</a></td>
<td>N/A</td>
<td>Send invitations to other users to join a group chat room.</td>
</tr>
<tr>
<td><a href="disco.html">Service Discovery</a></td>
<td><a href="http://www.jabber.org/jeps/jep-0030.html">JEP-30</a></td>
<td>Allows to discover services in XMPP entities.</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,60 @@
<html>
<head>
<title>Group Chat Invitations</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Group Chat Invitations</div><p>
The group chat invitation packet extension is used to invite other
users to a group chat room.
<ul>
<li><a href="#send">Inviting Other Users</a></li>
<li><a href="#listen">Listen for Invitations</a></li>
</ul>
<p>
<b>JEP related:</b> N/A -- this protocol is outdated now that the Multi-User Chat (MUC) JEP is available
(<a href="http://www.jabber.org/jeps/jep-0045.html">JEP-45</a>). However, most
existing clients still use this older protocol. Once MUC support becomes more
widespread, this API may be deprecated.
<hr>
<p><div class="subheader"><a name="send">Inviting Other Users</a></div><p>
To use the GroupChatInvitation packet extension
to invite another user to a group chat room, address a new message to the
user and set the room name appropriately, as in the following code example:
<pre>
Message message = new Message(<font color="#0000FF">"user@chat.example.com"</font>);
message.setBody(<font color="#0000FF">"Join me for a group chat!"</font>);
message.addExtension(new GroupChatInvitation(<font color="#0000FF">"room@chat.example.com"</font>));
con.sendPacket(message);
</pre>
The XML generated for the invitation portion of the code above would be:
<pre>
&lt;x xmlns="jabber:x:conference" jid="room@chat.example.com"/&gt;
</pre><p>
<hr>
<div class="subheader"><a name="listen">Listening for Invitations</a></div><p>
To listen for group chat invitations, use a PacketExtensionFilter for the
<tt>x</tt> element name and <tt>jabber:x:conference</tt> namespace, as in the
following code example:
<pre>
PacketFilter filter = new PacketExtensionFilter(<font color="#0000FF">"x"</font>, <font color="#0000FF">"jabber:x:conference"</font>);
<font color="#3f7f5f">// Create a packet collector or packet listeners using the filter...</font>
</pre>
</body>
</html>

View File

@ -0,0 +1,244 @@
<html>
<head>
<title>Message Events</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Message Events</div><p>
This extension is used to request and respond to events relating to the delivery,
display, and composition of messages. There are three stages in this extension:<ol>
<li>Request for event notifications,
<li>Receive the event notification requests and send event notifications, and
<li>Receive the event notifications.</ol>
<p>For more information on each stage please follow these links:</p>
<ul>
<li><a href="#reqevnot">Requesting Event Notifications</a></li>
<li><a href="#lstevnotreq">Reacting to Event Notification Requests</a></li>
<li><a href="#lstevnot">Reacting to Event Notifications</a></li>
</ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0022.html">JEP-22</a>
<hr>
<div class="subheader"><a name="reqevnot">Requesting Event Notifications</a></div><p>
<b>Description</b><p>
In order to receive event notifications for a given message you first have to specify
which events are you interested in. Each message that you send has to request its own event
notifications. Therefore, every message that you send as part of a chat should request its own event
notifications.</p>
<b>Usage</b><p>
The class <i>MessageEventManager</i> provides an easy way for requesting event notifications. All you have to do is specify
the message that requires the event notifications and the events that you are interested in.
<p>Use the static method <i><b>MessageEventManager.addNotificationsRequests(Message message, boolean offline, boolean
delivered, boolean displayed, boolean composing)</b></i> for requesting event notifications.
</p>
<b>Example</b><p>
Below you can find an example that logs in a user to the server, creates a message, adds the requests
for notifications and sends the message.
<blockquote>
<pre> <font color="#3f7f5f">// Connect to the server and log in</font>
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
<font color="#3f7f5f">// Create a chat with user2</font>
Chat chat1 = conn1.createChat(user2);
<font color="#3f7f5f">// Create a message to send</font>
Message msg = chat1.createMessage();
msg.setSubject(<font color="#0000FF">"Any subject you want"</font>);
msg.setBody(<font color="#0000FF">"An interesting body comes here..."</font>);
<font color="#3f7f5f">// Add to the message all the notifications requests (offline, delivered, displayed,</font>
<font color="#3f7f5f">// composing)</font>
MessageEventManager.addNotificationsRequests(msg, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>);
<font color="#3f7f5f">// Send the message that contains the notifications request</font>
chat1.sendMessage(msg);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="lstevnotreq">Reacting to Event Notification Requests</a></div><p>
<b>Description</b><p>
You can receive notification requests for the following events: delivered, displayed, composing and offline. You
<b>must</b> listen for these requests and react accordingly.</p>
<b>Usage</b><p>
The general idea is to create a new <i>DefaultMessageEventRequestListener</i> that will listen to the event notifications
requests and react with custom logic. Then you will have to add the listener to the
<i>MessageEventManager</i> that works on
the desired <i>XMPPConnection</i>.
<p>Note that <i>DefaultMessageEventRequestListener</i> is a default implementation of the
<i>MessageEventRequestListener</i> interface.
The class <i>DefaultMessageEventRequestListener</i> automatically sends a delivered notification to the sender of the message
if the sender has requested to be notified when the message is delivered. If you decide to create a new class that
implements the <i>MessageEventRequestListener</i> interface, please remember to send the delivered notification.</p>
<ul>
<li>To create a new <i>MessageEventManager</i> use the <i><b>MessageEventManager(XMPPConnection)</b></i> constructor.
</li>
<li>To create an event notification requests listener create a subclass of <i><b>DefaultMessageEventRequestListener</b></i> or
create a class that implements the <i><b>MessageEventRequestListener</b></i> interface.
</li>
<li>To add a listener to the messageEventManager use the MessageEventManager's message
<i><b>addMessageEventRequestListener(MessageEventRequestListener)</b></i>.</li>
</ul></p>
<b>Example</b><p>
Below you can find an example that connects two users to the server. One user will create a message, add the requests
for notifications and will send the message to the other user. The other user will add a
<i>DefaultMessageEventRequestListener</i>
to a <i>MessageEventManager</i> that will listen and react to the event notification requested by the other user.
<blockquote>
<pre> <font color="#3f7f5f">// Connect to the server and log in the users</font>
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
conn2 = new XMPPConnection(host);
conn2.login(server_user2, pass2);
<font color="#3f7f5f">// User2 creates a MessageEventManager</font>
MessageEventManager messageEventManager = new MessageEventManager(conn2);
<font color="#3f7f5f">// User2 adds the listener that will react to the event notifications requests</font>
messageEventManager.addMessageEventRequestListener(new DefaultMessageEventRequestListener() {
public void deliveredNotificationRequested(
String from,
String packetID,
MessageEventManager messageEventManager) {
super.deliveredNotificationRequested(from, packetID, messageEventManager);
<font color="#3f7f5f">// DefaultMessageEventRequestListener automatically responds that the message was delivered when receives this request</font>
System.out.println(<font color="#0000FF">"Delivered Notification Requested (" + from + ", " + packetID + ")"</font>);
}
public void displayedNotificationRequested(
String from,
String packetID,
MessageEventManager messageEventManager) {
super.displayedNotificationRequested(from, packetID, messageEventManager);
<font color="#3f7f5f">// Send to the message's sender that the message was displayed</font>
messageEventManager.sendDisplayedNotification(from, packetID);
}
public void composingNotificationRequested(
String from,
String packetID,
MessageEventManager messageEventManager) {
super.composingNotificationRequested(from, packetID, messageEventManager);
<font color="#3f7f5f">// Send to the message's sender that the message's receiver is composing a reply</font>
messageEventManager.sendComposingNotification(from, packetID);
}
public void offlineNotificationRequested(
String from,
String packetID,
MessageEventManager messageEventManager) {
super.offlineNotificationRequested(from, packetID, messageEventManager);
<font color="#3f7f5f">// The XMPP server should take care of this request. Do nothing.</font>
System.out.println(<font color="#0000FF">"Offline Notification Requested (" + from + ", " + packetID + ")"</font>);
}
});
<font color="#3f7f5f">// User1 creates a chat with user2</font>
Chat chat1 = conn1.createChat(user2);
<font color="#3f7f5f">// User1 creates a message to send to user2</font>
Message msg = chat1.createMessage();
msg.setSubject(<font color="#0000FF">"Any subject you want"</font>);
msg.setBody(<font color="#0000FF">"An interesting body comes here..."</font>);
<font color="#3f7f5f">// User1 adds to the message all the notifications requests (offline, delivered, displayed,</font>
<font color="#3f7f5f">// composing)</font>
MessageEventManager.addNotificationsRequests(msg, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>);
<font color="#3f7f5f">// User1 sends the message that contains the notifications request</font>
chat1.sendMessage(msg);
Thread.sleep(500);
<font color="#3f7f5f">// User2 sends to the message's sender that the message's receiver cancelled composing a reply</font>
messageEventManager.sendCancelledNotification(user1, msg.getPacketID());
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="lstevnot">Reacting to Event Notifications</a></div><p>
<b>Description</b><p>
Once you have requested for event notifications you will start to receive notifications of events. You can
receive notifications of the following events: delivered, displayed, composing, offline and cancelled. You
will probably want to react to some or all of these events.</p>
<b>Usage</b><p>
The general idea is to create a new <i>MessageEventNotificationListener</i> that will listen to the event notifications
and react with custom logic. Then you will have to add the listener to the <i>MessageEventManager</i> that works on
the desired <i>XMPPConnection</i>.
<ul>
<li>To create a new <i>MessageEventManager</i> use the <i><b>MessageEventManager(XMPPConnection)</b></i> constructor.
</li>
<li>To create an event notifications listener create a class that implements the <i><b>MessageEventNotificationListener</b></i>
interface.
</li>
<li>To add a listener to the messageEventManager use the MessageEventManager's message
<i><b>addMessageEventNotificationListener(MessageEventNotificationListener)</b></i>.</li>
</ul></p>
<b>Example</b><p>
Below you can find an example that logs in a user to the server, adds a <i>MessageEventNotificationListener</i>
to a <i>MessageEventManager</i> that will listen and react to the event notifications, creates a message, adds
the requests for notifications and sends the message.
<blockquote>
<pre> <font color="#3f7f5f">// Connect to the server and log in</font>
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
<font color="#3f7f5f">// Create a MessageEventManager</font>
MessageEventManager messageEventManager = new MessageEventManager(conn1);
<font color="#3f7f5f">// Add the listener that will react to the event notifications</font>
messageEventManager.addMessageEventNotificationListener(new MessageEventNotificationListener() {
public void deliveredNotification(String from, String packetID) {
System.out.println(<font color="#0000FF">"The message has been delivered (" + from + ", " + packetID + ")"</font>);
}
public void displayedNotification(String from, String packetID) {
System.out.println(<font color="#0000FF">"The message has been displayed (" + from + ", " + packetID + ")"</font>);
}
public void composingNotification(String from, String packetID) {
System.out.println(<font color="#0000FF">"The message's receiver is composing a reply (" + from + ", " + packetID + ")"</font>);
}
public void offlineNotification(String from, String packetID) {
System.out.println(<font color="#0000FF">"The message's receiver is offline (" + from + ", " + packetID + ")"</font>);
}
public void cancelledNotification(String from, String packetID) {
System.out.println(<font color="#0000FF">"The message's receiver cancelled composing a reply (" + from + ", " + packetID + ")"</font>);
}
});
<font color="#3f7f5f">// Create a chat with user2</font>
Chat chat1 = conn1.createChat(user2);
<font color="#3f7f5f">// Create a message to send</font>
Message msg = chat1.createMessage();
msg.setSubject(<font color="#0000FF">"Any subject you want"</font>);
msg.setBody(<font color="#0000FF">"An interesting body comes here..."</font>);
<font color="#3f7f5f">// Add to the message all the notifications requests (offline, delivered, displayed,</font>
<font color="#3f7f5f">// composing)</font>
MessageEventManager.addNotificationsRequests(msg, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>, <font COLOR="#7f0055"><b>true</b></font>);
<font color="#3f7f5f">// Send the message that contains the notifications request</font>
chat1.sendMessage(msg);
</pre>
</blockquote>
</body>
</html>

View File

@ -0,0 +1,619 @@
<html>
<head>
<title>Multi User Chat</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Multi User Chat</div><p>
Allows configuration of, participation in, and administration of individual text-based conference rooms.<p>
<ul>
<li><a href="#create">Create a new Room</a></li>
<li><a href="#join">Join a room</a></li>
<li><a href="#invite">Manage room invitations</a></li>
<li><a href="#discomuc">Discover MUC support</a></li>
<li><a href="#discojoin">Discover joined rooms</a></li>
<li><a href="#discoroom">Discover room information</a></li>
<li><a href="#privchat">Start a private chat</a></li>
<li><a href="#subject">Manage changes on room subject</a></li>
<li><a href="#role">Manage role modifications</a></li>
<li><a href="#afiliation">Manage affiliation modifications</a></li>
</ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0045.html">JEP-45</a>
<hr>
<div class="subheader"><a name="create">Create a new Room</a></div><p>
<b>Description</b><p>
Allowed users may create new rooms. There are two types of rooms that you can create. <b>Instant rooms</b>
which are available for immediate access and are automatically created based on some default
configuration and <b>Reserved rooms</b> which are manually configured by the room creator before
anyone is allowed to enter.</p>
<b>Usage</b><p>
In order to create a room you will need to first create an instance of <i><b>MultiUserChat</b></i>. The
room name passed to the constructor will be the name of the room to create. The next step is to send
<b>create(String nickname)</b> to the <i><b>MultiUserChat</b></i> instance where nickname is the nickname
to use when joining the room.</p><p>
Depending on the type of room that you want to create you will have to use different configuration forms. In
order to create an Instant room just send <b>sendConfigurationForm(Form form)</b> where form is an empty form.
But if you want to create a Reserved room then you should first get the room's configuration form, complete
the form and finally send it back to the server.</p>
<b>Examples</b><p>
In this example we can see how to create an instant room: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Create a MultiUserChat using an XMPPConnection for a room</font>
MultiUserChat muc = new MultiUserChat(conn1, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
<font color="#3f7f5f">// Create the room</font>
muc.create(<font color="#0000FF">"testbot"</font>);
<font color="#3f7f5f">// Send an empty room configuration form which indicates that we want</font>
<font color="#3f7f5f">// an instant room</font>
muc.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));
</pre>
</blockquote>
In this example we can see how to create a reserved room. The form is completed with default values: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Create a MultiUserChat using an XMPPConnection for a room</font>
MultiUserChat muc = new MultiUserChat(conn1, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
<font color="#3f7f5f">// Create the room</font>
muc.create(<font color="#0000FF">"testbot"</font>);
<font color="#3f7f5f">// Get the the room's configuration form</font>
Form form = muc.getConfigurationForm();
<font color="#3f7f5f">// Create a new form to submit based on the original form</font>
Form submitForm = form.createAnswerForm();
<font color="#3f7f5f">// Add default answers to the form to submit</font>
for (Iterator fields = form.getFields(); fields.hasNext();) {
FormField field = (FormField) fields.next();
if (!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {
<font color="#3f7f5f">// Sets the default value as the answer</font>
submitForm.setDefaultAnswer(field.getVariable());
}
}
<font color="#3f7f5f">// Sets the new owner of the room</font>
List owners = new ArrayList();
owners.add(<font color="#0000FF">"johndoe@jabber.org"</font>);
submitForm.setAnswer(<font color="#0000FF">"muc#roomconfig_roomowners"</font>, owners);
<font color="#3f7f5f">// Send the completed form (with default values) to the server to configure the room</font>
muc.sendConfigurationForm(submitForm);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="join">Join a room</a></div><p>
<b>Description</b><p>
Your usual first step in order to send messages to a room is to join the room. Multi User Chat allows
to specify several parameter while joining a room. Basically you can control the amount of history to
receive after joining the room as well as provide your nickname within the room and a password if the
room is password protected.</p>
<b>Usage</b><p>
In order to join a room you will need to first create an instance of <i><b>MultiUserChat</b></i>. The
room name passed to the constructor will be the name of the room to join. The next step is to send
<b>join(...)</b> to the <i><b>MultiUserChat</b></i> instance. But first you will have to decide which
join message to send. If you want to just join the room without a password and without specifying the amount
of history to receive then you could use <b>join(String nickname)</b> where nickname if your nickname in
the room. In case the room requires a password in order to join you could then use
<b>join(String nickname, String password)</b>. And finally, the most complete way to join a room is to send
<b>join(String nickname, String password, DiscussionHistory history, long timeout)</b>
where nickname is your nickname in the room, , password is your password to join the room, history is
an object that specifies the amount of history to receive and timeout is the milliseconds to wait
for a response from the server.</p>
<b>Examples</b><p>
In this example we can see how to join a room with a given nickname: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Create a MultiUserChat using an XMPPConnection for a room</font>
MultiUserChat muc2 = new MultiUserChat(conn1, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
<font color="#3f7f5f">// User2 joins the new room</font>
<font color="#3f7f5f">// The room service will decide the amount of history to send</font>
muc2.join(<font color="#0000FF">"testbot2"</font>);
</pre>
</blockquote>
In this example we can see how to join a room with a given nickname and password: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Create a MultiUserChat using an XMPPConnection for a room</font>
MultiUserChat muc2 = new MultiUserChat(conn1, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
<font color="#3f7f5f">// User2 joins the new room using a password</font>
<font color="#3f7f5f">// The room service will decide the amount of history to send</font>
muc2.join(<font color="#0000FF">"testbot2"</font>, <font color="#0000FF">"password"</font>);
</pre>
</blockquote>
In this example we can see how to join a room with a given nickname specifying the amount of history
to receive: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Create a MultiUserChat using an XMPPConnection for a room</font>
MultiUserChat muc2 = new MultiUserChat(conn1, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
<font color="#3f7f5f">// User2 joins the new room using a password and specifying</font>
<font color="#3f7f5f">// the amount of history to receive. In this example we are requesting the last 5 messages.</font>
DiscussionHistory history = new DiscussionHistory();
history.setMaxStanzas(5);
muc2.join(<font color="#0000FF">"testbot2"</font>, <font color="#0000FF">"password"</font>, history, SmackConfiguration.getPacketReplyTimeout());
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="invite">Manage room invitations</a></div><p>
<b>Description</b><p>
It can be useful to invite another user to a room in which one is an occupant. Depending on the
room's type the invitee could receive a password to use to join the room and/or be added to the
member list if the room is of type members-only. Smack allows to send room invitations and let
potential invitees to listening for room invitations and inviters to listen for invitees'
rejections.</p>
<b>Usage</b><p>
In order to invite another user to a room you must be already joined to the room. Once you are
joined just send <b>invite(String participant, String reason)</b> to the <i><b>MultiUserChat</b></i>
where participant is the user to invite to the room (e.g. hecate@shakespeare.lit) and reason is
the reason why the user is being invited.</p><p>
If potential invitees want to listen for room invitations then the invitee must add an <i><b>InvitationListener</b></i>
to the <i><b>MultiUserChat</b></i> class. Since the <i><b>InvitationListener</b></i> is an <i>interface</i>,
it is necessary to create a class that implements this <i>interface</i>. If an inviter wants to
listen for room invitation rejections, just add an <i><b>InvitationRejectionListener</b></i>
to the <i><b>MultiUserChat</b></i>. <i><b>InvitationRejectionListener</b></i> is also an
interface so you will need to create a class that implements this interface.</p>
<b>Examples</b><p>
In this example we can see how to invite another user to the room and lister for possible rejections: <br>
<blockquote>
<pre> <font color="#3f7f5f">// User2 joins the room</font>
MultiUserChat muc2 = new MultiUserChat(conn2, room);
muc2.join(<font color="#0000FF">"testbot2"</font>);
<font color="#3f7f5f">// User2 listens for invitation rejections</font>
muc2.addInvitationRejectionListener(new InvitationRejectionListener() {
public void invitationDeclined(String invitee, String reason) {
<font color="#3f7f5f">// Do whatever you need here...</font>
}
});
<font color="#3f7f5f">// User2 invites user3 to join to the room</font>
muc2.invite(<font color="#0000FF">"user3@host.org/Smack"</font>, <font color="#0000FF">"Meet me in this excellent room"</font>);
</pre>
</blockquote>
In this example we can see how to listen for room invitations and decline invitations: <br>
<blockquote>
<pre> <font color="#3f7f5f">// User3 listens for MUC invitations</font>
MultiUserChat.addInvitationListener(conn3, new InvitationListener() {
public void invitationReceived(XMPPConnection conn, String room, String inviter, String reason, String password) {
<font color="#3f7f5f">// Reject the invitation</font>
MultiUserChat.decline(conn, room, inviter, <font color="#0000FF">"I'm busy right now"</font>);
}
});
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="discomuc">Discover MUC support</a></div><p>
<b>Description</b><p>
A user may want to discover if one of the user's contacts supports the Multi-User Chat protocol.</p>
<b>Usage</b><p>
In order to discover if one of the user's contacts supports MUC just send
<b>isServiceEnabled(XMPPConnection connection, String user)</b> to the <i><b>MultiUserChat</b></i>
class where user is a fully qualified XMPP ID, e.g. jdoe@example.com. You will receive
a boolean indicating whether the user supports MUC or not.</p>
<b>Examples</b><p>
In this example we can see how to discover support of MUC: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Discover whether user3@host.org supports MUC or not</font>
boolean supports = MultiUserChat.isServiceEnabled(conn, <font color="#0000FF">"user3@host.org/Smack"</font>);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="discojoin">Discover joined rooms</a></div><p>
<b>Description</b><p>
A user may also want to query a contact regarding which rooms the contact is in.</p>
<b>Usage</b><p>
In order to get the rooms where a user is in just send
<b>getJoinedRooms(XMPPConnection connection, String user)</b> to the <i><b>MultiUserChat</b></i>
class where user is a fully qualified XMPP ID, e.g. jdoe@example.com. You will get an Iterator
of Strings as an answer where each String represents a room name.</p>
<b>Examples</b><p>
In this example we can see how to get the rooms where a user is in: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Get the rooms where user3@host.org has joined</font>
Iterator joinedRooms = MultiUserChat.getJoinedRooms(conn, <font color="#0000FF">"user3@host.org/Smack"</font>);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="discoroom">Discover room information</a></div><p>
<b>Description</b><p>
A user may need to discover information about a room without having to actually join the room. The server
will provide information only for public rooms.</p>
<b>Usage</b><p>
In order to discover information about a room just send <b>getRoomInfo(XMPPConnection connection, String room)</b>
to the <i><b>MultiUserChat</b></i> class where room is the XMPP ID of the room, e.g.
roomName@conference.myserver. You will get a RoomInfo object that contains the discovered room
information.</p>
<b>Examples</b><p>
In this example we can see how to discover information about a room: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Discover information about the room roomName@conference.myserver</font>
RoomInfo info = MultiUserChat.getRoomInfo(conn, <font color="#0000FF">"roomName@conference.myserver"</font>);
System.out.println("Number of occupants:" + info.getOccupantsCount());
System.out.println("Room Subject:" + info.getSubject());
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="privchat">Start a private chat</a></div><p>
<b>Description</b><p>
A room occupant may want to start a private chat with another room occupant even though they
don't know the fully qualified XMPP ID (e.g. jdoe@example.com) of each other.</p>
<b>Usage</b><p>
To create a private chat with another room occupant just send <b>createPrivateChat(String participant)</b>
to the <i><b>MultiUserChat</b></i> that you used to join the room. The parameter participant is the
occupant unique room JID (e.g. 'darkcave@macbeth.shakespeare.lit/Paul'). You will receive
a regular <i><b>Chat</b></i> object that you can use to chat with the other room occupant.</p>
<b>Examples</b><p>
In this example we can see how to start a private chat with another room occupant: <br>
<blockquote>
<pre> <font color="#3f7f5f">// Start a private chat with another participant</font>
Chat chat = muc2.createPrivateChat(<font color="#0000FF">"myroom@conference.jabber.org/johndoe"</font>);
chat.sendMessage(<font color="#0000FF">"Hello there"</font>);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="subject">Manage changes on room subject</a></div><p>
<b>Description</b><p>
A common feature of multi-user chat rooms is the ability to change the subject within the room. As a
default, only users with a role of "moderator" are allowed to change the subject in a room. Although
some rooms may be configured to allow a mere participant or even a visitor to change the subject.</p><p>
Every time the room's subject is changed you may want to be notified of the modification. The new subject
could be used to display an in-room message.</p>
<b>Usage</b><p>
In order to modify the room's subject just send <b>changeSubject(String subject)</b> to the
<i><b>MultiUserChat</b></i> that you used to join the room where subject is the new room's subject. On
the other hand, if you want to be notified whenever the room's subject is modified you should add a
<i><b>SubjectUpdatedListener</b></i> to the <i><b>MultiUserChat</b></i> by sending
<b>addSubjectUpdatedListener(SubjectUpdatedListener listener)</b> to the <i><b>MultiUserChat</b></i>.
Since the <i><b>SubjectUpdatedListener</b></i> is an <i>interface</i>, it is necessary to create a class
that implements this <i>interface</i>.</p>
<b>Examples</b><p>
In this example we can see how to change the room's subject and react whenever the room's subject is
modified: <br>
<blockquote>
<pre> <font color="#3f7f5f">// An occupant wants to be notified every time the room's subject is changed</font>
muc3.addSubjectUpdatedListener(new SubjectUpdatedListener() {
public void subjectUpdated(String subject, String from) {
....
}
});
<font color="#3f7f5f">// A room's owner changes the room's subject</font>
muc2.changeSubject(<font color="#0000FF">"New Subject"</font>);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="role">Manage role modifications</a></div><p>
<b>Description</b><p>
There are four defined roles that an occupant can have:</p>
<ol start="" type="">
<li>Moderator</li>
<li>Participant</li>
<li>Visitor</li>
<li>None (the absence of a role)</li>
</ol><p>
These roles are temporary in that they do not persist across a user's visits to the room
and can change during the course of an occupant's visit to the room.</p><p>
A moderator is the most powerful occupant within the context of the room, and can to some
extent manage other occupants' roles in the room. A participant has fewer privileges than a
moderator, although he or she always has the right to speak. A visitor is a more restricted
role within the context of a moderated room, since visitors are not allowed to send messages
to all occupants.</p><p>
Roles are granted, revoked, and maintained based on the occupant's room nickname or full
JID. Whenever an occupant's role is changed Smack will trigger specific events.</p>
<b>Usage</b><p>
In order to grant voice (i.e. make someone a <i>participant</i>) just send the message
<b>grantVoice(String nickname)</b> to <i><b>MultiUserChat</b></i>. Use <b>revokeVoice(String nickname)</b>
to revoke the occupant's voice (i.e. make the occupant a <i>visitor</i>).</p><p>
In order to grant moderator privileges to a participant or visitor just send the message
<b>grantModerator(String nickname)</b> to <i><b>MultiUserChat</b></i>. Use <b>revokeModerator(String nickname)</b>
to revoke the moderator privilege from the occupant thus making the occupant a participant.</p><p>
Smack allows you to listen for role modification events. If you are interested in listening role modification
events of any occupant then use the listener <b><i>ParticipantStatusListener</i></b>. But if you are interested
in listening for your own role modification events, use the listener <b><i>UserStatusListener</i></b>. Both listeners
should be added to the <i><b>MultiUserChat</b></i> by using
<b>addParticipantStatusListener(ParticipantStatusListener listener)</b> or
<b>addUserStatusListener(UserStatusListener listener)</b> respectively. These listeners include several notification
events but you may be interested in just a few of them. Smack provides default implementations for these listeners
avoiding you to implement all the interfaces' methods. The default implementations are <b><i>DefaultUserStatusListener</i></b>
and <b><i>DefaultParticipantStatusListener</i></b>. Below you will find the sent messages to the listeners whenever
an occupant's role has changed.</p><p>
These are the triggered events when the role has been upgraded:
</p>
<table border="1">
<tr><td><b>Old</b></td><td><b>New</b></td><td><b>Events</b></td></tr>
<tr><td>None</td><td>Visitor</td><td>--</td></tr>
<tr><td>Visitor</td><td>Participant</td><td>voiceGranted</td></tr>
<tr><td>Participant</td><td>Moderator</td><td>moderatorGranted</td></tr>
<tr><td>None</td><td>Participant</td><td>voiceGranted</td></tr>
<tr><td>None</td><td>Moderator</td><td>voiceGranted + moderatorGranted</td></tr>
<tr><td>Visitor</td><td>Moderator</td><td>voiceGranted + moderatorGranted</td></tr>
</table><p>
These are the triggered events when the role has been downgraded:
</p>
<table border="1">
<tr><td><b>Old</b></td><td><b>New</b></td><td><b>Events</b></td></tr>
<tr><td>Moderator</td><td>Participant</td><td>moderatorRevoked</td></tr>
<tr><td>Participant</td><td>Visitor</td><td>voiceRevoked</td></tr>
<tr><td>Visitor</td><td>None</td><td>kicked</td></tr>
<tr><td>Moderator</td><td>Visitor</td><td>voiceRevoked + moderatorRevoked</td></tr>
<tr><td>Moderator</td><td>None</td><td>kicked</td></tr>
<tr><td>Participant</td><td>None</td><td>kicked</td></tr>
</table></p>
<b>Examples</b><p>
In this example we can see how to grant voice to a visitor and listen for the notification events: <br>
<blockquote>
<pre> <font color="#3f7f5f">// User1 creates a room</font>
muc = new MultiUserChat(conn1, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
muc.create(<font color="#0000FF">"testbot"</font>);
<font color="#3f7f5f">// User1 (which is the room owner) configures the room as a moderated room</font>
Form form = muc.getConfigurationForm();
Form answerForm = form.createAnswerForm();
answerForm.setAnswer(<font color="#0000FF">"muc#roomconfig_moderatedroom"</font>, <font color="#0000FF">"1"</font>);
muc.sendConfigurationForm(answerForm);
<font color="#3f7f5f">// User2 joins the new room (as a visitor)</font>
MultiUserChat muc2 = new MultiUserChat(conn2, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
muc2.join(<font color="#0000FF">"testbot2"</font>);
<font color="#3f7f5f">// User2 will listen for his own "voice" notification events</font>
muc2.addUserStatusListener(new DefaultUserStatusListener() {
public void voiceGranted() {
super.voiceGranted();
...
}
public void voiceRevoked() {
super.voiceRevoked();
...
}
});
<font color="#3f7f5f">// User3 joins the new room (as a visitor)</font>
MultiUserChat muc3 = new MultiUserChat(conn3, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
muc3.join(<font color="#0000FF">"testbot3"</font>);
<font color="#3f7f5f">// User3 will lister for other occupants "voice" notification events</font>
muc3.addParticipantStatusListener(new DefaultParticipantStatusListener() {
public void voiceGranted(String participant) {
super.voiceGranted(participant);
...
}
public void voiceRevoked(String participant) {
super.voiceRevoked(participant);
...
}
});
<font color="#3f7f5f">// The room's owner grants voice to user2</font>
muc.grantVoice(<font color="#0000FF">"testbot2"</font>);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="afiliation">Manage affiliation modifications</a></div><p>
<b>Description</b><p>
There are five defined affiliations that a user can have in relation to a room:</p>
<ol start="" type="">
<li>Owner</li>
<li>Admin</li>
<li>Member</li>
<li>Outcast</li>
<li>None (the absence of an affiliation)</li>
</ol><p>
These affiliations are semi-permanent in that they persist across a user's visits to the room and
are not affected by happenings in the room. Affiliations are granted, revoked, and maintained
based on the user's bare JID.</p><p>
If a user without a defined affiliation enters a room, the user's affiliation is defined as &quot;none&quot;;
however, this affiliation does not persist across visits.</p><p>
Owners and admins are by definition immune from certain actions. Specifically, an owner or admin cannot
be kicked from a room and cannot be banned from a room. An admin must first lose his or her affiliation
(i.e., have an affiliation of &quot;none&quot; or &quot;member&quot;) before such actions could be performed
on them.</p><p>
The member affiliation provides a way for a room owner or admin to specify a &quot;whitelist&quot; of users
who are allowed to enter a members-only room. When a member enters a members-only room, his or her affiliation
does not change, no matter what his or her role is. The member affiliation also provides a way for users to
effectively register with an open room and thus be permanently associated with that room in some way (one
result may be that the user's nickname is reserved in the room).</p><p>
An outcast is a user who has been banned from a room and who is not allowed to enter the room. Whenever a
user's affiliation is changed Smack will trigger specific events.</p>
<b>Usage</b><p>
In order to grant membership to a room, administrator privileges or owner priveliges just send
<b>grantMembership(String jid)</b>, <b>grantAdmin(String jid)</b> or <b>grantOwnership(String jid)</b>
to <i><b>MultiUserChat</b></i> respectively. Use <b>revokeMembership(String jid)</b>, <b>revokeAdmin(String jid)</b>
or <b>revokeOwnership(String jid)</b> to revoke the membership to a room, administrator privileges or
owner priveliges respectively.</p><p>
In order to ban a user from the room just send the message <b>banUser(String jid, String reason)</b> to
<i><b>MultiUserChat</b></i>.</p><p>
Smack allows you to listen for affiliation modification events. If you are interested in listening affiliation modification
events of any user then use the listener <b><i>ParticipantStatusListener</i></b>. But if you are interested
in listening for your own affiliation modification events, use the listener <b><i>UserStatusListener</i></b>. Both listeners
should be added to the <i><b>MultiUserChat</b></i> by using
<b>addParticipantStatusListener(ParticipantStatusListener listener)</b> or
<b>addUserStatusListener(UserStatusListener listener)</b> respectively. These listeners include several notification
events but you may be interested in just a few of them. Smack provides default implementations for these listeners
avoiding you to implement all the interfaces' methods. The default implementations are <b><i>DefaultUserStatusListener</i></b>
and <b><i>DefaultParticipantStatusListener</i></b>. Below you will find the sent messages to the listeners whenever
a user's affiliation has changed.</p><p>
These are the triggered events when the affiliation has been upgraded:
</p>
<table border="1">
<tr><td><b>Old</b></td><td><b>New</b></td><td><b>Events</b></td></tr>
<tr><td>None</td><td>Member</td><td>membershipGranted</td></tr>
<tr><td>Member</td><td>Admin</td><td>membershipRevoked + adminGranted</td></tr>
<tr><td>Admin</td><td>Owner</td><td>adminRevoked + ownershipGranted</td></tr>
<tr><td>None</td><td>Admin</td><td>adminGranted</td></tr>
<tr><td>None</td><td>Owner</td><td>ownershipGranted</td></tr>
<tr><td>Member</td><td>Owner</td><td>membershipRevoked + ownershipGranted</td></tr>
</table><p>
These are the triggered events when the affiliation has been downgraded:
</p>
<table border="1">
<tr><td><b>Old</b></td><td><b>New</b></td><td><b>Events</b></td></tr>
<tr><td>Owner</td><td>Admin</td><td>ownershipRevoked + adminGranted</td></tr>
<tr><td>Admin</td><td>Member</td><td>adminRevoked + membershipGranted</td></tr>
<tr><td>Member</td><td>None</td><td>membershipRevoked</td></tr>
<tr><td>Owner</td><td>Member</td><td>ownershipRevoked + membershipGranted</td></tr>
<tr><td>Owner</td><td>None</td><td>ownershipRevoked</td></tr>
<tr><td>Admin</td><td>None</td><td>adminRevoked</td></tr>
<tr><td><i>Anyone</i></td><td>Outcast</td><td>banned</td></tr>
</table></p>
<b>Examples</b><p>
In this example we can see how to grant admin privileges to a user and listen for the notification events: <br>
<blockquote>
<pre> <font color="#3f7f5f">// User1 creates a room</font>
muc = new MultiUserChat(conn1, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
muc.create(<font color="#0000FF">"testbot"</font>);
<font color="#3f7f5f">// User1 (which is the room owner) configures the room as a moderated room</font>
Form form = muc.getConfigurationForm();
Form answerForm = form.createAnswerForm();
answerForm.setAnswer(<font color="#0000FF">"muc#roomconfig_moderatedroom"</font>, <font color="#0000FF">"1"</font>);
muc.sendConfigurationForm(answerForm);
<font color="#3f7f5f">// User2 joins the new room (as a visitor)</font>
MultiUserChat muc2 = new MultiUserChat(conn2, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
muc2.join(<font color="#0000FF">"testbot2"</font>);
<font color="#3f7f5f">// User2 will listen for his own admin privileges</font>
muc2.addUserStatusListener(new DefaultUserStatusListener() {
public void membershipRevoked() {
super.membershipRevoked();
...
}
public void adminGranted() {
super.adminGranted();
...
}
});
<font color="#3f7f5f">// User3 joins the new room (as a visitor)</font>
MultiUserChat muc3 = new MultiUserChat(conn3, <font color="#0000FF">"myroom@conference.jabber.org"</font>);
muc3.join(<font color="#0000FF">"testbot3"</font>);
<font color="#3f7f5f">// User3 will lister for other users admin privileges</font>
muc3.addParticipantStatusListener(new DefaultParticipantStatusListener() {
public void membershipRevoked(String participant) {
super.membershipRevoked(participant);
...
}
public void adminGranted(String participant) {
super.adminGranted(participant);
...
}
});
<font color="#3f7f5f">// The room's owner grants admin privileges to user2</font>
muc.grantAdmin(<font color="#0000FF">"user2@jabber.org"</font>);
</pre>
</blockquote>
</body>
</html>

View File

@ -0,0 +1,30 @@
<html>
<head>
<title>Private Data</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Private Data</div><p>
Manages private data, which is a mechanism to allow users to store arbitrary XML
data on an XMPP server. Each private data chunk is defined by a element name and
XML namespace. Example private data:
<pre>
&lt;color xmlns="http://example.com/xmpp/color"&gt;
&lt;favorite&gt;blue&lt;/blue&gt;
&lt;leastFavorite&gt;puce&lt;/leastFavorite&gt;
&lt;/color&gt;
</pre><p>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0049.html">JEP-49</a>
<hr>
<em>More coming soon.</em>
</body>
</html>

View File

@ -0,0 +1,179 @@
<html>
<head>
<title>Roster Item Exchange</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Roster Item Exchange</div><p>
This extension is used to send rosters, roster groups and roster entries from one XMPP
Entity to another. It also provides an easy way to hook up custom logic when entries
are received from other XMPP clients.
<p>Follow these links to learn how to send and receive roster items:</p>
<ul>
<li><a href="#riesendroster">Send a complete roster</a></li>
<li><a href="#riesendgroup">Send a roster's group</a></li>
<li><a href="#riesendentry">Send a roster's entry</a></li>
<li><a href="#riercventry">Receive roster entries</a></li>
</ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0093.html">JEP-93</a>
<hr>
<div class="subheader"><a name="riesendroster">Send a entire roster</a></div><p>
<b>Description</b><p>
Sometimes it is useful to send a whole roster to another user. Smack provides a
very easy way to send a complete roster to another XMPP client.</p>
<b>Usage</b><p>
Create an instance of <i><b>RosterExchangeManager</b></i> and use the <b>#send(Roster, String)</b>
message to send a roster to a given user. The first parameter is the roster to send and
the second parameter is the id of the user that will receive the roster entries.</p>
<b>Example</b><p>
In this example we can see how user1 sends his roster to user2.
<blockquote>
<pre> <font color="#3f7f5f">// Connect to the server and log in</font>
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
<font color="#3f7f5f">// Create a new roster exchange manager on conn1</font>
RosterExchangeManager rosterExchangeManager = new RosterExchangeManager(conn1);
<font color="#3f7f5f">// Send user1's roster to user2</font>
rosterExchangeManager.send(conn1.getRoster(), user2);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="riesendgroup">Send a roster group</a></div><p>
<b>Description</b><p>
It is also possible to send a roster group to another XMPP client. A roster group groups
a set of roster entries under a name.</p>
<b>Usage</b><p>
Create an instance of <i><b>RosterExchangeManager</b></i> and use the <b>#send(RosterGroup, String)</b>
message to send a roster group to a given user. The first parameter is the roster group to send and
the second parameter is the id of the user that will receive the roster entries.</p>
<b>Example</b><p>
In this example we can see how user1 sends his roster groups to user2.
<blockquote>
<pre> <font color="#3f7f5f">// Connect to the server and log in</font>
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
<font color="#3f7f5f">// Create a new roster exchange manager on conn1</font>
RosterExchangeManager rosterExchangeManager = new RosterExchangeManager(conn1);
<font color="#3f7f5f">// Send user1's RosterGroups to user2</font>
for (Iterator it = conn1.getRoster().getGroups(); it.hasNext(); )
rosterExchangeManager.send((RosterGroup)it.next(), user2);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="riesendentry">Send a roster entry</a></div><p>
<b>Description</b><p>
Sometimes you may need to send a single roster entry to another XMPP client. Smack also lets you send
items at this granularity level.</p>
<b>Usage</b><p>
Create an instance of <i><b>RosterExchangeManager</b></i> and use the <b>#send(RosterEntry, String)</b>
message to send a roster entry to a given user. The first parameter is the roster entry to send and
the second parameter is the id of the user that will receive the roster entries.</p>
<b>Example</b><p>
In this example we can see how user1 sends a roster entry to user2.
<blockquote>
<pre> <font color="#3f7f5f">// Connect to the server and log in</font>
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
<font color="#3f7f5f">// Create a new roster exchange manager on conn1</font>
RosterExchangeManager rosterExchangeManager = new RosterExchangeManager(conn1);
<font color="#3f7f5f">// Send a roster entry (any) to user2</font>
rosterExchangeManager1.send((RosterEntry)conn1.getRoster().getEntries().next(), user2);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="riercventry">Receive roster entries</a></div><p>
<b>Description</b><p>
Since roster items are sent between XMPP clients, it is necessary to listen to possible roster entries
receptions. Smack provides a mechanism that you can use to execute custom logic when roster entries are
received.</p>
<b>Usage</b><p>
<ol>
<li>Create a class that implements the <i><b>RosterExchangeListener</b></i> interface.</li>
<li>Implement the method <b>entriesReceived(String, Iterator)</b> that will be called when new entries
are received with custom logic.</li>
<li>Add the listener to the <i>RosterExchangeManager</i> that works on the desired <i>XMPPConnection</i>.</li>
</ol></p>
<b>Example</b><p>
In this example we can see how user1 sends a roster entry to user2 and user2 adds the received
entries to his roster.
<blockquote>
<pre> <font color="#3f7f5f">// Connect to the server and log in the users</font>
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
conn2 = new XMPPConnection(host);
conn2.login(server_user2, pass2);
final Roster user2_roster = conn2.getRoster();
<font color="#3f7f5f">// Create a RosterExchangeManager that will help user2 to listen and accept
the entries received</font>
RosterExchangeManager rosterExchangeManager2 = new RosterExchangeManager(conn2);
<font color="#3f7f5f">// Create a RosterExchangeListener that will iterate over the received roster entries</font>
RosterExchangeListener rosterExchangeListener = new RosterExchangeListener() {
public void entriesReceived(String from, Iterator remoteRosterEntries) {
while (remoteRosterEntries.hasNext()) {
try {
<font color="#3f7f5f">// Get the received entry</font>
RemoteRosterEntry remoteRosterEntry = (RemoteRosterEntry) remoteRosterEntries.next();
<font color="#3f7f5f">// Display the remote entry on the console</font>
System.out.println(remoteRosterEntry);
<font color="#3f7f5f">// Add the entry to the user2's roster</font>
user2_roster.createEntry(
remoteRosterEntry.getUser(),
remoteRosterEntry.getName(),
remoteRosterEntry.getGroupArrayNames());
}
catch (XMPPException e) {
e.printStackTrace();
}
}
}
};
<font color="#3f7f5f">// Add the RosterExchangeListener to the RosterExchangeManager that user2 is using</font>
rosterExchangeManager2.addRosterListener(rosterExchangeListener);
<font color="#3f7f5f">// Create a RosterExchangeManager that will help user1 to send his roster</font>
RosterExchangeManager rosterExchangeManager1 = new RosterExchangeManager(conn1);
<font color="#3f7f5f">// Send user1's roster to user2</font>
rosterExchangeManager1.send(conn1.getRoster(), user2);
</pre>
</blockquote>
</body>
</html>

View File

@ -0,0 +1,57 @@
BODY {
font-size : 100%;
background-color : #fff;
}
BODY, TD, TH {
font-family : tahoma, arial, helvetica;
font-size : 0.8em;
}
PRE, TT, CODE {
font-family : courier new, monospaced;
font-size : 1.0em;
}
A:hover {
text-decoration : none;
}
LI {
padding-bottom : 4px;
}
.header {
font-size : 1.4em;
font-weight : bold;
width : 100%;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
.subheader {
font-size: 1.1em;
font-weight : bold;
}
.footer {
font-size : 0.8em;
color : #999;
text-align : center;
width : 100%;
border-top : 1px #ccc solid;
padding-top : 2px;
}
.code {
border : 1px #ccc solid;
padding : 0em 1.0em 0em 1.0em;
margin : 4px 0px 4px 0px;
}
.nav, .nav A {
font-family : verdana;
font-size : 0.85em;
color : #600;
text-decoration : none;
font-weight : bold;
}
.nav {
width : 100%;
border-bottom : 1px #ccc solid;
padding : 3px 3px 5px 1px;
}
.nav A:hover {
text-decoration : underline;
}

View File

@ -0,0 +1,22 @@
<html>
<head>
<title>Time</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">Entity Time Exchange</div><p>
Supports a protocol that XMPP clients use to exchange their respective local
times and time zones.<p>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0090.html">JEP-90</a>
<hr>
<em>More coming soon.</em>
</body>
</html>

View File

@ -0,0 +1,26 @@
<html>
<head>
<title>Smack Extensions User Manual</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<base target="mainFrame">
</head>
<body>
<a href="intro.html">Introduction</a><p>
<div class="subheader">Smack Extensions</div><p>
<a href="privatedata.html">Private Data</a><br>
<a href="xhtml.html">XHTML Messages</a><br>
<a href="messageevents.html">Message Events</a><br>
<a href="dataforms.html">Data Forms</a><br>
<a href="muc.html">Multi User Chat</a><br>
<a href="rosterexchange.html">Roster Item Exchange</a><br>
<a href="time.html">Time Exchange</a><br>
<a href="invitation.html">Group Chat Invitations</a><br>
<a href="disco.html">Service Discovery</a><br>
</p>
</body>
</html>

View File

@ -0,0 +1,200 @@
<html>
<head>
<title>XHTML Support</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">XHTML Messages</div><p>
Provides the ability to send and receive formatted messages using XHTML.
<p>Follow these links to learn how to compose, send, receive and discover support for
XHTML messages:</p>
<ul>
<li><a href="#xhtmlcompose">Compose an XHTML Message</a></li>
<li><a href="#xhtmlsend">Send an XHTML Message</a></li>
<li><a href="#xhtmlreceive">Receive an XHTML Message</a></li>
<li><a href="#xhtmldiscover">Discover support for XHTML Messages</a></li>
</ul>
<b>JEP related:</b> <a href="http://www.jabber.org/jeps/jep-0071.html">JEP-71</a>
<hr>
<div class="subheader"><a name="xhtmlcompose">Compose an XHTML Message</a></div><p>
<b>Description</b><p>
The first step in order to send an XHTML message is to compose it. Smack provides a special
class that helps to build valid XHTML messages hiding any low level complexity.
For special situations, advanced users may decide not to use the helper class and generate
the XHTML by themselves. Even for these situations Smack provides a well defined entry point
in order to add the generated XHTML content to a given message.</p>
<p>
Note: not all clients are able to view XHTML formatted messages. Therefore,
it's recommended that you include a normal body in that message that is either an
unformatted version of the text or a note that XHTML support is required
to view the message contents.</p>
<b>Usage</b><p>
Create an instance of <i><b>XHTMLText</b></i> specifying the style and language of the body.
You can add several XHTML bodies to the message but each body should be for a different language.
Once you have an XHTMLText you can start to append tags and text to it. In order to append tags there
are several messages that you can use. For each XHTML defined tag there is a message that you can send.
In order to add text you can send the message <b>#append(String textToAppend)</b>.</p>
<p>After you have configured the XHTML text, the last step you have to do is to add the XHTML text
to the message you want to send. If you decided to create the XHTML text by yourself, you will have to
follow this last step too. In order to add the XHTML text to the message send the message
<b>#addBody(Message message, String body)</b> to the <i><b>XHTMLManager</b></i> class where <i>message</i>
is the message that will receive the XHTML body and <i>body</i> is the string to add as an XHTML body to
the message.</b></p>
<b>Example</b><p>
In this example we can see how to compose the following XHTML message: <br>
<font color="#0000FF">&lt;body&gt;&lt;p style='font-size:large'&gt;Hey John, this is my new &lt;span
style='color:green'&gt;green&lt;/span&gt;&lt;em&gt;!!!!&lt;/em&gt;&lt;/p&gt;&lt;/body&gt;</font>
<blockquote>
<pre> <font color="#3f7f5f">// Create a message to send</font>
Message msg = chat.createMessage();
msg.setSubject(<font color="#0000FF">"Any subject you want"</font>);
msg.setBody(<font color="#0000FF">"Hey John, this is my new green!!!!"</font>);
<font color="#3f7f5f">// Create an XHTMLText to send with the message</font>
XHTMLText xhtmlText = new XHTMLText(null, null);
xhtmlText.appendOpenParagraphTag(<font color="#0000FF">"font-size:large"</font>);
xhtmlText.append(<font color="#0000FF">"Hey John, this is my new "</font>);
xhtmlText.appendOpenSpanTag(<font color="#0000FF">"color:green"</font>);
xhtmlText.append(<font color="#0000FF">"green"</font>);
xhtmlText.appendCloseSpanTag();
xhtmlText.appendOpenEmTag();
xhtmlText.append(<font color="#0000FF">"!!!!"</font>);
xhtmlText.appendCloseEmTag();
xhtmlText.appendCloseParagraphTag();
<font color="#3f7f5f">// Add the XHTML text to the message</font>
XHTMLManager.addBody(msg, xhtmlText.toString());
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="xhtmlsend">Send an XHTML Message</a></div><p>
<b>Description</b><p>
After you have composed an XHTML message you will want to send it. Once you have added
the XHTML content to the message you want to send you are almost done. The last step is to send
the message as you do with any other message.</p>
<b>Usage</b><p>
An XHTML message is like any regular message, therefore to send the message you can follow
the usual steps you do in order to send a message. For example, to send a message as part
of a chat just use the message <b>#send(Message)</b> of <i><b>Chat</b></i> or you can use
the message <b>#send(Packet)</b> of <i><b>XMPPConnection</b></i>.</p>
<b>Example</b><p>
In this example we can see how to send a message with XHTML content as part of a chat.
<blockquote>
<pre> <font color="#3f7f5f">// Create a message to send</font>
Message msg = chat.createMessage();
<font color="#3f7f5f">// Obtain the XHTML text to send from somewhere</font>
String xhtmlBody = getXHTMLTextToSend();
<font color="#3f7f5f">// Add the XHTML text to the message</font>
XHTMLManager.addBody(msg, xhtmlBody);
<font color="#3f7f5f">// Send the message that contains the XHTML</font>
chat.sendMessage(msg);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="xhtmlreceive">Receive an XHTML Message</a></div><p>
<b>Description</b><p>
It is also possible to obtain the XHTML content from a received message. Remember
that the specification defines that a message may contain several XHTML bodies
where each body should be for a different language.</p>
<b>Usage</b><p>
To get the XHTML bodies of a given message just send the message <b>#getBodies(Message)</b>
to the class <i><b>XHTMLManager</b></i>. The answer of this message will be an
<i><b>Iterator</b></i> with the different XHTML bodies of the message or null if none.</p>
<b>Example</b><p>
In this example we can see how to create a PacketListener that obtains the XHTML bodies of any received message.
<blockquote>
<pre> <font color="#3f7f5f">// Create a listener for the chat and display any XHTML content</font>
PacketListener packetListener = new PacketListener() {
public void processPacket(Packet packet) {
Message message = (Message) packet;
<font color="#3f7f5f">// Obtain the XHTML bodies of the message</font>
Iterator it = XHTMLManager.getBodies(message);
if (it != null) {
<font color="#3f7f5f">// Display the bodies on the console</font>
while (it.hasNext()) {
String body = (String) it.next();
System.out.println(body);
}
}
};
chat.addMessageListener(packetListener);
</pre>
</blockquote>
<hr>
<div class="subheader"><a name="xhtmldiscover">Discover support for XHTML Messages</a></div><p>
<b>Description</b><p>
Before you start to send XHTML messages to a user you should discover if the user supports XHTML messages.
There are two ways to achieve the discovery, explicitly and implicitly. Explicit is when you first try
to discover if the user supports XHTML before sending any XHTML message. Implicit is when you send
XHTML messages without first discovering if the conversation partner's client supports XHTML and depenging on
the answer (normal message or XHTML message) you find out if the user supports XHTML messages or not. This
section explains how to explicitly discover for XHTML support.</p>
<b>Usage</b><p>
In order to discover if a remote user supports XHTML messages send <b>#isServiceEnabled(XMPPConnection
connection, String userID)</b> to the class <i><b>XHTMLManager</b></i> where connection is the connection
to use to perform the service discovery and userID is the user to check (A fully qualified xmpp ID,
e.g. jdoe@example.com). This message will return true if the specified user handles XHTML messages.</p>
<b>Example</b><p>
In this example we can see how to discover if a remote user supports XHTML Messages.
<blockquote>
<pre> Message msg = chat.createMessage();
<font color="#3f7f5f">// Include a normal body in the message</font>
msg.setBody(getTextToSend());
<font color="#3f7f5f">// Check if the other user supports XHTML messages</font>
if (XHTMLManager.isServiceEnabled(connection, chat.getParticipant())) {
<font color="#3f7f5f">// Obtain the XHTML text to send from somewhere</font>
String xhtmlBody = getXHTMLTextToSend();
<font color="#3f7f5f">// Include an XHTML body in the message</font>
XHTMLManager.addBody(msg, xhtmlBody);
}
<font color="#3f7f5f">// Send the message</font>
chat.sendMessage(msg);
</pre>
</blockquote>
</body>
</html>

View File

@ -0,0 +1,109 @@
<html>
<head>
<title>Smack: Getting Started - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" /
</head>
<body>
<div class="header">
Getting Started With Smack
</div>
<div class="nav">
&laquo; <a href="index.html">Table of Contents</a>
</div>
<p>
This document will introduce you to the Smack API and provide an overview of
important classes and concepts.
</p>
<p class="subheader">
Requirements
</p>
The only requirement for Smack is JDK 1.2 or later<sup>
<a style="text-decoration:none;" href="#ssenote">1</a></sup>.
An XML parser is embedded in the smack.jar file and no other third party
libraries are required.<p>
<sup>1</sup> <font size="-1"><i>JDK 1.2 and 1.3 users that wish to use SSL connections must have the
<a href="http://java.sun.com/products/jsse/index-103.html">JSSE</a> library in their classpath.</i></font>
<p class="subheader">
Establishing a Connection
</p>
The <tt>XMPPConnection</tt> class is used to create a connection to an
XMPP server. To create an SSL connection, use the SSLXMPPConnection class.
Below are code examples for making a connection:<p>
<div class="code">
<pre>
<font color="gray"><i>// Create a connection to the jabber.org server.</i></font>
XMPPConnection conn1 = <font color="navy"><b>new</b></font> XMPPConnection(<font color="green">"jabber.org"</font>);
<font color="gray"><i>// Create a connection to the jabber.org server on a specific port.</i></font>
XMPPConnection conn2 = <font color="navy"><b>new</b></font> XMPPConnection(<font color="green">"jabber.org"</font>, 5222);
<font color="gray"><i>// Create an SSL connection to jabber.org.</i></font>
XMPPConnection connection = <font color="navy"><b>new</b></font> SSLXMPPConnection(<font color="green">"jabber.org"</font>);
</pre></div>
<p>Once you've created a connection, you should login using a username and password
with the <tt>XMPPConnection.login(String username, String password)</tt> method.
Once you've logged in, you can being chatting with other users by creating
new <tt>Chat</tt> or <tt>GroupChat</tt> objects.
<p class="subheader">
Working with the Roster
</p>
The roster lets you keep track of the availability (presence) of other users. Users
can be organized into groups such as "Friends" and "Co-workers", and then you
discover whether each user is online or offline.<p>
Retrieve the roster using the <tt>XMPPConnection.getRoster()</tt> method. The roster
class allows you to find all the roster entries, the groups they belong to, and the
current presence status of each entry.
<p class="subheader">
Reading and Writing Packets
</p>
Each message to the XMPP server from a client is called a packet and is
sent as XML. The <tt>org.jivesoftware.smack.packet</tt> package contains
classes that encapsulate the three different basic packet types allowed by
XMPP (message, presence, and IQ). Classes such as <tt>Chat</tt> and <tt>GroupChat</tt>
provide higher-level constructs that manage creating and sending packets
automatically, but you can also create and send packets directly. Below
is a code example for changing your presence to let people know you're unavailable
and "out fishing":<p>
<div class="code">
<pre>
<font color="gray"><i>// Create a new presence. Pass in false to indicate we're unavailable.</i></font>
Presence presence = new Presence(Presence.Type.UNAVAILABLE);
presence.setStatus(<font color="green">"Gone fishing"</font>);
<font color="gray"><i>// Send the packet (assume we have a XMPPConnection instance called "con").</i></font>
con.sendPacket(presence);
</pre></div>
<p>
Smack provides two ways to read incoming packets: <tt>PacketListener</tt>, and
<tt>PacketCollector</tt>. Both use <tt>PacketFilter</tt> instances to determine
which packets should be processed. A packet listener is used for event style programming,
while a packet collector has a result queue of packets that you can do
polling and blocking operations on. So, a packet listener is useful when
you want to take some action whenever a packet happens to come in, while a
packet collector is useful when you want to wait for a specific packet
to arrive. Packet collectors and listeners can be created using an
XMPPConnection instance.
<p><div class="footer">
Copyright &copy; Jive Software 2002-2005
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,37 @@
<html>
<head>
<title>Smack Documentation - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<table border="0"><tr><td>
<img src="images/smacklogo.png" width="100" height="100" alt="Smack" border="0" hspace="10">
</td><td>
<font size="4"><b>Smack Documentation</b></font>
</div></td></tr></table>
<p>
<strong>Contents:</strong>
</p>
<ul>
<li><a href="overview.html">Overview</a>
<li><a href="gettingstarted.html">Getting Started Guide</a>
<li><a href="messaging.html">Messaging Basics</a>
<li><a href="roster.html">Roster and Presence</a>
<li><a href="processing.html">Processing Incoming Packets</a>
<li><a href="providers.html">Provider Architecture</a>
<li><a href="properties.html">Packet Properties</a>
<li><a href="debugging.html">Debugging with Smack</a>
<p>
<li><a href="extensions/index.html">Smack Extensions Manual</a>
</ul>
<div class="footer">
Copyright &copy; Jive Software 2002-2005
</div>
</body>
</html>

View File

@ -0,0 +1,108 @@
<html>
<head>
<title>Smack: Chat - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">
Messaging using Chat and GroupChat
</div>
<div class="nav">
&laquo; <a href="index.html">Table of Contents</a>
</div>
<p>
Sending messages back and forth is at the core of instant messaging. Two classes
aid in sending and receiving messages:
<ul>
<li> <tt>org.jivesoftware.smack.Chat</tt> -- used to send messages between two people.
<li> <tt>org.jivesoftware.smack.GroupChat</tt> -- used to join a chat room to send messages between many people.
</ul>
Both the Chat and GroupChat classes use the <tt>org.jivesoftware.smack.packet.Message</tt> packet
class to send messages. In certain circumstances, you may wish to bypass the higher-level
Chat and GroupChat classes to send and listen for messages directly.
</p>
<p class="subheader">
Chat
</p>
A chat creates a new thread of messages (using a thread ID) between two users. The
following code snippet demonstrates how to create a new Chat with a user and then send
them a text message:<p>
<div class="code"><pre>
<font color="gray"><i>// Assume we've created an XMPPConnection name "connection".</i></font>
Chat newChat = connection.createChat(<font color="green">"jsmith@jivesoftware.com"</font>);
newChat.sendMessage(<font color="green">"Howdy!"</font>);
</pre></div><p>
The <tt>Chat.sendMessage(String)</tt> method is a convenience method that creates a Message
object, sets the body using the String parameter, then sends the message. In the case
that you wish to set additional values on a Message before sending it, use the
<tt>Chat.createMessage()</tt> and <tt>Chat.sendMessage(Message)</tt> methods, as in the
following code snippet:<p>
<div class="code"><pre>
<font color="gray"><i>// Assume we've created an XMPPConnection name "connection".</i></font>
Chat newChat = connection.createChat(<font color="green">"jsmith@jivesoftware.com"</font>);
Message newMessage = newChat.createMessage();
newMessage.setBody(<font color="green">"Howdy!"</font>);
message.setProperty(<font color="green">"favoriteColor"</font>, <font color="green">"red"</font>);
newChat.sendMessage(newMessage);
</pre></div><p>
The Chat object allows you to easily listen for replies from the other chat participant.
The following code snippet is a parrot-bot -- it echoes back everything the other user types.<p>
<div class="code"><pre>
<font color="gray"><i>// Assume we've created an XMPPConnection name "connection".</i></font>
Chat newChat = connection.createChat(<font color="green">"jsmith@jivesoftware.com"</font>);
newMessage.setBody(<font color="green">"Hi, I'm an annoying parrot-bot! Type something back to me."</font>);
<b>while</b> (<b>true</b>) {
<font color="gray"><i>// Wait for the next message the user types to us.</i></font>
Message message = newChat.nextMessage();
<font color="gray"><i>// Send back the same text the other user sent us.</i></font>
newChat.sendMessage(message.getBody());
}
</pre></div><p>
The code above uses the <tt>Chat.nextMessage()</tt> method to get the next message, which
will wait indefinitely until another message comes in. There are other methods to wait
a specific amount of time for a new message, or you can add a listener that will be notified
every time a new message arrives.
<p class="subheader">
GroupChat
</p>
A group chat connects to a chat room on a server and allows you to send and receive messages
from a group of people. Before you can send or receive messages, you must join the room using
a nickname. The following code snippet connects to a chat room and sends a
message.<p>
<div class="code"><pre>
<font color="gray"><i>// Assume we've created an XMPPConnection name "connection".</i></font>
GroupChat newGroupChat = connection.createGroupChat(<font color="green">"test@jivesoftware.com"</font>);
<font color="gray"><i>// Join the group chat using the nickname "jsmith".</i></font>
newGroupChat.join(<font color="green">"jsmith"</font>);
<font color="gray"><i>// Send a message to all the other people in the chat room.</i></font>
newGroupChat.sendMessage(<font color="green">"Howdy!"</font>);
</pre></div><p>
In general, sending and receiving messages in a group chat works very similarly to
the <tt>Chat</tt> class. Method are also provided to get the list of the other
users in the room.<p>
<br clear="all" /><br><br>
<div class="footer">
Copyright &copy; Jive Software 2002-2005
</div>
</body>
</html>

View File

@ -0,0 +1,72 @@
<html>
<head>
<title>Smack: Overview - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">
Smack Overview
</div>
<div class="nav">
&laquo; <a href="index.html">Table of Contents</a>
</div>
<p>
Smack is a library for communicating with XMPP servers to perform
instant messaging and chat.<p>
<p class="subheader">
Smack Key Advantages
</p>
<ul>
<li>Extremely simple to use, yet powerful API. Sending a text message to a user
can be accomplished in three lines of code:
<div class="code"><pre>
XMPPConnection connection = <font color="navy"><b>new</b></font> XMPPConnection(<font color="green">"jabber.org"</font>);
connection.login(<font color="green">"mtucker"</font>, <font color="green">"password"</font>);
connection.createChat(<font color="green">"jsmith@jivesoftware.com"</font>).sendMessage(<font color="green">"Howdy!"</font>);
</pre></div>
<li>Doesn't force you to code at the packet level, as other libraries do. Smack provides
intelligent higher level constructs such as the <tt>Chat</tt> and <tt>GroupChat</tt>
classes, which let you program more efficiently.
<li>Does not require that you're familiar with the XMPP XML format, or even that you're familiar with XML.
<li>Provides easy machine to machine communication. Smack lets you set any number of properties on
each message, including properties that are Java objects.
<li>Open Source under the Apache License, which means you can incorporate Smack into your commercial or
non-commercial applications.
</ul>
<p class="subheader">
About XMPP
</p>
XMPP (eXtensible Messaging and Presence Protocol) is an open, XML based protocol
making it's way through the IETF approval process under the guidance of the
Jabber Software Foundation (<a href="http://www.jabber.org">http://www.jabber.org</a>).
<p class="subheader">
How To Use This Documentation
</p>
This documentation assumes that you're already familiar with the main features of XMPP
instant messaging. It's also highly recommended that you open the Javadoc API guide and
use that as a reference while reading through this documentation.
<br clear="all" /><br><br>
<div class="footer">
Copyright &copy; Jive Software 2002-2005
</div>
</body>
</html>

View File

@ -0,0 +1,87 @@
<html>
<head>
<title>Smack: Processing Incoming Packets - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">
Processing Incoming Packets
</div>
<div class="nav">
&laquo; <a href="index.html">Table of Contents</a>
</div>
<p>
Smack provides a flexible framework for processing incoming packets using two constructs:
<ul>
<li><tt>org.jivesoftware.smack.PacketCollector</tt> -- a class that lets you
synchronously wait for new packets.
<li><tt>org.jivesoftware.smack.PacketListener</tt> -- an interface for asynchronously
notifying you of incoming packets.
</ul>
A packet listener is used for event style programming, while a packet collector has a
result queue of packets that you can do polling and blocking operations on. So, a packet
listener is useful when you want to take some action whenever a packet happens to come in,
while a packet collector is useful when you want to wait for a specific packet to come
arrive. Packet collectors and listeners can be created using an <tt>XMPPConnection</tt> instance.<p>
The <tt>org.jivesoftware.smack.filter.PacketFilter</tt> interface determines which
specific packets will be delivered to a <tt>PacketCollector</tt> or <tt>PacketListener</tt>.
Many pre-defined filters can be found in the <tt>org.jivesoftware.smack.filter</tt> package.
<p>
The following code snippet demonstrates registering both a packet collector and a packet
listener:<p>
<div class="code"><pre>
<font color="gray"><i>// Create a packet filter to listen for new messages from a particular</i></font>
<font color="gray"><i>// user. We use an AndFilter to combine two other filters.</i></font>
PacketFilter filter = new AndFilter(new PacketTypeFilter(<b>Message.class</b>),
new FromContainsFilter(<font color="green">"mary@jivesoftware.com"</font>));
<font color="gray"><i>// Assume we've created an XMPPConnection name "connection".</i></font>
<font color="gray"><i>// First, register a packet collector using the filter we created.</i></font>
PacketCollector myCollector = connection.createPacketCollector(filter);
<font color="gray"><i>// Normally, you'd do something with the collector, like wait for new packets.</i></font>
<font color="gray"><i>// Next, create a packet listener. We use an anonymous inner class for brevity.</i></font>
PacketListener myListener = new PacketListener() {
<b>public</b> <b>void</b> processPacket(Packet packet) {
<font color="gray"><i>// Do something with the incoming packet here.</i></font>
}
};
<font color="gray"><i>// Register the listener.</i></font>
connection.addPacketListener(myListener, filter);
</pre></div><p>
<p class="subheader">
Standard Packet Filters
</p>
A rich set of packet filters are included with Smack, or you can create your own filters by coding
to the <tt>PacketFilter</tt> interface. The default set of filters includes:
<ul>
<li> <tt>PacketTypeFilter</tt> -- filters for packets that are a particular Class type.
<li> <tt>PacketIDFilter</tt> -- filters for packets with a particular packet ID.
<li> <tt>ThreadFilter</tt> -- filters for message packets with a particular thread ID.
<li> <tt>ToContainsFilter</tt> -- filters for packets that are sent to a particular address.
<li> <tt>FromContainsFilter</tt> -- filters for packets that are sent to a particular address.
<li> <tt>PacketExtensionFilter</tt> -- filters for packets that have a particular packet extension.
<li> <tt>AndFilter</tt> -- implements the logical AND operation over two filters.
<li> <tt>OrFilter</tt> -- implements the logical OR operation over two filters.
<li> <tt>NotFilter</tt> -- implements the logical NOT operation on a filter.
</ul>
<br clear="all" /><br><br>
<div class="footer">
Copyright &copy; Jive Software 2002-2005
</div>
</body>
</html>

View File

@ -0,0 +1,119 @@
<html>
<head>
<title>Smack: Packet Properties - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" /
</head>
<body>
<div class="header">
Packet Properties
</div>
<div class="nav">
&laquo; <a href="index.html">Table of Contents</a>
</div>
<p>
Smack provides an easy mechanism for attaching arbitrary properties to packets. Each property
has a String name, and a value that is a Java primitive (int, long, float, double, boolean) or
any Serializable object (a Java object is Serializable when it implements the Serializable
interface).
</p>
<p class="subheader">
Using the API
</p>
<p>
All major objects have property support, such as Message objects. The following code
demonstrates how to set properties:
</p>
<div class="code"><pre>
Message message = chat.createMessage();
<font color="gray"></i>// Add a Color object as a property.</i></font>
message.setProperty(<font color="blue">"favoriteColor"</font>, new Color(0, 0, 255));
<font color="gray"></i>// Add an int as a property.</i></font>
message.setProperty(<font color="blue">"favoriteNumber"</font>, 4);
chat.sendMessage(message);
</pre></div>
<p>
Getting those same properties would use the following code:
</p>
<div class="code"><pre>
Message message = chat.nextMessage();
<font color="gray"></i>// Get a Color object property.</i></font>
Color favoriteColor = (Color)message.getProperty(<font color="blue">"favoriteColor"</font>);
<font color="gray"></i>// Get an int property. Note that properties are always returned as
// Objects, so we must cast the value to an Integer, then convert
// it to an int.</i></font>
int favoriteNumber = ((Integer)message.getProperty(<font color="blue">"favoriteNumber"</font>)).intValue();
</pre></div>
<p class="subheader">
Objects as Properties
</p>
<p>
Using objects as property values is a very powerful and easy way to exchange data. However,
you should keep the following in mind:
</p>
<ul>
<li>Packet extensions are the more standard way to add extra data to XMPP stanzas. Using
properties may be more convenient in some cases, however, since Smack will do the
work of handling the XML.
<li>When you send a Java object as a property, only clients running Java will be able to
interpret the data. So, consider using a series of primitive values to transfer data
instead.
<li>Objects sent as property values must implement Serialiable. Additionally, both the sender
and receiver must have identical versions of the class, or a serialization exception
will occur when de-serializing the object.
<li>Serialized objects can potentially be quite large, which will use more bandwidth and
server resources.
</ul>
<p class="subheader">
XML Format
</p>
<p>
The current XML format used to send property data is not a standard, so will likely not be
recognized by clients not using Smack. The XML looks like the following (comments added for
clarity):
</p>
<div class="code"><pre>
<font color="gray"><i>&lt;!-- All properties are in a x block. --&gt;</i></font>
&lt;properties xmlns="http://www.jivesoftware.com/xmlns/xmpp/properties"&gt;
<font color="gray"><i>&lt;!-- First, a property named "prop1" that's an integer. --&gt;</i></font>
&lt;property&gt;
&lt;name&gt;prop1&lt;/name&gt;
&lt;value type="integer"&gt;123&lt;/value&gt;
&lt;property&gt;
<font color="gray"><i>&lt;!-- Next, a Java object that's been serialized and then converted
from binary data to base-64 encoded text. --&gt;</i></font>
&lt;property&gt;
&lt;name&gt;blah2&lt;/name&gt;
&lt;value type="java-object"&gt;adf612fna9nab&lt;/value&gt;
&lt;property&gt;
&lt;/properties&gt;
</pre></div>
<p>
The currently supported types are: <tt>integer</tt>, <tt>long</tt>, <tt>float</tt>,
<tt>double</tt>, <tt>boolean</tt>, <tt>string</tt>, and <tt>java-object</tt>.
</p>
<div class="footer">
Copyright &copy; Jive Software 2002-2004
</div>
</body>
</html>

View File

@ -0,0 +1,121 @@
<html>
<head>
<title>Smack: Provider Architecture - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">
Provider Architecture: Packet Extensions and Custom IQ's
</div>
<div class="nav">
&laquo; <a href="index.html">Table of Contents</a>
</div>
<p>
The Smack provider architecture is a system for plugging in
custom XML parsing of packet extensions and IQ packets. The
standard <a href="extensions/index.html">Smack Extensions</a>
are built using the provider architecture. Two types of
providers exist:<ul>
<li><tt>IQProvider</tt> -- parses IQ requests into Java objects.
<li><tt>PacketExtension</tt> -- parses XML sub-documents attached to
packets into PacketExtension instances.</ul>
<p class="subheader">IQProvider</p>
By default, Smack only knows how to process IQ packets with sub-packets that
are in a few namespaces such as:<ul>
<li>jabber:iq:auth
<li>jabber:iq:roster
<li>jabber:iq:register</ul>
Because many more IQ types are part of XMPP and its extensions, a pluggable IQ parsing
mechanism is provided. IQ providers are registered programatically or by creating a
smack.providers file in the META-INF directory of your JAR file. The file is an XML
document that contains one or more iqProvider entries, as in the following example:
<pre>
&lt;?xml version="1.0"?&gt;
&lt;smackProviders&gt;
&lt;iqProvider&gt;
&lt;elementName&gt;query&lt;/elementName&gt;
&lt;namespace&gt;jabber:iq:time&lt;/namespace&gt;
&lt;className&gt;org.jivesoftware.smack.packet.Time&lt/className&gt;
&lt;/iqProvider&gt;
&lt;/smackProviders&gt;</pre>
Each IQ provider is associated with an element name and a namespace. In the
example above, the element name is <tt>query</tt> and the namespace is
<tt>abber:iq:time</tt>. If multiple provider entries attempt to register to
handle the same namespace, the first entry loaded from the classpath will
take precedence. <p>
The IQ provider class can either implement the IQProvider
interface, or extend the IQ class. In the former case, each IQProvider is
responsible for parsing the raw XML stream to create an IQ instance. In
the latter case, bean introspection is used to try to automatically set
properties of the IQ instance using the values found in the IQ packet XML.
For example, an XMPP time packet resembles the following:
<pre>
&lt;iq type='result' to='joe@example.com' from='mary@example.com' id='time_1'&gt;
&lt;query xmlns='jabber:iq:time'&gt;
&lt;utc&gt;20020910T17:58:35&lt;/utc&gt;
&lt;tz&gt;MDT&lt;/tz&gt;
&lt;display&gt;Tue Sep 10 12:58:35 2002&lt;/display&gt;
&lt;/query&gt;
&lt;/iq&gt;</pre>
In order for this packet to be automatically mapped to the Time object listed in the
providers file above, it must have the methods setUtc(String), setTz(String), and
setDisplay(String). The introspection service will automatically try to convert the String
value from the XML into a boolean, int, long, float, double, or Class depending on the
type the IQ instance expects.<p>
<p class="subheader">PacketExtensionProvider</p>
Packet extension providers provide a pluggable system for
packet extensions, which are child elements in a custom namespace
of IQ, message and presence packets.
Each extension provider is registered with an element name and namespace
in the smack.providers file as in the following example:
<pre>
&lt;?xml version="1.0"?&gt;
&lt;smackProviders&gt;
&lt;extensionProvider&gt;
&lt;elementName&gt;x&lt;/elementName&gt;
&lt;namespace&gt;jabber:iq:event&lt;/namespace&gt;
&lt;className&gt;org.jivesoftware.smack.packet.MessageEvent&lt/className&gt;
&lt;/extensionProvider&gt;
&lt;/smackProviders&gt;</pre>
If multiple provider entries attempt to register to handle the same element
name and namespace, the first entry loaded from the classpath will take
precedence.<p>
Whenever a packet extension is found in a packet, parsing will
be passed to the correct provider. Each provider can either implement the
PacketExtensionProvider interface or be a standard Java Bean. In the
former case, each extension provider is responsible for parsing the raw
XML stream to contruct an object. In the latter case, bean introspection
is used to try to automatically set the properties of the class using
the values in the packet extension sub-element.<p>
When an extension provider is not registered for an element name and
namespace combination, Smack will store all top-level elements of the
sub-packet in DefaultPacketExtension object and then attach it to the packet.
<br clear="all" /><br><br>
<div class="footer">
Copyright &copy; Jive Software 2002-2004
</div>
</body>
</html>

View File

@ -0,0 +1,125 @@
<html>
<head>
<title>Smack: Roster and Presence - Jive Software</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="header">
Roster and Presence
</div>
<div class="nav">
&laquo; <a href="index.html">Table of Contents</a>
</div>
<p>
The roster lets you keep track of the availability ("presence") of other users.
A roster also allows you to organize users into groups such as "Friends" and
"Co-workers". Other IM systems refer to the roster as the buddy list, contact list,
etc.<p>
A <tt>Roster</tt> instance is obtained using the <tt>XMPPConnection.getRoster()</tt>
method, but only after successfully logging into a server.
<p class="subheader">Roster Entries</p>
<p>
Every user in a roster is represented by a RosterEntry, which consists of:<ul>
<li>An XMPP address (e.g. jsmith@example.com).
<li>A name you've assigned to the user (e.g. "Joe").
<li>The list of groups in the roster that the entry belongs to. If the roster
entry belongs to no groups, it's called an "unfiled entry".
</ul>
The following code snippet prints all entries in the roster:
<pre>
Roster roster = con.getRoster();
<b>for</b> (Iterator i=roster.getEntries(); i.hasNext(); ) {
System.out.println(i.next());
}
</pre>
Methods also exist to get individual entries, the list of unfiled entries, or to get one or
all roster groups.
<p class="subheader">Presence</p>
<img src="images/roster.png" width="166" height="322" vspace="5" hspace="5" alt="Roster" border="0" align="right">
<p>Every entry in the roster has presence associated with it. The
<tt>Roster.getPresence(String user)</tt> method will return a Presence object with
the user's presence or <tt>null</tt> if the user is not online or you are not
subscribed to the user's presence. <i>Note:</i> typically, presence
subscription is always tied to the user being on the roster, but this is not
true in all cases.</p>
<p>A user either has a presence of online or offline. When a user is online, their
presence may contain extended information such as what they are currently doing, whether
they wish to be disturbed, etc. See the Presence class for further details.</p>
<p class="subheader">Listening for Roster and Presence Changes</p>
<p>The typical use of the roster class is to display a tree view of groups and entries
along with the current presence value of each entry. As an example, see the image showing
a Roster in the Exodus XMPP client to the right.</p>
<p>The presence information will likely
change often, and it's also possible for the roster entries to change or be deleted.
To listen for changing roster and presence data, a RosterListener should be used.
The following code snippet registers a RosterListener with the Roster that prints
any presence changes in the roster to standard out. A normal client would use
similar code to update the roster UI with the changing information.
<br clear="all">
<pre>
final Roster roster = con.getRoster();
roster.addRosterListener(new RosterListener() {
<b>public void</b> rosterModified() {
<font color="gray"><i>// Ignore event for this example.</i></font>
}
<b>public void</b> presenceChanged(String user) {
<font color="gray"><i>// If the presence is unavailable then "null" will be printed,
// which is fine for this example.</i></font>
System.out.println(<font color="green">"Presence changed: "</font> + roster.getPresence(user));
}
});
</pre>
<p class="subheader">Adding Entries to the Roster</p>
<p>Rosters and presence use a permissions-based model where users must give permission before
they are added to someone else's roster. This protects a user's privacy by
making sure that only approved users are able to view their presence information.
Therefore, when you add a new roster entry it will be in a pending state until
the other user accepts your request.</p>
If another user requests a presence subscription so they can add you to their roster,
you must accept or reject that request. Smack handles presence subscription requests
in one of three ways: <ul>
<li> Automatically accept all presence subscription requests.
<li> Automatically reject all presence subscription requests.
<li> Process presence subscription requests manually.
</ul>
The mode can be set using the <tt>Roster.setSubscriptionMode(int subscriptionMode)</tt>
method. Simple clients normally use one of the automated subscription modes, while
full-featured clients should manually process subscription requests and let the
end-user accept or reject each request. If using the manual mode, a PacketListener
should be registered that listens for Presence packets that have a type of
<tt>Presence.Type.SUBSCRIBE</tt>.
<br clear="all" /><br><br>
<div class="footer">
Copyright &copy; Jive Software 2002-2004
</div>
</body>
</html>

View File

@ -0,0 +1,56 @@
BODY {
font-size : 100%;
background-color : #fff;
}
BODY, TD, TH {
font-family : tahoma, arial, helvetica;
font-size : 0.8em;
}
PRE, TT, CODE {
font-family : courier new, monospaced;
font-size : 1.0em;
}
A:hover {
text-decoration : none;
}
LI {
padding-bottom : 4px;
}
.header {
font-size : 1.4em;
font-weight : bold;
width : 100%;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
.subheader {
font-weight : bold;
}
.footer {
font-size : 0.8em;
color : #999;
text-align : center;
width : 100%;
border-top : 1px #ccc solid;
padding-top : 2px;
}
.code {
border : 1px #ccc solid;
padding : 0em 1.0em 0em 1.0em;
margin : 4px 0px 4px 0px;
}
.nav, .nav A {
font-family : verdana;
font-size : 0.85em;
color : #600;
text-decoration : none;
font-weight : bold;
}
.nav {
width : 100%;
border-bottom : 1px #ccc solid;
padding : 3px 3px 5px 1px;
}
.nav A:hover {
text-decoration : underline;
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Servlet 2.3 is required for Jive Forums 3 -->
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Smack Client UI</display-name>
<description>Smack sample UI</description>
<!-- Welcome file list -->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>

View File

@ -0,0 +1,138 @@
<%--
- $RCSfile$
- $Revision$
- $Date$
-
- Copyright (C) 2002-2003 Jive Software. All rights reserved.
-
- The Jive Software License (based on Apache Software License, Version 1.1)
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- 3. The end-user documentation included with the redistribution,
- if any, must include the following acknowledgment:
- "This product includes software developed by
- Jive Software (http://www.jivesoftware.com)."
- Alternately, this acknowledgment may appear in the software itself,
- if and wherever such third-party acknowledgments normally appear.
-
- 4. The names "Smack" and "Jive Software" must not be used to
- endorse or promote products derived from this software without
- prior written permission. For written permission, please
- contact webmaster@jivesoftware.com.
-
- 5. Products derived from this software may not be called "Smack",
- nor may "Smack" appear in their name, without prior written
- permission of Jive Software.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
- ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
--%>
<%@ page import="java.util.*,
org.jivesoftware.smack.*,
org.jivesoftware.smack.packet.*,
org.jivesoftware.smack.util.*"%>
<%@ include file="global.jsp" %>
<%
// If we don't have a valid connection then proceed to login
XMPPConnection conn = (XMPPConnection) session.getAttribute("connection");
if (conn == null || !conn.isConnected()) {
response.sendRedirect("login.jsp");
return;
}
Roster roster = conn.getRoster();
// Get parameters
String user = getParameter(request, "user");
String nickname = getParameter(request, "nickname");
String group1 = getParameter(request, "group1");
String group2 = getParameter(request, "group2");
// Create a new entry in the roster that belongs to a certain groups
if (user != null) {
roster.createEntry(user, nickname, new String[] {group1, group2});
response.sendRedirect("viewRoster.jsp");
return;
}
%>
<html>
<head>
<title>Add Contact</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link href="css/general.css" rel="stylesheet" type="text/css">
</head>
<body>
<table width="100%" border="0">
<tr>
<td><span id="bigBlack">Add contact to roster</span></td>
<td align="right"><a href="viewRoster.jsp"><img src="images/address_book.png" alt="View roster" border="0"></a></td>
</tr>
<tr>
<td colspan="2">&nbsp;</td>
</tr>
<tr>
<td colspan="2"><table width="100%" border="0">
<tr>
<td width="20%">&nbsp;</td>
<td width="60%"> <table cellSpacing=0 borderColorDark=#E0E0E0 cellPadding=0 width=100% align=center borderColorLight=#000000 border=1>
<tr bgcolor="#AAAAAA">
<td class=text id=bigWhite height=16 align="center"> <b>Contact
Information</b> </td>
</tr>
<tr>
<td align="center"> <table width="100%" border="0">
<form method="post" action="addContact.jsp">
<tr>
<td class=text id=black height=16>Username:</td>
<td><input type="text" name="user"> &nbsp;<span class=text id=black height=16>(e.g.
johndoe@jabber.org)</span></td>
</tr>
<tr>
<td class=text id=black height=16>Nickname:</td>
<td><input type="text" name="nickname"></td>
</tr>
<tr>
<td class=text id=black height=16>Group 1:</td>
<td><input type="text" name="group1" value="<%= (group1!=null)?group1:"" %>"></td>
</tr>
<tr>
<td class=text id=black height=16>Group 2:</td>
<td><input type="text" name="group2"></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td colspan=2 align="center"> <input type="submit" value="Add Contact"></td>
</tr>
</form>
</table></td>
</tr>
</table></td>
<td width="20%">&nbsp;</td>
</tr>
</table></td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,60 @@
<%--
- $$RCSfile$$
- $$Revision$$
- $$Date$$
-
- Copyright (C) 2002-2003 Jive Software. All rights reserved.
-
- The Jive Software License (based on Apache Software License, Version 1.1)
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- 3. The end-user documentation included with the redistribution,
- if any, must include the following acknowledgment:
- "This product includes software developed by
- Jive Software (http://www.jivesoftware.com)."
- Alternately, this acknowledgment may appear in the software itself,
- if and wherever such third-party acknowledgments normally appear.
-
- 4. The names "Smack" and "Jive Software" must not be used to
- endorse or promote products derived from this software without
- prior written permission. For written permission, please
- contact webmaster@jivesoftware.com.
-
- 5. Products derived from this software may not be called "Smack",
- nor may "Smack" appear in their name, without prior written
- permission of Jive Software.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
- ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
--%>
<html>
<head>
<title>Chat with contact</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link href="css/general.css" rel="stylesheet" type="text/css">
</head>
<body>
Not implemented yet! <a href="viewRoster.jsp"><img src="images/address_book.png" alt="View roster" border="0"></a>
</body>
</html>

View File

@ -0,0 +1,36 @@
BODY
{
FONT-FAMILY: Verdana, Geneva, Arial, Helvetica, sans-serif;
FONT-SIZE: 10px;
margin-left: 0px;
margin-right: 0px;
margin-bottom: 0px;
margin-top: 0px;
background-color: #FFFFFF;
}
.text {
FONT-FAMILY: Verdana, Geneva, Arial, Helvetica, sans-serif;
FONT-SIZE: 10px;
}
input,textarea,select
{
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size: 10px;
}
#black {
color: #000000;
font-weight: BOLD;
}
#white {
color: FFFFFF;
font-weight: BOLD;
}
#bigWhite {
color: FFFFFF;
font-weight: BOLD;
font-size: 14px;
}
#bigBlack {
font-weight: BOLD;
font-size: 18px;
}

View File

@ -0,0 +1,66 @@
<%--
- $$RCSfile$$
- $$Revision$$
- $$Date$$
-
- Copyright (C) 2002-2003 Jive Software. All rights reserved.
-
- The Jive Software License (based on Apache Software License, Version 1.1)
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- 3. The end-user documentation included with the redistribution,
- if any, must include the following acknowledgment:
- "This product includes software developed by
- Jive Software (http://www.jivesoftware.com)."
- Alternately, this acknowledgment may appear in the software itself,
- if and wherever such third-party acknowledgments normally appear.
-
- 4. The names "Smack" and "Jive Software" must not be used to
- endorse or promote products derived from this software without
- prior written permission. For written permission, please
- contact webmaster@jivesoftware.com.
-
- 5. Products derived from this software may not be called "Smack",
- nor may "Smack" appear in their name, without prior written
- permission of Jive Software.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL JIVE SOFTWARE OR
- ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
--%>
<%!
public static String getParameter(HttpServletRequest request, String name)
{
String temp = request.getParameter(name);
if (temp != null) {
if (temp.equals("")) {
return null;
}
else {
return temp;
}
}
else {
return null;
}
}
%>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Some files were not shown because too many files have changed in this diff Show More