mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-12-26 04:28:00 +01:00
ff03adb970
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@1978 b35dd754-fafc-0310-a699-88a17e54d16e
729 lines
26 KiB
Java
729 lines
26 KiB
Java
/**
|
|
* $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, "&", "&");
|
|
body = this.replace(body, "<", "<");
|
|
body = this.replace(body, ">", ">");
|
|
|
|
// replace newlines in the body:
|
|
body = this.replace(body, "\r", "");
|
|
body = this.replace(body, "\n", "<br>");
|
|
|
|
// encode the quotes
|
|
body = this.replace(body, "\"", """);
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|