Commit 37bf168a authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gaston

Added support for external components. JM-5


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@945 b35dd754-fafc-0310-a699-88a17e54d16e
parent c5e9bc33
......@@ -11,23 +11,24 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.AuthFactory;
import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
import java.util.ArrayList;
import java.util.List;
/**
* Implements the TYPE_IQ jabber:iq:auth protocol (plain only). Clients
* use this protocol to authenticate with the server. A 'get' query
......@@ -79,7 +80,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
public IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException {
try {
Session session = sessionManager.getSession(packet.getFrom());
ClientSession session = sessionManager.getSession(packet.getFrom());
IQ response = null;
try {
Element iq = packet.getElement();
......@@ -146,14 +147,15 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
}
private IQ login(String username, Element iq, IQ packet, IQ response, String password,
Session session, String digest) throws UnauthorizedException, UserNotFoundException
ClientSession session, String digest) throws UnauthorizedException,
UserNotFoundException
{
JID jid = localServer.createJID(username, iq.elementTextTrim("resource"));
// If a session already exists with the requested JID, then check to see
// if we should kick it off or refuse the new connection
if (sessionManager.isActiveRoute(jid)) {
Session oldSession = null;
ClientSession oldSession = null;
try {
oldSession = sessionManager.getSession(jid);
oldSession.incrementConflictCount();
......@@ -218,7 +220,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
return response;
}
private IQ anonymousLogin(Session session, IQ packet) throws UnauthorizedException {
private IQ anonymousLogin(ClientSession session, IQ packet) {
IQ response = IQ.createResultIQ(packet);;
if (anonymousAllowed) {
session.setAnonymousAuth();
......
......@@ -11,30 +11,32 @@
package org.jivesoftware.messenger.handler;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.forms.DataForm;
import org.jivesoftware.messenger.forms.FormField;
import org.jivesoftware.messenger.forms.spi.XDataFormImpl;
import org.jivesoftware.messenger.forms.spi.XFormFieldImpl;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.group.GroupManager;
import org.jivesoftware.messenger.roster.RosterManager;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.*;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.util.Log;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
/**
* Implements the TYPE_IQ jabber:iq:register protocol (plain only). Clients
* use this protocol to register a user account with the server.
......@@ -146,7 +148,7 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
return delegate.handleIQ(packet);
}
Session session = sessionManager.getSession(packet.getFrom());
ClientSession session = sessionManager.getSession(packet.getFrom());
IQ reply = null;
// If inband registration is not allowed, return an error.
if (!enabled) {
......@@ -185,9 +187,6 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
catch (UserNotFoundException e) {
reply.setChildElement(probeResult.createCopy());
}
catch (UnauthorizedException e) {
reply.setChildElement(probeResult.createCopy());
}
}
else {
// This is a workaround. Since we don't want to have an incorrect TO attribute
......
......@@ -11,15 +11,21 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.roster.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.*;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.roster.Roster;
import org.xmpp.packet.*;
import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import java.util.ArrayList;
import java.util.Iterator;
......@@ -157,7 +163,7 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
UserAlreadyExistsException, SharedGroupException {
IQ returnPacket = null;
Session session = sessionManager.getSession(packet.getFrom());
ClientSession session = sessionManager.getSession(packet.getFrom());
IQ.Type type = packet.getType();
......
......@@ -11,18 +11,9 @@
package org.jivesoftware.messenger.net;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.net.Socket;
import java.net.SocketException;
import org.dom4j.Element;
import org.dom4j.io.XPPPacketReader;
import org.jivesoftware.messenger.Connection;
import org.jivesoftware.messenger.PacketRouter;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.audit.Auditor;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.LocaleUtils;
......@@ -35,6 +26,13 @@ import org.xmpp.packet.Message;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Roster;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.net.Socket;
import java.net.SocketException;
/**
* Reads XMPP XML from a socket.
*
......@@ -47,9 +45,6 @@ public class SocketReadThread extends Thread {
*/
private static String CHARSET = "UTF-8";
private static final String ETHERX_NAMESPACE = "http://etherx.jabber.org/streams";
private static final String FLASH_NAMESPACE = "http://www.jabber.com/streams/flash";
private Socket sock;
private Session session;
private Connection connection;
......@@ -73,16 +68,15 @@ public class SocketReadThread extends Thread {
* @param serverName The name of the server this socket is working for
* @param auditor The audit manager that will audit incoming packets
* @param sock The socket to read from
* @param session The session being read
* @param conn The connection being read
*/
public SocketReadThread(PacketRouter router, String serverName, Auditor auditor, Socket sock,
Session session) {
Connection conn) {
super("SRT reader");
this.serverName = serverName;
this.router = router;
this.auditor = auditor;
this.session = session;
connection = session.getConnection();
this.connection = conn;
this.sock = sock;
}
......@@ -122,14 +116,16 @@ public class SocketReadThread extends Thread {
// unavailable presence
if (clearSignout == false) {
if (session != null && session.getStatus() == Session.STATUS_AUTHENTICATED) {
Presence presence = session.getPresence();
if (presence != null) {
// Simulate an unavailable presence sent by the user.
Presence packet = presence.createCopy();
packet.setType(Presence.Type.unavailable);
packet.setFrom(session.getAddress());
router.route(packet);
clearSignout = true;
if (session instanceof ClientSession) {
Presence presence = ((ClientSession) session).getPresence();
if (presence != null) {
// Simulate an unavailable presence sent by the user.
Presence packet = presence.createCopy();
packet.setType(Presence.Type.unavailable);
packet.setFrom(session.getAddress());
router.route(packet);
clearSignout = true;
}
}
}
}
......@@ -224,88 +220,44 @@ public class SocketReadThread extends Thread {
}
/**
* Uses the XPP to grab the opening stream tag and create
* an active session object. In all cases, the method obtains the
* opening stream tag, checks for errors, and either creates a session
* or returns an error and kills the connection. If the connection
* remains open, the XPP will be set to be ready for the first packet.
* A call to next() should result in an START_TAG state with the first
* packet in the stream.
*
* @throws UnauthorizedException If the caller did not have permission
* to use this method.
* Uses the XPP to grab the opening stream tag and create an active session
* object. The session to create will depend on the sent namespace. In all
* cases, the method obtains the opening stream tag, checks for errors, and
* either creates a session or returns an error and kills the connection.
* If the connection remains open, the XPP will be set to be ready for the
* first packet. A call to next() should result in an START_TAG state with
* the first packet in the stream.
*/
private void createSession() throws UnauthorizedException, XmlPullParserException, IOException, Exception {
private void createSession() throws UnauthorizedException, XmlPullParserException, IOException {
XmlPullParser xpp = reader.getXPPParser();
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
eventType = xpp.next();
}
boolean isFlashClient = xpp.getPrefix().equals("flash");
// Conduct error checking, the opening tag should be 'stream'
// in the 'etherx' namespace
if (!xpp.getName().equals("stream") && !isFlashClient) {
throw new XmlPullParserException(LocaleUtils.getLocalizedString("admin.error.bad-stream"));
}
if (!xpp.getNamespace(xpp.getPrefix()).equals(ETHERX_NAMESPACE) &&
!(isFlashClient && xpp.getNamespace(xpp.getPrefix()).equals(FLASH_NAMESPACE))) {
throw new XmlPullParserException(LocaleUtils.getLocalizedString("admin.error.bad-namespace"));
// Create the correct session based on the sent namespace
if ("jabber:client".equals(xpp.getNamespaceUri(xpp.getDepth()-1))) {
// The connected client is a regular client so create a ClientSession
session = ClientSession.createSession(serverName, reader, connection);
}
// TODO Should we keep the language requested by the client in the session so that future
// messages to the client may use the correct resource bundle? So far we are only answering
// the same language specified by the client (if any) or if none then answer a default
// language
String language = "en";
for (int i = 0; i < xpp.getAttributeCount(); i++) {
if ("lang".equals(xpp.getAttributeName(i))) {
language = xpp.getAttributeValue(i);
}
}
Writer writer = connection.getWriter();
// Build the start packet response
StringBuffer sb = new StringBuffer();
sb.append("<?xml version='1.0' encoding='");
sb.append(CHARSET);
sb.append("'?>");
if (isFlashClient) {
sb.append("<flash:stream xmlns:flash=\"http://www.jabber.com/streams/flash\" ");
else if ("jabber:component:accept".equals(xpp.getNamespaceUri(xpp.getDepth()-1))) {
// The connected client is a component so create a ComponentSession
session = ComponentSession.createSession(serverName, reader, connection);
}
else {
sb.append("<stream:stream ");
Writer writer = connection.getWriter();
StringBuffer sb = new StringBuffer();
sb.append("<?xml version='1.0' encoding='");
sb.append(CHARSET);
sb.append("'?>");
// Include the bad-namespace-prefix in the response
sb.append("<stream:error>");
sb.append("<bad-namespace-prefix xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\"/>");
sb.append("</stream:error>");
sb.append("</stream:stream>");
writer.write(sb.toString());
writer.flush();
// Close the underlying connection
connection.close();
}
sb.append("xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\" from=\"");
sb.append(serverName);
sb.append("\" id=\"");
sb.append(session.getStreamID().toString());
sb.append("\" xml:lang=\"");
sb.append(language);
sb.append("\">");
writer.write(sb.toString());
// If this is a flash client then flag the connection and append a special caracter to the
// response
if (isFlashClient) {
session.getConnection().setFlashClient(true);
writer.write('\0');
// Skip possible end of tags and \0 characters
/*final int[] holderForStartAndLength = new int[2];
final char[] chars = xpp.getTextCharacters(holderForStartAndLength);
if (chars[xpp.getColumnNumber()-2] == '/') {
xpp.next();
try {
xpp.next();
}
catch (XmlPullParserException ie) {
// We expect this exception since the parser is reading a \0 character
}
}*/
}
writer.flush();
// TODO: check for SASL support in opening stream tag
}
}
......@@ -11,16 +11,16 @@
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.audit.AuditManager;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.net.SSLSocketAcceptThread;
import org.jivesoftware.messenger.net.SocketAcceptThread;
import org.jivesoftware.messenger.net.SocketConnection;
import org.jivesoftware.messenger.net.SocketReadThread;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
......@@ -113,16 +113,11 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
auditManager.getAuditor(),
sock,
isSecure);
Session session = sessionManager.createSession(conn);
SocketReadThread reader = new SocketReadThread(router,
serverName, auditManager.getAuditor(),
sock, session);
SocketReadThread reader = new SocketReadThread(router, serverName,
auditManager.getAuditor(), sock, conn);
reader.setDaemon(true);
reader.start();
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
catch (IOException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
......
......@@ -11,21 +11,7 @@
package org.jivesoftware.messenger.spi;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jivesoftware.messenger.Component;
import org.jivesoftware.messenger.ComponentManager;
import org.jivesoftware.messenger.PacketDeliverer;
import org.jivesoftware.messenger.PresenceManager;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.SessionManager;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.user.UserManager;
......@@ -37,6 +23,9 @@ import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Simple in memory implementation of the PresenceManager interface.
*
......@@ -238,7 +227,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
}
Presence presence = null;
for (Session session : sessionManager.getSessions(user.getUsername())) {
for (ClientSession session : sessionManager.getSessions(user.getUsername())) {
if (presence == null) {
presence = session.getPresence();
}
......@@ -263,7 +252,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
}
List<Presence> presences = new ArrayList<Presence>();
for (Session session : sessionManager.getSessions(user.getUsername())) {
for (ClientSession session : sessionManager.getSessions(user.getUsername())) {
presences.add(session.getPresence());
}
return Collections.unmodifiableCollection(presences);
......@@ -298,9 +287,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
Component component = getPresenceComponent(probee);
if (server.isLocal(probee)) {
if (probee.getNode() != null && !"".equals(probee.getNode())) {
Collection<Session> sessions =
Collection<ClientSession> sessions =
sessionManager.getSessions(probee.getNode());
for (Session session : sessions) {
for (ClientSession session : sessions) {
Presence presencePacket = session.getPresence().createCopy();
presencePacket.setFrom(session.getAddress());
try {
......@@ -317,7 +306,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
presence.setType(Presence.Type.probe);
presence.setFrom(server.createJID(prober, ""));
presence.setTo(probee);
component.processPacket(presence);
component.process(presence);
}
else {
Presence presence = (Presence) foreignUserCache.get(probee.toBareJID());
......@@ -345,9 +334,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
public void probePresence(JID prober, JID probee) {
try {
if (server.isLocal(probee)) {
Collection<Session> sessions =
Collection<ClientSession> sessions =
sessionManager.getSessions(probee.getNode());
for (Session session : sessions) {
for (ClientSession session : sessions) {
Presence presencePacket = session.getPresence().createCopy();
presencePacket.setFrom(session.getAddress());
try {
......
......@@ -38,7 +38,7 @@
// Get the session & address objects
SessionManager sessionManager = webManager.getSessionManager();
JID address = new JID(jid);
Session currentSess = sessionManager.getSession(address);
ClientSession currentSess = sessionManager.getSession(address);
boolean isAnonymous = address.getNode() == null || "".equals(address.getNode());
// Get a presence manager
......@@ -57,7 +57,7 @@
}
// See if there are multiple sessions for this user:
Collection<Session> sessions = null;
Collection<ClientSession> sessions = null;
int sessionCount = sessionManager.getSessionCount(address.getNode());
if (!isAnonymous && sessionCount > 1) {
sessions = sessionManager.getSessions(address.getNode());
......@@ -279,7 +279,7 @@ user <b><%= address.getNode() %></b> has multiple sessions open, they will appea
<% int count = 0;
String linkURL = "session-details.jsp";
for (Session sess : sessions) {
for (ClientSession sess : sessions) {
count++;
boolean current = sess.getAddress().equals(address);
%>
......
......@@ -130,7 +130,7 @@ Below is a list of sessions on this server.
SessionResultFilter filter = new SessionResultFilter();
filter.setStartIndex(start);
filter.setNumResults(range);
Collection<Session> sessions = sessionManager.getSessions(filter);
Collection<ClientSession> sessions = sessionManager.getSessions(filter);
if (sessions.isEmpty()) {
%>
<tr>
......@@ -146,7 +146,7 @@ Below is a list of sessions on this server.
<% int count = start;
boolean current = false; // needed in session-row.jspf
String linkURL = "session-details.jsp";
for (Session sess : sessions) {
for (ClientSession sess : sessions) {
count++;
%>
<%@ include file="session-row.jspf" %>
......
......@@ -105,13 +105,13 @@
// Get all sessions associated with this user:
int numSessions = -1;
Session sess = null;
Collection<Session> sessions = null;
ClientSession sess = null;
Collection<ClientSession> sessions = null;
if (user != null) {
numSessions = sessionManager.getSessionCount(user.getUsername());
sessions = sessionManager.getSessions(user.getUsername());
if (numSessions == 1) {
sess = (Session)sessions.iterator().next();
sess = sessions.iterator().next();
}
}
%>
......@@ -205,9 +205,9 @@ function updateSelect(el) {
<select size="2" name="jid" multiple>
<% Iterator iter = sessions.iterator();
<% Iterator<ClientSession> iter = sessions.iterator();
while (iter.hasNext()) {
sess = (Session)iter.next();
sess = iter.next();
%>
<option value="<%= sess.getAddress().toString() %>"><%= sess.getAddress().toString() %></option>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment