package org.simplejavamail.mailer.internal.socks.socks5client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
public class Socks5 {
private static final int SOCKS_DEFAULT_PORT = 1080;
public static final byte AUTHENTICATION_SUCCEEDED = 0x00;
private Socks5 chainProxy;
private ProxyCredentials credentials = new ProxyCredentials();
private InetAddress inetAddress;
private int port = SOCKS_DEFAULT_PORT;
private Socket proxySocket;
private SocksAuthenticationHelper socksAuthenticationHelper = new SocksAuthenticationHelper();
private boolean alwaysResolveAddressLocally = false;
public Socks5(final InetSocketAddress socketAddress, final String username, final String password) {
this(socketAddress);
setCredentials(new ProxyCredentials(username, password));
}
public Socks5(final String host, final int port)
throws UnknownHostException {
this(InetAddress.getByName(host), port);
}
Socks5(final InetAddress inetAddress, final int port) {
this(new InetSocketAddress(inetAddress, port));
}
public Socks5(final InetSocketAddress socketAddress) {
this(null, socketAddress);
}
@SuppressWarnings("SameParameterValue")
private Socks5(final Socks5 chainProxy, final InetSocketAddress socketAddress) {
inetAddress = socketAddress.getAddress();
port = socketAddress.getPort();
this.setChainProxy(chainProxy);
}
public Socks5(final String host, final int port, final ProxyCredentials credentials)
throws UnknownHostException {
this.inetAddress = InetAddress.getByName(host);
this.port = port;
this.credentials = credentials;
}
public void buildConnection()
throws IOException {
if (inetAddress == null) {
throw new IllegalArgumentException("Please set inetAddress before calling buildConnection.");
}
if (proxySocket == null) {
proxySocket = createProxySocket(inetAddress, port);
} else if (!proxySocket.isConnected()) {
proxySocket.connect(new InetSocketAddress(inetAddress, port));
}
if (SocksAuthenticationHelper.shouldAuthenticate(proxySocket)) {
SocksAuthenticationHelper.performUserPasswordAuthentication(this);
}
}
public void requestConnect(final String host, final int port)
throws IOException {
if (!alwaysResolveAddressLocally) {
// resolve address in SOCKS server
SocksCommandSender.send(proxySocket, host, port);
} else {
// resolve address in local.
final InetAddress address = InetAddress.getByName(host);
SocksCommandSender.send(proxySocket, address, port);
}
}
public void requestConnect(final InetAddress address, final int port)
throws IOException {
SocksCommandSender.send(proxySocket, address, port);
}
public void requestConnect(final SocketAddress address)
throws IOException {
SocksCommandSender.send(proxySocket, address);
}
public int getPort() {
return port;
}
Socks5 setPort(final int port) {
this.port = port;
return this;
}
public Socket getProxySocket() {
return proxySocket;
}
public void setProxySocket(final Socket proxySocket) {
this.proxySocket = proxySocket;
}
public InputStream getInputStream()
throws IOException {
return proxySocket.getInputStream();
}
public OutputStream getOutputStream()
throws IOException {
return proxySocket.getOutputStream();
}
public ProxyCredentials getCredentials() {
return credentials;
}
public Socks5 setCredentials(final ProxyCredentials credentials) {
this.credentials = credentials;
return this;
}
SocksAuthenticationHelper getSocksAuthenticationHelper() {
return socksAuthenticationHelper;
}
Socks5 setSocksAuthenticationHelper(final SocksAuthenticationHelper requester) {
this.socksAuthenticationHelper = requester;
return this;
}
public Socks5 copy() {
final Socks5 socks5 = new Socks5(inetAddress, port);
socks5.setAlwaysResolveAddressLocally(alwaysResolveAddressLocally).setCredentials(credentials)
.setSocksAuthenticationHelper(socksAuthenticationHelper).setChainProxy(chainProxy);
return socks5;
}
public Socks5 getChainProxy() {
return chainProxy;
}
Socks5 setChainProxy(final Socks5 chainProxy) {
this.chainProxy = chainProxy;
return this;
}
public InetAddress getInetAddress() {
return inetAddress;
}
Socks5 setInetAddress(final InetAddress inetAddress) {
this.inetAddress = inetAddress;
return this;
}
@Override
public String toString() {
final StringBuilder stringBuffer = new StringBuilder("[SOCKS5:");
stringBuffer.append(new InetSocketAddress(inetAddress, port)).append("]");
if (getChainProxy() != null) {
return stringBuffer.append(" --> ").append(getChainProxy()).toString();
}
return stringBuffer.toString();
}
Socket createProxySocket(final InetAddress address, final int port)
throws IOException {
return new Socket(address, port);
}
public Socket createProxySocket()
throws IOException {
return new Socket();
}
boolean isAlwaysResolveAddressLocally() {
return alwaysResolveAddressLocally;
}
Socks5 setAlwaysResolveAddressLocally(final boolean alwaysResolveAddressLocally) {
this.alwaysResolveAddressLocally = alwaysResolveAddressLocally;
return this;
}
}