package com.runjva.sourceforge.jsocks.protocol;
import java.awt.*;
import java.awt.event.*;
/**
* Socks configuration dialog.<br>
* Class which provides GUI means of getting Proxy configuration from the user.
*/
// FIXME: Only used by SocksEcho class
public class SocksDialog extends Dialog implements WindowListener,
ItemListener, ActionListener, Runnable {
/**
*
*/
private static final long serialVersionUID = 1L;
// 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();
SocksProxyBase 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, SocksProxyBase init_proxy) {
super(parent, "Proxy Configuration", true);
warning_dialog = new Dialog(parent, "Warning", true);
guiInit();
setResizable(false);
addWindowListener(this);
final 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.
*/
public SocksProxyBase getProxy() {
mode = COMMAND_MODE;
pack();
setVisible(true);
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.
*/
public SocksProxyBase getProxy(SocksProxyBase p) {
if (p != null) {
doInit(p);
}
mode = COMMAND_MODE;
pack();
setVisible(true);
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) {
final 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) {
final 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) {
final 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 (final 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() {
final String s = direct_text.getText();
s.trim();
if (s.length() == 0) {
return;
}
// Check for Duplicate
final 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() {
final 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() {
final 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(SocksProxyBase p) {
if (p.version == 5) {
socks_group.setSelectedCheckbox(socks5radio);
onSocksChange();
if (((Socks5Proxy) p).getAuthenticationMethod(0) != null) {
none_check.setState(true);
}
final 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());
final 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 (final 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);
}
private void msgBox(String title, String message) {
warning_label.setText(message);
warning_label.invalidate();
warning_dialog.setTitle(title);
warning_dialog.pack();
warning_dialog.setVisible(true);
}
/*
* ======================================================================
* Form: Table:
*/
// +---+-------+---+---+
// |...|.......|...|...|
// +---+-------+---+---+
// |...........|.......|
// +---+-------+-------+
// |...|.......|.......|
// +---+-------+-------+
// |...|.......|.......|
// +---+-------+-------+
// |...........|.......|
// +-----------+-------+
// |...........|.......|
// |...........+---+---+
// |...........|...|...|
// +-----------+---+---+
// |...........|...|...|
// +---+---+---+---+---+
// |...|...|...|...|...|
// +---+---+---+---+---+
//
void guiInit() {
// Some default names used
Label label;
Container container;
Font font;
final 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));
final 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