/**
* Copyright 2003-2016 SSHTOOLS Limited. All Rights Reserved.
*
* For product documentation visit https://www.sshtools.com/
*
* This file is part of J2SSH Maverick.
*
* J2SSH Maverick is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* J2SSH Maverick is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with J2SSH Maverick. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* This file is originally from the http://sourceforge.net/projects/jsocks/
* released under the LGPL.
*/
package socks;
import java.awt.*;
import java.awt.event.*;
/**
* Socks configuration dialog.<br>
* Class which provides GUI means of getting Proxy configuration from the user.
*/
public class SocksDialog extends Dialog implements WindowListener,
ItemListener, ActionListener, Runnable {
private static final long serialVersionUID = 2090387761280549764L;
// GUI components
TextField host_text, port_text, user_text, password_text, direct_text;
Button add_button, remove_button, cancel_button, ok_button, dismiss_button;
List direct_list;
Checkbox socks4radio, socks5radio, none_check, up_check, gssapi_check;
Dialog warning_dialog;
Label warning_label;
String host, user, password;
int port;
Thread net_thread = null;
// CheckboxGroups
CheckboxGroup socks_group = new CheckboxGroup();
Proxy proxy;
InetRange ir;
final static int COMMAND_MODE = 0;
final static int OK_MODE = 1;
int mode;
/**
* Wether to resolve addresses in separate thread.
* <p>
* Default value is true, however on some JVMs, namely one from the
* Microsoft, it doesn't want to work properly, separate thread can't close
* the dialog opened in GUI thread, and everuthing else is then crashes.
* <p>
* When setting this variable to false, SocksDialog will block while trying
* to look up proxy host, and if this takes considerable amount of time it
* might be annoying to user.
*/
public static boolean useThreads = true;
// Constructors
// //////////////////////////////////
/**
* Creates SOCKS configuration dialog.<br>
* Uses default initialisation:<br>
* Proxy host: socks-proxy <br>
* Proxy port: 1080 <br>
* Version: 5<br>
*/
public SocksDialog(Frame parent) {
this(parent, null);
}
/**
* Creates SOCKS configuration dialog and initialises it to given proxy.
*/
public SocksDialog(Frame parent, Proxy init_proxy) {
super(parent, "Proxy Configuration", true);
warning_dialog = new Dialog(parent, "Warning", true);
guiInit();
setResizable(false);
addWindowListener(this);
Component[] comps = getComponents();
for (int i = 0; i < comps.length; ++i) {
if (comps[i] instanceof Button)
((Button) comps[i]).addActionListener(this);
else if (comps[i] instanceof TextField)
((TextField) comps[i]).addActionListener(this);
else if (comps[i] instanceof Checkbox) {
((Checkbox) comps[i]).addItemListener(this);
}
}
proxy = init_proxy;
if (proxy != null)
doInit(proxy);
else
ir = new InetRange();
dismiss_button.addActionListener(this);
warning_dialog.addWindowListener(this);
}
// Public Methods
// //////////////
/**
* Displays SOCKS configuartion dialog.
* <p>
* Returns initialised proxy object, or null if user cancels dialog by
* either pressing Cancel or closing the dialog window.
*/
@SuppressWarnings("deprecation")
public Proxy getProxy() {
mode = COMMAND_MODE;
pack();
show();
return proxy;
}
/**
* Initialises dialog to given proxy and displays SOCKS configuartion
* dialog.
* <p>
* Returns initialised proxy object, or null if user cancels dialog by
* either pressing Cancel or closing the dialog window.
*/
@SuppressWarnings("deprecation")
public Proxy getProxy(Proxy p) {
if (p != null) {
doInit(p);
}
mode = COMMAND_MODE;
pack();
show();
return proxy;
}
// WindowListener Interface
// ///////////////////////////////
public void windowActivated(java.awt.event.WindowEvent e) {
}
public void windowDeactivated(java.awt.event.WindowEvent e) {
}
public void windowOpened(java.awt.event.WindowEvent e) {
}
public void windowClosing(java.awt.event.WindowEvent e) {
Window source = e.getWindow();
if (source == this) {
onCancel();
} else if (source == warning_dialog) {
onDismiss();
}
}
public void windowClosed(java.awt.event.WindowEvent e) {
}
public void windowIconified(java.awt.event.WindowEvent e) {
}
public void windowDeiconified(java.awt.event.WindowEvent e) {
}
// ActionListener interface
// /////////////////////////
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();
if (source == cancel_button)
onCancel();
else if (source == add_button || source == direct_text)
onAdd();
else if (source == remove_button)
onRemove();
else if (source == dismiss_button)
onDismiss();
else if (source == ok_button || source instanceof TextField)
onOK();
}
// ItemListener interface
// //////////////////////
public void itemStateChanged(ItemEvent ie) {
Object source = ie.getSource();
// System.out.println("ItemEvent:"+source);
if (source == socks5radio || source == socks4radio)
onSocksChange();
else if (source == up_check)
onUPChange();
}
// Runnable interface
// //////////////////
/**
* Resolves proxy address in other thread, to avoid annoying blocking in GUI
* thread.
*/
public void run() {
if (!initProxy()) {
// Check if we have been aborted
if (mode != OK_MODE)
return;
if (net_thread != Thread.currentThread())
return;
mode = COMMAND_MODE;
warning_label.setText("Look up failed.");
warning_label.invalidate();
return;
}
// System.out.println("Done!");
while (!warning_dialog.isShowing())
; /* do nothing */
;
warning_dialog.dispose();
// dispose(); //End Dialog
}
// Private Methods
// /////////////////
private void onOK() {
host = host_text.getText().trim();
user = user_text.getText();
password = password_text.getText();
if (host.length() == 0) {
warn("Proxy host is not set!");
return;
}
if (socks_group.getSelectedCheckbox() == socks4radio) {
if (user.length() == 0) {
warn("User name is not set");
return;
}
} else {
if (up_check.getState()) {
if (user.length() == 0) {
warn("User name is not set.");
return;
}
if (password.length() == 0) {
warn("Password is not set.");
return;
}
} else if (!none_check.getState()) {
warn("Please select at least one Authentication Method.");
return;
}
}
try {
port = Integer.parseInt(port_text.getText());
} catch (NumberFormatException nfe) {
warn("Proxy port is invalid!");
return;
}
mode = OK_MODE;
if (useThreads) {
net_thread = new Thread(this);
net_thread.start();
info("Looking up host: " + host);
// System.out.println("Info returned.");
} else if (!initProxy()) {
warn("Proxy host is invalid.");
mode = COMMAND_MODE;
}
if (mode == OK_MODE)
dispose();
}
private void onCancel() {
// System.out.println("Cancel");
proxy = null;
dispose();
}
private void onAdd() {
String s = direct_text.getText();
s.trim();
if (s.length() == 0)
return;
// Check for Duplicate
String[] direct_hosts = direct_list.getItems();
for (int i = 0; i < direct_hosts.length; ++i)
if (direct_hosts[i].equals(s))
return;
direct_list.add(s);
ir.add(s);
}
private void onRemove() {
int index = direct_list.getSelectedIndex();
if (index < 0)
return;
ir.remove(direct_list.getItem(index));
direct_list.remove(index);
direct_list.select(index);
}
private void onSocksChange() {
Object selected = socks_group.getSelectedCheckbox();
if (selected == socks4radio) {
user_text.setEnabled(true);
password_text.setEnabled(false);
none_check.setEnabled(false);
up_check.setEnabled(false);
} else {
if (up_check.getState()) {
user_text.setEnabled(true);
password_text.setEnabled(true);
} else {
user_text.setEnabled(false);
password_text.setEnabled(false);
}
none_check.setEnabled(true);
up_check.setEnabled(true);
}
// System.out.println("onSocksChange:"+selected);
}
private void onUPChange() {
// System.out.println("onUPChange");
if (up_check.getState()) {
user_text.setEnabled(true);
password_text.setEnabled(true);
} else {
user_text.setEnabled(false);
password_text.setEnabled(false);
}
}
private void onDismiss() {
warning_dialog.dispose();
if (mode == OK_MODE) {
mode = COMMAND_MODE;
if (net_thread != null)
net_thread.interrupt();
}
}
private void doInit(Proxy p) {
if (p.version == 5) {
socks_group.setSelectedCheckbox(socks5radio);
onSocksChange();
if (((Socks5Proxy) p).getAuthenticationMethod(0) != null)
none_check.setState(true);
UserPasswordAuthentication auth = (UserPasswordAuthentication) ((Socks5Proxy) p)
.getAuthenticationMethod(2);
if (auth != null) {
user_text.setText(auth.getUser());
password_text.setText(auth.getPassword());
up_check.setState(true);
onUPChange();
}
} else {
socks_group.setSelectedCheckbox(socks4radio);
onSocksChange();
user_text.setText(((Socks4Proxy) p).user);
}
ir = (InetRange) (p.directHosts.clone());
String[] direct_hosts = ir.getAll();
direct_list.removeAll();
for (int i = 0; i < direct_hosts.length; ++i)
direct_list.add(direct_hosts[i]);
host_text.setText(p.proxyIP.getHostName());
port_text.setText("" + p.proxyPort);
}
private boolean initProxy() {
try {
if (socks_group.getSelectedCheckbox() == socks5radio) {
proxy = new Socks5Proxy(host, port);
if (up_check.getState())
((Socks5Proxy) proxy).setAuthenticationMethod(2,
new UserPasswordAuthentication(user, password));
if (!none_check.getState())
((Socks5Proxy) proxy).setAuthenticationMethod(0, null);
} else
proxy = new Socks4Proxy(host, port, user);
} catch (java.net.UnknownHostException uhe) {
return false;
}
proxy.directHosts = ir;
return true;
}
private void info(String s) {
msgBox("Info", s);
}
private void warn(String s) {
msgBox("Warning", s);
}
@SuppressWarnings("deprecation")
private void msgBox(String title, String message) {
warning_label.setText(message);
warning_label.invalidate();
warning_dialog.setTitle(title);
warning_dialog.pack();
warning_dialog.show();
}
/*
* ======================================================================
* Form: Table: +---+-------+---+---+ | | | | | +---+-------+---+---+ | | |
* +---+-------+-------+ | | | | +---+-------+-------+ | | | |
* +---+-------+-------+ | | | +-----------+-------+ | | | | +---+---+ | | |
* | +-----------+---+---+ | | | | +---+---+---+---+---+ | | | | | |
* +---+---+---+---+---+
*/
void guiInit() {
// Some default names used
Label label;
Container container;
Font font;
GridBagConstraints c = new GridBagConstraints();
font = new Font("Dialog", Font.PLAIN, 12);
container = this;
// container = new Panel();
container.setLayout(new GridBagLayout());
container.setFont(font);
container.setBackground(SystemColor.menu);
c.insets = new Insets(3, 3, 3, 3);
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHEAST;
label = new Label("Host:");
container.add(label, c);
c.gridx = 1;
c.gridy = 0;
c.gridwidth = 2;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
host_text = new TextField("socks-proxy", 15);
container.add(host_text, c);
c.gridx = 3;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHEAST;
label = new Label("Port:");
container.add(label, c);
c.gridx = 4;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
port_text = new TextField("1080", 5);
container.add(port_text, c);
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 3;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTH;
socks4radio = new Checkbox("Socks4", socks_group, false);
// 1.0 compatible code
// socks4radio = new Checkbox("Socks4",false);
// socks4radio.setCheckboxGroup(socks_group);
socks4radio.setFont(new Font(font.getName(), Font.BOLD, 14));
container.add(socks4radio, c);
c.gridx = 3;
c.gridy = 1;
c.gridwidth = 2;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTH;
socks5radio = new Checkbox("Socks5", socks_group, true);
// 1.0 compatible code
// socks5radio = new Checkbox("Socks5",true);
// socks5radio.setCheckboxGroup(socks_group);
socks5radio.setFont(new Font(font.getName(), Font.BOLD, 14));
container.add(socks5radio, c);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.EAST;
label = new Label("User Id:");
container.add(label, c);
c.gridx = 1;
c.gridy = 2;
c.gridwidth = 2;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
user_text = new TextField("", 15);
user_text.setEnabled(false);
container.add(user_text, c);
c.gridx = 3;
c.gridy = 2;
c.gridwidth = 2;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTH;
label = new Label("Authentication");
label.setFont(new Font(font.getName(), Font.BOLD, 14));
container.add(label, c);
c.gridx = 0;
c.gridy = 3;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.EAST;
label = new Label("Password:");
container.add(label, c);
c.gridx = 1;
c.gridy = 3;
c.gridwidth = 2;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
password_text = new TextField("", 15);
password_text.setEchoChar('*');
password_text.setEnabled(false);
// password_text.setEchoCharacter('*');//1.0
container.add(password_text, c);
c.gridx = 3;
c.gridy = 3;
c.gridwidth = 2;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
none_check = new Checkbox("None", true);
container.add(none_check, c);
c.gridx = 0;
c.gridy = 4;
c.gridwidth = 3;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTH;
label = new Label("Direct Hosts");
label.setFont(new Font(font.getName(), Font.BOLD, 14));
container.add(label, c);
c.gridx = 3;
c.gridy = 4;
c.gridwidth = 2;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
up_check = new Checkbox("User/Password", false);
container.add(up_check, c);
c.gridx = 0;
c.gridy = 5;
c.gridwidth = 3;
c.gridheight = 2;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
direct_list = new List(3);
container.add(direct_list, c);
c.gridx = 3;
c.gridy = 5;
c.gridwidth = 2;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
gssapi_check = new Checkbox("GSSAPI", false);
gssapi_check.setEnabled(false);
container.add(gssapi_check, c);
c.gridx = 0;
c.gridy = 7;
c.gridwidth = 3;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
direct_text = new TextField("", 25);
container.add(direct_text, c);
c.gridx = 3;
c.gridy = 7;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTH;
add_button = new Button("Add");
container.add(add_button, c);
c.gridx = 3;
c.gridy = 6;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTH;
remove_button = new Button("Remove");
container.add(remove_button, c);
c.gridx = 1;
c.gridy = 8;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTH;
cancel_button = new Button("Cancel");
container.add(cancel_button, c);
c.gridx = 0;
c.gridy = 8;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
ok_button = new Button("OK");
container.add(ok_button, c);
// up_check.setEnabled(false);
// Warning Dialog
dismiss_button = new Button("Dismiss");
warning_label = new Label("", Label.CENTER);
warning_label.setFont(new Font("Dialog", Font.BOLD, 15));
Panel p = new Panel();
p.add(dismiss_button);
warning_dialog.add(p, BorderLayout.SOUTH);
warning_dialog.add(warning_label, BorderLayout.CENTER);
warning_dialog.setResizable(false);
}// end guiInit
/*
* // Main //////////////////////////////////// public static void
* main(String[] args) throws Exception{ Frame f = new
* Frame("Test for SocksDialog"); f.add("Center", new
* Label("Fill the Dialog")); SocksDialog socksdialog = new SocksDialog(f);
* f.pack(); f.show(); f.addWindowListener(socksdialog); Proxy p =
* socksdialog.getProxy(); System.out.println("Selected: "+p); }
*/
}// end class