From f7ed1f6128fc3d9f576b606a9e5cd233b628473d Mon Sep 17 00:00:00 2001 From: Brian Hinz Date: Fri, 10 Jun 2011 00:44:05 +0000 Subject: [PATCH] initial support for ClientRedirect and VeNCrypt sub-type Ident in java viewer git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4489 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- java/src/com/tigervnc/rfb/CConnection.java | 11 --- java/src/com/tigervnc/rfb/CMsgHandler.java | 3 + java/src/com/tigervnc/rfb/CMsgReaderV3.java | 16 +++++ java/src/com/tigervnc/rfb/CMsgWriter.java | 2 + java/src/com/tigervnc/rfb/CSecurityIdent.java | 58 +++++++++++++++ java/src/com/tigervnc/rfb/ConnParams.java | 5 +- java/src/com/tigervnc/rfb/Encodings.java | 1 + java/src/com/tigervnc/rfb/Security.java | 12 +++- java/src/com/tigervnc/rfb/SecurityClient.java | 18 +++-- java/src/com/tigervnc/vncviewer/CConn.java | 70 ++++++++++++++++--- .../com/tigervnc/vncviewer/OptionsDialog.java | 12 ++-- 11 files changed, 172 insertions(+), 36 deletions(-) create mode 100644 java/src/com/tigervnc/rfb/CSecurityIdent.java diff --git a/java/src/com/tigervnc/rfb/CConnection.java b/java/src/com/tigervnc/rfb/CConnection.java index 5acae52b..2a7ecfcc 100644 --- a/java/src/com/tigervnc/rfb/CConnection.java +++ b/java/src/com/tigervnc/rfb/CConnection.java @@ -256,17 +256,6 @@ abstract public class CConnection extends CMsgHandler { nSecTypes = 0; } - // addSecType() should be called once for each security type which the - // client supports. The order in which they're added is such that the - // first one is most preferred. -/* - public void addSecType(int secType) { - if (nSecTypes == maxSecTypes) - throw new Exception("too many security types"); - secTypes.set(nSecTypes++,secType); - } -*/ - // setShared sets the value of the shared flag which will be sent to the // server upon initialisation. public void setShared(boolean s) { shared = s; } diff --git a/java/src/com/tigervnc/rfb/CMsgHandler.java b/java/src/com/tigervnc/rfb/CMsgHandler.java index 11d26815..81fd2a1b 100644 --- a/java/src/com/tigervnc/rfb/CMsgHandler.java +++ b/java/src/com/tigervnc/rfb/CMsgHandler.java @@ -61,6 +61,9 @@ public class CMsgHandler { cp.setName(name); } + public void clientRedirect(int port, String host, + String x509subject) {} + public void setCursor(int width, int height, Point hotspot, int[] data, byte[] mask) {} public void serverInit() {} diff --git a/java/src/com/tigervnc/rfb/CMsgReaderV3.java b/java/src/com/tigervnc/rfb/CMsgReaderV3.java index 308d60d1..6d9e254b 100644 --- a/java/src/com/tigervnc/rfb/CMsgReaderV3.java +++ b/java/src/com/tigervnc/rfb/CMsgReaderV3.java @@ -80,6 +80,9 @@ public class CMsgReaderV3 extends CMsgReader { case Encodings.pseudoEncodingLastRect: nUpdateRectsLeft = 1; // this rectangle is the last one break; + case Encodings.pseudoEncodingClientRedirect: + readClientRedirect(x, y, w, h); + break; default: readRect(new Rect(x, y, x+w, y+h), encoding); break; @@ -133,6 +136,19 @@ public class CMsgReaderV3 extends CMsgReader { handler.setExtendedDesktopSize(x, y, w, h, layout); } + void readClientRedirect(int x, int y, int w, int h) + { + int port = is.readU16(); + String host = is.readString(); + String x509subject = is.readString(); + + if (x != 0 || y != 0 || w != 0 || h != 0) { + vlog.error("Ignoring ClientRedirect rect with non-zero position/size"); + } else { + handler.clientRedirect(port, host, x509subject); + } + } + int nUpdateRectsLeft; static LogWriter vlog = new LogWriter("CMsgReaderV3"); diff --git a/java/src/com/tigervnc/rfb/CMsgWriter.java b/java/src/com/tigervnc/rfb/CMsgWriter.java index 7abbc09c..7cafddde 100644 --- a/java/src/com/tigervnc/rfb/CMsgWriter.java +++ b/java/src/com/tigervnc/rfb/CMsgWriter.java @@ -57,6 +57,8 @@ abstract public class CMsgWriter { encodings[nEncodings++] = Encodings.pseudoEncodingExtendedDesktopSize; if (cp.supportsDesktopRename) encodings[nEncodings++] = Encodings.pseudoEncodingDesktopName; + if (cp.supportsClientRedirect) + encodings[nEncodings++] = Encodings.pseudoEncodingClientRedirect; if (Decoder.supported(preferredEncoding)) { encodings[nEncodings++] = preferredEncoding; } diff --git a/java/src/com/tigervnc/rfb/CSecurityIdent.java b/java/src/com/tigervnc/rfb/CSecurityIdent.java new file mode 100644 index 00000000..6523e411 --- /dev/null +++ b/java/src/com/tigervnc/rfb/CSecurityIdent.java @@ -0,0 +1,58 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software 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 this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +package com.tigervnc.rfb; + +import java.io.IOException; + +import com.tigervnc.rdr.*; +import com.tigervnc.vncviewer.*; + +public class CSecurityIdent extends CSecurity { + + public CSecurityIdent() { } + + public boolean processMsg(CConnection cc) { + InStream is = cc.getInStream(); + OutStream os = cc.getOutStream(); + + StringBuffer username = new StringBuffer(); + + CConn.upg.getUserPasswd(username, null); + + // Return the response to the server + os.writeU32(username.length()); + try { + byte[] utf8str = username.toString().getBytes("UTF8"); + os.writeBytes(utf8str, 0, username.length()); + } catch(java.io.UnsupportedEncodingException e) { + e.printStackTrace(); + } + os.flush(); + return true; + } + + public int getType() { return Security.secTypeIdent; } + + java.net.Socket sock; + UserPasswdGetter upg; + + static LogWriter vlog = new LogWriter("Ident"); + public String description() { return "No Encryption"; } + +} diff --git a/java/src/com/tigervnc/rfb/ConnParams.java b/java/src/com/tigervnc/rfb/ConnParams.java index 16c6ff48..c5e50d51 100644 --- a/java/src/com/tigervnc/rfb/ConnParams.java +++ b/java/src/com/tigervnc/rfb/ConnParams.java @@ -29,7 +29,7 @@ public class ConnParams { supportsLocalCursor = false; supportsLocalXCursor = false; supportsDesktopResize = false; supportsExtendedDesktopSize = false; supportsDesktopRename = false; supportsLastRect = false; - supportsSetDesktopSize = false; + supportsSetDesktopSize = false; supportsClientRedirect = false; customCompressLevel = false; compressLevel = 6; noJpeg = false; qualityLevel = -1; name_ = null; nEncodings_ = 0; encodings_ = null; @@ -134,6 +134,8 @@ public class ConnParams { supportsLocalCursor = true; else if (encodings[i] == Encodings.pseudoEncodingDesktopSize) supportsDesktopResize = true; + else if (encodings[i] == Encodings.pseudoEncodingClientRedirect) + supportsClientRedirect = true; else if (encodings[i] >= Encodings.pseudoEncodingCompressLevel0 && encodings[i] <= Encodings.pseudoEncodingCompressLevel9) { customCompressLevel = true; @@ -154,6 +156,7 @@ public class ConnParams { public boolean supportsDesktopResize; public boolean supportsExtendedDesktopSize; public boolean supportsDesktopRename; + public boolean supportsClientRedirect; public boolean supportsLastRect; public boolean supportsSetDesktopSize; diff --git a/java/src/com/tigervnc/rfb/Encodings.java b/java/src/com/tigervnc/rfb/Encodings.java index 215178dc..493d5488 100644 --- a/java/src/com/tigervnc/rfb/Encodings.java +++ b/java/src/com/tigervnc/rfb/Encodings.java @@ -35,6 +35,7 @@ public class Encodings { public static final int pseudoEncodingDesktopSize = -223; public static final int pseudoEncodingExtendedDesktopSize = -308; public static final int pseudoEncodingDesktopName = -307; + public static final int pseudoEncodingClientRedirect = -311; // TightVNC-specific public static final int pseudoEncodingLastRect = -224; diff --git a/java/src/com/tigervnc/rfb/Security.java b/java/src/com/tigervnc/rfb/Security.java index 95a66c3d..379851d8 100644 --- a/java/src/com/tigervnc/rfb/Security.java +++ b/java/src/com/tigervnc/rfb/Security.java @@ -39,7 +39,6 @@ public class Security { public static final int secTypeUltra = 17; public static final int secTypeTLS = 18; public static final int secTypeVeNCrypt = 19; - public static final int secTypeManaged = 20; /* VeNCrypt subtypes */ public static final int secTypePlain = 256; @@ -49,6 +48,9 @@ public class Security { public static final int secTypeX509None = 260; public static final int secTypeX509Vnc = 261; public static final int secTypeX509Plain = 262; + public static final int secTypeIdent = 265; + public static final int secTypeTLSIdent = 266; + public static final int secTypeX509Ident = 267; // result types @@ -131,16 +133,18 @@ public class Security { //if (name.equalsIgnoreCase("ultra")) return secTypeUltra; //if (name.equalsIgnoreCase("TLS")) return secTypeTLS; if (name.equalsIgnoreCase("VeNCrypt")) return secTypeVeNCrypt; - if (name.equalsIgnoreCase("Managed")) return secTypeManaged; /* VeNCrypt subtypes */ if (name.equalsIgnoreCase("Plain")) return secTypePlain; + if (name.equalsIgnoreCase("Ident")) return secTypeIdent; if (name.equalsIgnoreCase("TLSNone")) return secTypeTLSNone; if (name.equalsIgnoreCase("TLSVnc")) return secTypeTLSVnc; if (name.equalsIgnoreCase("TLSPlain")) return secTypeTLSPlain; + if (name.equalsIgnoreCase("TLSIdent")) return secTypeTLSIdent; if (name.equalsIgnoreCase("X509None")) return secTypeX509None; if (name.equalsIgnoreCase("X509Vnc")) return secTypeX509Vnc; if (name.equalsIgnoreCase("X509Plain")) return secTypeX509Plain; + if (name.equalsIgnoreCase("X509Ident")) return secTypeX509Ident; return secTypeInvalid; } @@ -157,16 +161,18 @@ public class Security { //case secTypeUltra: return "Ultra"; //case secTypeTLS: return "TLS"; case secTypeVeNCrypt: return "VeNCrypt"; - case secTypeManaged: return "Managed"; /* VeNCrypt subtypes */ case secTypePlain: return "Plain"; + case secTypeIdent: return "Ident"; case secTypeTLSNone: return "TLSNone"; case secTypeTLSVnc: return "TLSVnc"; case secTypeTLSPlain: return "TLSPlain"; + case secTypeTLSIdent: return "TLSIdent"; case secTypeX509None: return "X509None"; case secTypeX509Vnc: return "X509Vnc"; case secTypeX509Plain: return "X509Plain"; + case secTypeX509Ident: return "X509Ident"; default: return "[unknown secType]"; } } diff --git a/java/src/com/tigervnc/rfb/SecurityClient.java b/java/src/com/tigervnc/rfb/SecurityClient.java index 90c35d81..a8abd9e1 100644 --- a/java/src/com/tigervnc/rfb/SecurityClient.java +++ b/java/src/com/tigervnc/rfb/SecurityClient.java @@ -19,24 +19,26 @@ package com.tigervnc.rfb; +import com.tigervnc.vncviewer.CConn; + public class SecurityClient extends Security { public SecurityClient() { super(secTypes); } public CSecurity GetCSecurity(int secType) { - //assert (CSecurity::upg != NULL); /* (upg == NULL) means bug in the viewer */ - //assert (CSecurityTLS::msg != NULL); + assert (CConn.upg != null); /* (upg == null) means bug in the viewer */ + assert (msg != null); if (!IsSupported(secType)) throw new Exception("Security type not supported"); switch (secType) { - case Security.secTypeManaged: return (new CSecurityManaged()); case Security.secTypeNone: return (new CSecurityNone()); case Security.secTypeVncAuth: return (new CSecurityVncAuth()); case Security.secTypeVeNCrypt: return (new CSecurityVeNCrypt(this)); case Security.secTypePlain: return (new CSecurityPlain()); + case Security.secTypeIdent: return (new CSecurityIdent()); case Security.secTypeTLSNone: return (new CSecurityStack(secTypeTLSNone, "TLS with no password", new CSecurityTLS(true), null)); @@ -46,15 +48,21 @@ public class SecurityClient extends Security { case Security.secTypeTLSPlain: return (new CSecurityStack(secTypeTLSPlain, "TLS with Username/Password", new CSecurityTLS(true), new CSecurityPlain())); + case Security.secTypeTLSIdent: + return (new CSecurityStack(secTypeTLSIdent, "TLS with username only", + new CSecurityTLS(true), new CSecurityIdent())); case Security.secTypeX509None: return (new CSecurityStack(secTypeX509None, "X509 with no password", new CSecurityTLS(false), null)); case Security.secTypeX509Vnc: - return (new CSecurityStack(secTypeX509None, "X509 with VNCAuth", + return (new CSecurityStack(secTypeX509Vnc, "X509 with VNCAuth", new CSecurityTLS(false), new CSecurityVncAuth())); case Security.secTypeX509Plain: return (new CSecurityStack(secTypeX509Plain, "X509 with Username/Password", new CSecurityTLS(false), new CSecurityPlain())); + case Security.secTypeX509Ident: + return (new CSecurityStack(secTypeX509Ident, "X509 with username only", + new CSecurityTLS(false), new CSecurityIdent())); default: throw new Exception("Security type not supported"); } @@ -72,6 +80,6 @@ public class SecurityClient extends Security { static StringParameter secTypes = new StringParameter("SecurityTypes", "Specify which security scheme to use (None, VncAuth)", - "Managed,X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone,VncAuth,None"); + "Ident,TLSIdent,X509Ident,X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone,VncAuth,None"); } diff --git a/java/src/com/tigervnc/vncviewer/CConn.java b/java/src/com/tigervnc/vncviewer/CConn.java index 28b5d295..9224aa17 100644 --- a/java/src/com/tigervnc/vncviewer/CConn.java +++ b/java/src/com/tigervnc/vncviewer/CConn.java @@ -282,6 +282,25 @@ public class CConn extends CConnection resizeFramebuffer(); } + // clientRedirect() migrates the client to another host/port + public void clientRedirect(int port, String host, + String x509subject) { + try { + getSocket().close(); + setServerPort(port); + sock = new java.net.Socket(host, port); + sock.setTcpNoDelay(true); + sock.setTrafficClass(0x10); + setSocket(sock); + vlog.info("Redirected to "+host+":"+port); + setStreams(new JavaInStream(sock.getInputStream()), + new JavaOutStream(sock.getOutputStream())); + initialiseProtocol(); + } catch (java.io.IOException e) { + e.printStackTrace(); + } + } + // setName() is called when the desktop name changes public void setName(String name) { super.setName(name); @@ -404,6 +423,8 @@ public class CConn extends CConnection private void resizeFramebuffer() { + if ((cp.width == 0) && (cp.height == 0)) + return; if (desktop == null) return; if ((desktop.width() == cp.width) && (desktop.height() == cp.height)) @@ -677,7 +698,7 @@ public class CConn extends CConnection options.encX509.setEnabled(false); options.ca.setEnabled(false); options.crl.setEnabled(false); - options.secManaged.setEnabled(false); + options.secIdent.setEnabled(false); options.secNone.setEnabled(false); options.secVnc.setEnabled(false); options.secPlain.setEnabled(false); @@ -693,11 +714,6 @@ public class CConn extends CConnection case Security.secTypeVeNCrypt: options.secVeNCrypt.setSelected(true); break; - case Security.secTypeManaged: - options.encNone.setSelected(true); - options.secManaged.setSelected(true); - options.sendLocalUsername.setSelected(true); - break; case Security.secTypeNone: options.encNone.setSelected(true); options.secNone.setSelected(true); @@ -719,6 +735,10 @@ public class CConn extends CConnection options.secPlain.setSelected(true); options.sendLocalUsername.setSelected(true); break; + case Security.secTypeIdent: + options.secIdent.setSelected(true); + options.sendLocalUsername.setSelected(true); + break; case Security.secTypeTLSNone: options.encTLS.setSelected(true); options.secNone.setSelected(true); @@ -732,6 +752,11 @@ public class CConn extends CConnection options.secPlain.setSelected(true); options.sendLocalUsername.setSelected(true); break; + case Security.secTypeTLSIdent: + options.encTLS.setSelected(true); + options.secIdent.setSelected(true); + options.sendLocalUsername.setSelected(true); + break; case Security.secTypeX509None: options.encX509.setSelected(true); options.secNone.setSelected(true); @@ -745,11 +770,16 @@ public class CConn extends CConnection options.secPlain.setSelected(true); options.sendLocalUsername.setSelected(true); break; + case Security.secTypeX509Ident: + options.encX509.setSelected(true); + options.secIdent.setSelected(true); + options.sendLocalUsername.setSelected(true); + break; } } } options.sendLocalUsername.setEnabled(options.secPlain.isSelected()|| - options.secManaged.isSelected()); + options.secIdent.isSelected()); } options.fullScreen.setSelected(fullScreen); @@ -823,19 +853,19 @@ public class CConn extends CConnection if (state() != RFBSTATE_NORMAL) { /* Process security types which don't use encryption */ if (options.encNone.isSelected()) { - if (options.secManaged.isSelected()) - Security.EnableSecType(Security.secTypeManaged); if (options.secNone.isSelected()) Security.EnableSecType(Security.secTypeNone); if (options.secVnc.isSelected()) Security.EnableSecType(Security.secTypeVncAuth); if (options.secPlain.isSelected()) Security.EnableSecType(Security.secTypePlain); + if (options.secIdent.isSelected()) + Security.EnableSecType(Security.secTypeIdent); } else { - Security.DisableSecType(Security.secTypeManaged); Security.DisableSecType(Security.secTypeNone); Security.DisableSecType(Security.secTypeVncAuth); Security.DisableSecType(Security.secTypePlain); + Security.DisableSecType(Security.secTypeIdent); } /* Process security types which use TLS encryption */ @@ -846,10 +876,13 @@ public class CConn extends CConnection Security.EnableSecType(Security.secTypeTLSVnc); if (options.secPlain.isSelected()) Security.EnableSecType(Security.secTypeTLSPlain); + if (options.secIdent.isSelected()) + Security.EnableSecType(Security.secTypeTLSIdent); } else { Security.DisableSecType(Security.secTypeTLSNone); Security.DisableSecType(Security.secTypeTLSVnc); Security.DisableSecType(Security.secTypeTLSPlain); + Security.DisableSecType(Security.secTypeTLSIdent); } /* Process security types which use X509 encryption */ @@ -860,10 +893,13 @@ public class CConn extends CConnection Security.EnableSecType(Security.secTypeX509Vnc); if (options.secPlain.isSelected()) Security.EnableSecType(Security.secTypeX509Plain); + if (options.secIdent.isSelected()) + Security.EnableSecType(Security.secTypeX509Ident); } else { Security.DisableSecType(Security.secTypeX509None); Security.DisableSecType(Security.secTypeX509Vnc); Security.DisableSecType(Security.secTypeX509Plain); + Security.DisableSecType(Security.secTypeX509Ident); } /* Process *None security types */ @@ -908,6 +944,20 @@ public class CConn extends CConnection Security.DisableSecType(Security.secTypeX509Plain); } + /* Process *Ident security types */ + if (options.secIdent.isSelected()) { + if (options.encNone.isSelected()) + Security.EnableSecType(Security.secTypeIdent); + if (options.encTLS.isSelected()) + Security.EnableSecType(Security.secTypeTLSIdent); + if (options.encX509.isSelected()) + Security.EnableSecType(Security.secTypeX509Ident); + } else { + Security.DisableSecType(Security.secTypeIdent); + Security.DisableSecType(Security.secTypeTLSIdent); + Security.DisableSecType(Security.secTypeX509Ident); + } + CSecurityTLS.x509ca.setParam(options.ca.getText()); CSecurityTLS.x509crl.setParam(options.crl.getText()); } diff --git a/java/src/com/tigervnc/vncviewer/OptionsDialog.java b/java/src/com/tigervnc/vncviewer/OptionsDialog.java index b38c00c5..98198158 100644 --- a/java/src/com/tigervnc/vncviewer/OptionsDialog.java +++ b/java/src/com/tigervnc/vncviewer/OptionsDialog.java @@ -49,7 +49,7 @@ class OptionsDialog extends Dialog implements JCheckBox viewOnly, acceptClipboard, sendClipboard; JCheckBox fullScreen, shared, useLocalCursor, fastCopyRect; JCheckBox secVeNCrypt, encNone, encTLS, encX509; - JCheckBox secNone, secVnc, secPlain, secManaged, sendLocalUsername; + JCheckBox secNone, secVnc, secPlain, secIdent, sendLocalUsername; JButton okButton, cancelButton; JButton ca, crl; JButton defSaveButton; @@ -206,7 +206,7 @@ class OptionsDialog extends Dialog implements secNone = addCheckbox("None", null, authPanel); secVnc = addCheckbox("Standard VNC", null, authPanel); secPlain = addJCheckBox("Plaintext", null, authPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0)); - secManaged = addJCheckBox("Managed", null, authPanel, new GridBagConstraints(0,3,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0)); + secIdent = addJCheckBox("Ident", null, authPanel, new GridBagConstraints(0,3,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0)); sendLocalUsername = new JCheckBox("Send Local Username"); sendLocalUsername.addItemListener(this); addGBComponent(sendLocalUsername, authPanel, 1, 2, 1, 2, 0, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,20,0,0)); @@ -266,7 +266,7 @@ class OptionsDialog extends Dialog implements compressLevel.setEnabled(customCompressLevel.isSelected()); qualityLevel.setEnabled(noJpeg.isSelected()); sendLocalUsername.setEnabled(secVeNCrypt.isEnabled()&& - (secPlain.isSelected()||secManaged.isSelected())); + (secPlain.isSelected()||secIdent.isSelected())); } JRadioButton addRadioCheckbox(String str, ButtonGroup group, JPanel panel) { @@ -365,15 +365,15 @@ class OptionsDialog extends Dialog implements encX509.setEnabled(secVeNCrypt.isSelected()); ca.setEnabled(secVeNCrypt.isSelected()); crl.setEnabled(secVeNCrypt.isSelected()); - secManaged.setEnabled(secVeNCrypt.isSelected()); + secIdent.setEnabled(secVeNCrypt.isSelected()); secNone.setEnabled(secVeNCrypt.isSelected()); secVnc.setEnabled(secVeNCrypt.isSelected()); secPlain.setEnabled(secVeNCrypt.isSelected()); sendLocalUsername.setEnabled(secVeNCrypt.isSelected()); } - if (s instanceof JCheckBox && (JCheckBox)s == secManaged || + if (s instanceof JCheckBox && (JCheckBox)s == secIdent || s instanceof JCheckBox && (JCheckBox)s == secPlain) { - sendLocalUsername.setEnabled(secManaged.isSelected()||secPlain.isSelected()); + sendLocalUsername.setEnabled(secIdent.isSelected()||secPlain.isSelected()); } } -- 2.39.5