1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-27 00:32:07 +01:00

Patch double committed for some reason. Also cleaned up a couple of pointless warnings.

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@10674 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Daniel Henninger 2008-07-15 03:17:43 +00:00 committed by dhenninger
parent 4c4cc77e42
commit 7f77fda9db
8 changed files with 5 additions and 913 deletions

View file

@ -26,7 +26,7 @@ import java.util.*;
* and {@link org.jivesoftware.smack.provider.PrivacyProvider} to allow and block
* communications from other users. It contains the appropriate structure to suit
* user-defined privacy lists. Different configured Privacy packages are used in the
* Server Manager communication in order to:
* server & manager communication in order to:
* <ul>
* <li>Retrieving one's privacy lists.
* <li>Adding, removing, and editing one's privacy lists.

View file

@ -52,57 +52,3 @@ class DirectSocketFactory
}
}
package org.jivesoftware.smack.proxy;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
/**
* SocketFactory for direct connection
*
* @author Atul Aggarwal
*/
class DirectSocketFactory
extends SocketFactory
{
public DirectSocketFactory()
{
}
public Socket createSocket(String host, int port)
throws IOException, UnknownHostException
{
Socket newSocket = new Socket(Proxy.NO_PROXY);
newSocket.connect(new InetSocketAddress(host,port));
return newSocket;
}
public Socket createSocket(String host ,int port, InetAddress localHost,
int localPort)
throws IOException, UnknownHostException
{
return new Socket(host,port,localHost,localPort);
}
public Socket createSocket(InetAddress host, int port)
throws IOException
{
Socket newSocket = new Socket(Proxy.NO_PROXY);
newSocket.connect(new InetSocketAddress(host,port));
return newSocket;
}
public Socket createSocket( InetAddress address, int port,
InetAddress localAddress, int localPort)
throws IOException
{
return new Socket(address,port,localAddress,localPort);
}
}

View file

@ -154,159 +154,3 @@ class HTTPProxySocketFactory
= Pattern.compile("HTTP/\\S+\\s(\\d+)\\s(.*)\\s*");
}
package org.jivesoftware.smack.proxy;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
import org.jivesoftware.smack.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Http Proxy Socket Factory which returns socket connected to Http Proxy
*
* @author Atul Aggarwal
*/
class HTTPProxySocketFactory
extends SocketFactory
{
private ProxyInfo proxy;
public HTTPProxySocketFactory(ProxyInfo proxy)
{
this.proxy = proxy;
}
public Socket createSocket(String host, int port)
throws IOException, UnknownHostException
{
return httpProxifiedSocket(host, port);
}
public Socket createSocket(String host ,int port, InetAddress localHost,
int localPort)
throws IOException, UnknownHostException
{
return httpProxifiedSocket(host, port);
}
public Socket createSocket(InetAddress host, int port)
throws IOException
{
return httpProxifiedSocket(host.getHostAddress(), port);
}
public Socket createSocket( InetAddress address, int port,
InetAddress localAddress, int localPort)
throws IOException
{
return httpProxifiedSocket(address.getHostAddress(), port);
}
private Socket httpProxifiedSocket(String host, int port)
throws IOException
{
String proxyhost = proxy.getProxyAddress();
int proxyPort = proxy.getProxyPort();
Socket socket = new Socket(proxyhost,proxyPort);
String hostport = "CONNECT " + host + ":" + port;
String proxyLine;
String username = proxy.getProxyUsername();
if (username == null)
{
proxyLine = "";
}
else
{
String password = proxy.getProxyPassword();
proxyLine = "\r\nProxy-Authorization: Basic "
+ new String (Base64.encodeBytes((username + ":"
+ password).getBytes("UTF-8")));
}
socket.getOutputStream().write((hostport + " HTTP/1.1\r\nHost: "
+ hostport + proxyLine + "\r\n\r\n").getBytes("UTF-8"));
InputStream in = socket.getInputStream();
StringBuilder got = new StringBuilder(100);
int nlchars = 0;
while (true)
{
char c = (char) in.read();
got.append(c);
if (got.length() > 1024)
{
throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Recieved " +
"header of >1024 characters from "
+ proxyhost + ", cancelling connection");
}
if (c == -1)
{
throw new ProxyException(ProxyInfo.ProxyType.HTTP);
}
if ((nlchars == 0 || nlchars == 2) && c == '\r')
{
nlchars++;
}
else if ((nlchars == 1 || nlchars == 3) && c == '\n')
{
nlchars++;
}
else
{
nlchars = 0;
}
if (nlchars == 4)
{
break;
}
}
if (nlchars != 4)
{
throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Never " +
"received blank line from "
+ proxyhost + ", cancelling connection");
}
String gotstr = got.toString();
BufferedReader br = new BufferedReader(new StringReader(gotstr));
String response = br.readLine();
if (response == null)
{
throw new ProxyException(ProxyInfo.ProxyType.HTTP, "Empty proxy " +
"response from " + proxyhost + ", cancelling");
}
Matcher m = RESPONSE_PATTERN.matcher(response);
if (!m.matches())
{
throw new ProxyException(ProxyInfo.ProxyType.HTTP , "Unexpected " +
"proxy response from " + proxyhost + ": " + response);
}
int code = Integer.parseInt(m.group(1));
if (code != HttpURLConnection.HTTP_OK)
{
throw new ProxyException(ProxyInfo.ProxyType.HTTP);
}
return socket;
}
private static final Pattern RESPONSE_PATTERN
= Pattern.compile("HTTP/\\S+\\s(\\d+)\\s(.*)\\s*");
}

View file

@ -12,34 +12,7 @@ public class ProxyException
{
public ProxyException(ProxyInfo.ProxyType type, String ex, Throwable cause)
{
super("Proxy Exception " + type.toString() + " : "+ex , cause);
}
public ProxyException(ProxyInfo.ProxyType type, String ex)
{
super("Proxy Exception " + type.toString() + " : "+ex);
}
public ProxyException(ProxyInfo.ProxyType type)
{
super("Proxy Exception " + type.toString() + " : " + "Unknown Error");
}
}
package org.jivesoftware.smack.proxy;
import java.io.IOException;
/**
* An exception class to handle exceptions caused by proxy.
*
* @author Atul Aggarwal
*/
public class ProxyException
extends IOException
{
public ProxyException(ProxyInfo.ProxyType type, String ex, Throwable cause)
{
super("Proxy Exception " + type.toString() + " : "+ex , cause);
super("Proxy Exception " + type.toString() + " : "+ex+", "+cause);
}
public ProxyException(ProxyInfo.ProxyType type, String ex)

View file

@ -112,117 +112,3 @@ public class ProxyInfo
}
}
}
package org.jivesoftware.smack.proxy;
import javax.net.SocketFactory;
/**
* Class which stores proxy information such as proxy type, host, port,
* authentication etc.
*
* @author Atul Aggarwal
*/
public class ProxyInfo
{
public static enum ProxyType
{
NONE,
HTTP,
SOCKS4,
SOCKS5
}
private String proxyAddress;
private int proxyPort;
private String proxyUsername;
private String proxyPassword;
private ProxyType proxyType;
public ProxyInfo( ProxyType pType, String pHost, int pPort, String pUser,
String pPass)
{
this.proxyType = pType;
this.proxyAddress = pHost;
this.proxyPort = pPort;
this.proxyUsername = pUser;
this.proxyPassword = pPass;
}
public static ProxyInfo forHttpProxy(String pHost, int pPort, String pUser,
String pPass)
{
return new ProxyInfo(ProxyType.HTTP, pHost, pPort, pUser, pPass);
}
public static ProxyInfo forSocks4Proxy(String pHost, int pPort, String pUser,
String pPass)
{
return new ProxyInfo(ProxyType.SOCKS4, pHost, pPort, pUser, pPass);
}
public static ProxyInfo forSocks5Proxy(String pHost, int pPort, String pUser,
String pPass)
{
return new ProxyInfo(ProxyType.SOCKS5, pHost, pPort, pUser, pPass);
}
public static ProxyInfo forNoProxy()
{
return new ProxyInfo(ProxyType.NONE, null, 0, null, null);
}
public static ProxyInfo forDefaultProxy()
{
return new ProxyInfo(ProxyType.NONE, null, 0, null, null);
}
public ProxyType getProxyType()
{
return proxyType;
}
public String getProxyAddress()
{
return proxyAddress;
}
public int getProxyPort()
{
return proxyPort;
}
public String getProxyUsername()
{
return proxyUsername;
}
public String getProxyPassword()
{
return proxyPassword;
}
public SocketFactory getSocketFactory()
{
if(proxyType == ProxyType.NONE)
{
return new DirectSocketFactory();
}
else if(proxyType == ProxyType.HTTP)
{
return new HTTPProxySocketFactory(this);
}
else if(proxyType == ProxyType.SOCKS4)
{
return new Socks4ProxySocketFactory(this);
}
else if(proxyType == ProxyType.SOCKS5)
{
return new Socks5ProxySocketFactory(this);
}
else
{
return null;
}
}
}

View file

@ -197,202 +197,3 @@ public class Socks4ProxySocketFactory
}
}
}
package org.jivesoftware.smack.proxy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
/**
* Socket factory for socks4 proxy
*
* @author Atul Aggarwal
*/
public class Socks4ProxySocketFactory
extends SocketFactory
{
private ProxyInfo proxy;
public Socks4ProxySocketFactory(ProxyInfo proxy)
{
this.proxy = proxy;
}
public Socket createSocket(String host, int port)
throws IOException, UnknownHostException
{
return socks4ProxifiedSocket(host,port);
}
public Socket createSocket(String host ,int port, InetAddress localHost,
int localPort)
throws IOException, UnknownHostException
{
return socks4ProxifiedSocket(host,port);
}
public Socket createSocket(InetAddress host, int port)
throws IOException
{
return socks4ProxifiedSocket(host.getHostAddress(),port);
}
public Socket createSocket( InetAddress address, int port,
InetAddress localAddress, int localPort)
throws IOException
{
return socks4ProxifiedSocket(address.getHostAddress(),port);
}
private Socket socks4ProxifiedSocket(String host, int port)
throws IOException
{
Socket socket = null;
InputStream in = null;
OutputStream out = null;
String proxy_host = proxy.getProxyAddress();
int proxy_port = proxy.getProxyPort();
String user = proxy.getProxyUsername();
String passwd = proxy.getProxyPassword();
try
{
socket=new Socket(proxy_host, proxy_port);
in=socket.getInputStream();
out=socket.getOutputStream();
socket.setTcpNoDelay(true);
byte[] buf=new byte[1024];
int index=0;
/*
1) CONNECT
The client connects to the SOCKS server and sends a CONNECT request when
it wants to establish a connection to an application server. The client
includes in the request packet the IP address and the port number of the
destination host, and userid, in the following format.
+----+----+----+----+----+----+----+----+----+----+....+----+
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
+----+----+----+----+----+----+----+----+----+----+....+----+
# of bytes: 1 1 2 4 variable 1
VN is the SOCKS protocol version number and should be 4. CD is the
SOCKS command code and should be 1 for CONNECT request. NULL is a byte
of all zero bits.
*/
index=0;
buf[index++]=4;
buf[index++]=1;
buf[index++]=(byte)(port>>>8);
buf[index++]=(byte)(port&0xff);
try
{
InetAddress addr=InetAddress.getByName(host);
byte[] byteAddress = addr.getAddress();
for (int i = 0; i < byteAddress.length; i++)
{
buf[index++]=byteAddress[i];
}
}
catch(UnknownHostException uhe)
{
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,
uhe.toString(), uhe);
}
if(user!=null)
{
System.arraycopy(user.getBytes(), 0, buf, index, user.length());
index+=user.length();
}
buf[index++]=0;
out.write(buf, 0, index);
/*
The SOCKS server checks to see whether such a request should be granted
based on any combination of source IP address, destination IP address,
destination port number, the userid, and information it may obtain by
consulting IDENT, cf. RFC 1413. If the request is granted, the SOCKS
server makes a connection to the specified port of the destination host.
A reply packet is sent to the client when this connection is established,
or when the request is rejected or the operation fails.
+----+----+----+----+----+----+----+----+
| VN | CD | DSTPORT | DSTIP |
+----+----+----+----+----+----+----+----+
# of bytes: 1 1 2 4
VN is the version of the reply code and should be 0. CD is the result
code with one of the following values:
90: request granted
91: request rejected or failed
92: request rejected becasue SOCKS server cannot connect to
identd on the client
93: request rejected because the client program and identd
report different user-ids
The remaining fields are ignored.
*/
int len=6;
int s=0;
while(s<len)
{
int i=in.read(buf, s, len-s);
if(i<=0)
{
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,
"stream is closed");
}
s+=i;
}
if(buf[0]!=0)
{
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,
"server returns VN "+buf[0]);
}
if(buf[1]!=90)
{
try
{
socket.close();
}
catch(Exception eee)
{
}
String message="ProxySOCKS4: server returns CD "+buf[1];
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,message);
}
byte[] temp = new byte[2];
in.read(temp, 0, 2);
return socket;
}
catch(RuntimeException e)
{
throw e;
}
catch(Exception e)
{
try
{
if(socket!=null)socket.close();
}
catch(Exception eee)
{
}
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4, e.toString());
}
}
}

View file

@ -356,361 +356,3 @@ public class Socks5ProxySocketFactory
}
}
}
package org.jivesoftware.smack.proxy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
/**
* Socket factory for Socks5 proxy
*
* @author Atul Aggarwal
*/
public class Socks5ProxySocketFactory
extends SocketFactory
{
private ProxyInfo proxy;
public Socks5ProxySocketFactory(ProxyInfo proxy)
{
this.proxy = proxy;
}
public Socket createSocket(String host, int port)
throws IOException, UnknownHostException
{
return socks5ProxifiedSocket(host,port);
}
public Socket createSocket(String host ,int port, InetAddress localHost,
int localPort)
throws IOException, UnknownHostException
{
return socks5ProxifiedSocket(host,port);
}
public Socket createSocket(InetAddress host, int port)
throws IOException
{
return socks5ProxifiedSocket(host.getHostAddress(),port);
}
public Socket createSocket( InetAddress address, int port,
InetAddress localAddress, int localPort)
throws IOException
{
return socks5ProxifiedSocket(address.getHostAddress(),port);
}
private Socket socks5ProxifiedSocket(String host, int port)
throws IOException
{
Socket socket = null;
InputStream in = null;
OutputStream out = null;
String proxy_host = proxy.getProxyAddress();
int proxy_port = proxy.getProxyPort();
String user = proxy.getProxyUsername();
String passwd = proxy.getProxyPassword();
try
{
socket=new Socket(proxy_host, proxy_port);
in=socket.getInputStream();
out=socket.getOutputStream();
socket.setTcpNoDelay(true);
byte[] buf=new byte[1024];
int index=0;
/*
+----+----------+----------+
|VER | NMETHODS | METHODS |
+----+----------+----------+
| 1 | 1 | 1 to 255 |
+----+----------+----------+
The VER field is set to X'05' for this version of the protocol. The
NMETHODS field contains the number of method identifier octets that
appear in the METHODS field.
The values currently defined for METHOD are:
o X'00' NO AUTHENTICATION REQUIRED
o X'01' GSSAPI
o X'02' USERNAME/PASSWORD
o X'03' to X'7F' IANA ASSIGNED
o X'80' to X'FE' RESERVED FOR PRIVATE METHODS
o X'FF' NO ACCEPTABLE METHODS
*/
buf[index++]=5;
buf[index++]=2;
buf[index++]=0; // NO AUTHENTICATION REQUIRED
buf[index++]=2; // USERNAME/PASSWORD
out.write(buf, 0, index);
/*
The server selects from one of the methods given in METHODS, and
sends a METHOD selection message:
+----+--------+
|VER | METHOD |
+----+--------+
| 1 | 1 |
+----+--------+
*/
//in.read(buf, 0, 2);
fill(in, buf, 2);
boolean check=false;
switch((buf[1])&0xff)
{
case 0: // NO AUTHENTICATION REQUIRED
check=true;
break;
case 2: // USERNAME/PASSWORD
if(user==null || passwd==null)
{
break;
}
/*
Once the SOCKS V5 server has started, and the client has selected the
Username/Password Authentication protocol, the Username/Password
subnegotiation begins. This begins with the client producing a
Username/Password request:
+----+------+----------+------+----------+
|VER | ULEN | UNAME | PLEN | PASSWD |
+----+------+----------+------+----------+
| 1 | 1 | 1 to 255 | 1 | 1 to 255 |
+----+------+----------+------+----------+
The VER field contains the current version of the subnegotiation,
which is X'01'. The ULEN field contains the length of the UNAME field
that follows. The UNAME field contains the username as known to the
source operating system. The PLEN field contains the length of the
PASSWD field that follows. The PASSWD field contains the password
association with the given UNAME.
*/
index=0;
buf[index++]=1;
buf[index++]=(byte)(user.length());
System.arraycopy(user.getBytes(), 0, buf, index,
user.length());
index+=user.length();
buf[index++]=(byte)(passwd.length());
System.arraycopy(passwd.getBytes(), 0, buf, index,
passwd.length());
index+=passwd.length();
out.write(buf, 0, index);
/*
The server verifies the supplied UNAME and PASSWD, and sends the
following response:
+----+--------+
|VER | STATUS |
+----+--------+
| 1 | 1 |
+----+--------+
A STATUS field of X'00' indicates success. If the server returns a
`failure' (STATUS value other than X'00') status, it MUST close the
connection.
*/
//in.read(buf, 0, 2);
fill(in, buf, 2);
if(buf[1]==0)
{
check=true;
}
break;
default:
}
if(!check)
{
try
{
socket.close();
}
catch(Exception eee)
{
}
throw new ProxyException(ProxyInfo.ProxyType.SOCKS5,
"fail in SOCKS5 proxy");
}
/*
The SOCKS request is formed as follows:
+----+-----+-------+------+----------+----------+
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
Where:
o VER protocol version: X'05'
o CMD
o CONNECT X'01'
o BIND X'02'
o UDP ASSOCIATE X'03'
o RSV RESERVED
o ATYP address type of following address
o IP V4 address: X'01'
o DOMAINNAME: X'03'
o IP V6 address: X'04'
o DST.ADDR desired destination address
o DST.PORT desired destination port in network octet
order
*/
index=0;
buf[index++]=5;
buf[index++]=1; // CONNECT
buf[index++]=0;
byte[] hostb=host.getBytes();
int len=hostb.length;
buf[index++]=3; // DOMAINNAME
buf[index++]=(byte)(len);
System.arraycopy(hostb, 0, buf, index, len);
index+=len;
buf[index++]=(byte)(port>>>8);
buf[index++]=(byte)(port&0xff);
out.write(buf, 0, index);
/*
The SOCKS request information is sent by the client as soon as it has
established a connection to the SOCKS server, and completed the
authentication negotiations. The server evaluates the request, and
returns a reply formed as follows:
+----+-----+-------+------+----------+----------+
|VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
Where:
o VER protocol version: X'05'
o REP Reply field:
o X'00' succeeded
o X'01' general SOCKS server failure
o X'02' connection not allowed by ruleset
o X'03' Network unreachable
o X'04' Host unreachable
o X'05' Connection refused
o X'06' TTL expired
o X'07' Command not supported
o X'08' Address type not supported
o X'09' to X'FF' unassigned
o RSV RESERVED
o ATYP address type of following address
o IP V4 address: X'01'
o DOMAINNAME: X'03'
o IP V6 address: X'04'
o BND.ADDR server bound address
o BND.PORT server bound port in network octet order
*/
//in.read(buf, 0, 4);
fill(in, buf, 4);
if(buf[1]!=0)
{
try
{
socket.close();
}
catch(Exception eee)
{
}
throw new ProxyException(ProxyInfo.ProxyType.SOCKS5,
"server returns "+buf[1]);
}
switch(buf[3]&0xff)
{
case 1:
//in.read(buf, 0, 6);
fill(in, buf, 6);
break;
case 3:
//in.read(buf, 0, 1);
fill(in, buf, 1);
//in.read(buf, 0, buf[0]+2);
fill(in, buf, (buf[0]&0xff)+2);
break;
case 4:
//in.read(buf, 0, 18);
fill(in, buf, 18);
break;
default:
}
return socket;
}
catch(RuntimeException e)
{
throw e;
}
catch(Exception e)
{
try
{
if(socket!=null)
{
socket.close();
}
}
catch(Exception eee)
{
}
String message="ProxySOCKS5: "+e.toString();
if(e instanceof Throwable)
{
throw new ProxyException(ProxyInfo.ProxyType.SOCKS5,message,
(Throwable)e);
}
throw new IOException(message);
}
}
private void fill(InputStream in, byte[] buf, int len)
throws IOException
{
int s=0;
while(s<len)
{
int i=in.read(buf, s, len-s);
if(i<=0)
{
throw new ProxyException(ProxyInfo.ProxyType.SOCKS5, "stream " +
"is closed");
}
s+=i;
}
}
}

View file

@ -297,7 +297,7 @@ public class AgentSession {
* <p/>
* <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
* (equivalent to Presence.Mode.CHAT).
* <li>Presence.Mode.DO_NOT_DISTURB - the agent is busy and should not be disturbed.
* <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
* However, special case, or extreme urgency chats may still be offered to the agent.
* <li>Presence.Mode.AWAY -- the agent is not available and should not
* have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
@ -323,7 +323,7 @@ public class AgentSession {
* <p/>
* <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
* (equivalent to Presence.Mode.CHAT).
* <li>Presence.Mode.DO_NOT_DISTURB - the agent is busy and should not be disturbed.
* <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
* However, special case, or extreme urgency chats may still be offered to the agent.
* <li>Presence.Mode.AWAY -- the agent is not available and should not
* have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
@ -386,7 +386,7 @@ public class AgentSession {
* <p/>
* <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
* (equivalent to Presence.Mode.CHAT).
* <li>Presence.Mode.DO_NOT_DISTURB - the agent is busy and should not be disturbed.
* <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
* However, special case, or extreme urgency chats may still be offered to the agent.
* <li>Presence.Mode.AWAY -- the agent is not available and should not
* have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>