diff --git a/apps/webchat/source/java/org/jivesoftware/webchat/ChatServlet.java b/apps/webchat/source/java/org/jivesoftware/webchat/ChatServlet.java
new file mode 100644
index 000000000..bf364a211
--- /dev/null
+++ b/apps/webchat/source/java/org/jivesoftware/webchat/ChatServlet.java
@@ -0,0 +1,346 @@
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright (C) 2003 CoolServlets, Inc. All rights reserved.
+ *
+ * This software is the proprietary information of Jive Software. Use is subject to license terms.
+ */
+
+package org.jivesoftware.webchat;
+
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smack.packet.Message;
+
+import javax.servlet.http.*;
+import javax.servlet.ServletException;
+import javax.servlet.ServletConfig;
+import javax.servlet.RequestDispatcher;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.*;
+
+/**
+ * For now, it's assumed the all JSP pages are in the context root.
+ *
+ * Init params:
+ * - host:
+ *
- port (optional):
+ *
- SSLEnabled (optional):
+ *
+ *
+ *
+ */
+public class ChatServlet extends HttpServlet implements HttpSessionListener {
+
+ private Map chatData = new HashMap();
+
+ private String host;
+ private int port = -1;
+ private boolean SSLEnabled;
+
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+ host = config.getInitParameter("host");
+ if (host == null) {
+ throw new ServletException("Init parameter \"host\" must be set.");
+ }
+ String portString = config.getInitParameter("port");
+ if (portString != null) {
+ try {
+ port = Integer.parseInt(portString);
+ }
+ catch (NumberFormatException nfe) {
+ throw new ServletException("Init parameter \"port\" must be a valid number.", nfe);
+ }
+ }
+ SSLEnabled = Boolean.valueOf(config.getInitParameter("SSLEnabled")).booleanValue();
+ }
+
+ public void destroy() {
+ super.destroy();
+ // Clean up.
+ for (Iterator i=chatData.values().iterator(); i.hasNext(); ) {
+ ChatData data = (ChatData)i.next();
+ if (data.groupChat != null) {
+ data.groupChat.leave();
+ }
+ data.connection.close();
+ }
+ }
+
+ 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");
+ if ("login".equals(command)) {
+ String returnCode = handleLogin(request, response);
+ if ("success".equals(returnCode)) {
+ response.sendRedirect(path + "/chat-launcher.jsp");
+ return;
+ }
+ else {
+ // error, so go back to index page (so errors can be printed)
+ RequestDispatcher rd = request.getRequestDispatcher("/index.jsp");
+ rd.forward(request, response);
+ return;
+ }
+ }
+ else if ("logout".equals(command)) {
+ XMPPConnection con = (XMPPConnection)chatData.get(sessionID);
+
+ }
+ else if ("write".equals(command)) {
+ String message = request.getParameter("message");
+ ChatData data = (ChatData)chatData.get(sessionID);
+ if (message == null) {
+ writeData("Parameter \"message\" is required.", response);
+ return;
+ }
+ else if (data == null) {
+ writeData("Must login first.", response);
+ return;
+ }
+ try {
+ data.groupChat.sendMessage(message);
+ StringBuffer reply = new StringBuffer();
+ reply.append("\n");
+
+ reply.append("\n");
+ reply.append("\n");
+ reply.append("Chat Form");
+ reply.append("\n");
+ reply.append("");
+ writeData(reply.toString(), response);
+ }
+ catch (XMPPException e) {
+ e.printStackTrace();
+ }
+ }
+ else if ("read".equals(command)) {
+ ChatData data = (ChatData)chatData.get(sessionID);
+ if (data == null) {
+ writeData("Must login first.", response);
+ return;
+ }
+ StringBuffer reply = new StringBuffer();
+ reply.append("\n");
+ reply.append("\n\n");
+ reply.append("Chat Read Page\n");
+ reply.append("\n");
+ reply.append("\n");
+ reply.append("\n");
+ reply.append("\n");
+ reply.append("");
+ writeData(reply.toString(), response);
+ }
+ else if (command != null) {
+ writeData("Invalid command.", response);
+ }
+ else {
+ writeData("Jive Messenger Chat Servlet", response);
+ }
+ }
+
+ /**
+ * Handles all login logic.
+ *
+ * @param request
+ * @param response
+ */
+ private String handleLogin(HttpServletRequest request, HttpServletResponse response) {
+ // The session ID - used to identify different chat sessions
+ String sessionID = request.getSession().getId();
+ // Get expected parameters
+ String username = request.getParameter("username");
+ String password = request.getParameter("password");
+ String room = request.getParameter("room");
+ String nickname = request.getParameter("nickname");
+ String garbage = request.getParameter("garbage");
+ // Validate parameters
+ Map errors = new HashMap();
+ if (username == null || "".equals(username.trim())) {
+ errors.put("username","");
+ }
+ if (password == null || "".equals(password.trim())) {
+ errors.put("password","");
+ }
+ if (room == null || "".equals(room.trim())) {
+ errors.put("room","");
+ }
+ if (nickname == null || "".equals(nickname.trim())) {
+ errors.put("nickname","");
+ }
+ // If there were no errors, continue
+ if (errors.size() == 0) {
+ ChatData data = (ChatData)chatData.get(sessionID);
+ // If a connection already exists for this session, close it before creating
+ // another.
+ if (data != null) {
+ if (data.groupChat != null) {
+ data.groupChat.leave();
+ }
+ data.connection.close();
+ }
+ // Otherwise, create new a new connection.
+ else {
+ data = new ChatData();
+ }
+ try {
+ // Create connection.
+ if (!SSLEnabled) {
+ if (port != -1) {
+ data.connection = new XMPPConnection(host, port);
+ }
+ else {
+ data.connection = new XMPPConnection(host);
+ }
+ }
+ else {
+ if (port != -1) {
+ data.connection = new SSLXMPPConnection(host, port);
+ }
+ else {
+ data.connection = new SSLXMPPConnection(host);
+ }
+ }
+ // Login
+ data.connection.login(username, password, "Jive Messenger Chat Servlet " + garbage);
+ // Join groupChat room.
+ data.groupChat = data.connection.createGroupChat(room);
+ data.groupChat.join(nickname);
+
+ // Save chat data in the map.
+ chatData.put(sessionID, data);
+
+ // 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("messenger.servlet.nickname", nickname);
+ }
+ catch (XMPPException e) {
+ errors.put("general","");
+ e.printStackTrace();
+ }
+ catch (ClassCastException e) {
+ // TODO: remove this catch - it's just a bug workaround for now
+ errors.put("general","");
+ e.printStackTrace();
+ }
+ }
+
+ if (errors.size() > 0) {
+ // Add the error map to the request as an attribute:
+ request.setAttribute("messenger.servlet.errors",errors);
+ return "error";
+ }
+ else {
+ return "success";
+ }
+ }
+
+ // HttpSessionListener Interface
+
+ public void sessionCreated(HttpSessionEvent event) {
+ // Do nothing.
+ }
+
+ public void sessionDestroyed(HttpSessionEvent event) {
+ // Close the XMPPConnection if there is one.
+ String sessionID = event.getSession().getId();
+ ChatData data = (ChatData)chatData.get(sessionID);
+ if (data.groupChat != null) {
+ data.groupChat.leave();
+ }
+ data.connection.close();
+ }
+
+ private void writeData(String data, HttpServletResponse response) {
+ try {
+ PrintWriter out = response.getWriter();
+ response.setContentType("text/html");
+ out.println(data);
+ out.close();
+ }
+ catch (IOException ioe) {}
+ }
+
+ private class ChatData {
+ public XMPPConnection connection;
+ public GroupChat groupChat;
+ }
+
+ /**
+ * Replaces all instances of oldString with newString in string.
+ *
+ * @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
+ */
+ public static final String replace(String string, String oldString, String newString) {
+ if (string == null) {
+ return null;
+ }
+ // If the newString is null just return the string since there's nothing
+ // to replace.
+ if (newString == null) {
+ return string;
+ }
+ int i=0;
+ // 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);
+ buf.append(string2, 0, i).append(newString2);
+ i += oLength;
+ int j = i;
+ // 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;
+ }
+}
\ No newline at end of file