Merge branch 'allowoverride' of https://github.com/michalsrb/tigervnc
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 773556a..cd5a23b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,9 @@
#
cmake_minimum_required(VERSION 2.8)
+if(POLICY CMP0022)
+ cmake_policy(SET CMP0022 OLD)
+endif()
# Internal cmake modules
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
@@ -146,18 +149,22 @@
find_path(GETTEXT_INCLUDE_DIR libintl.h)
if(GETTEXT_INCLUDE_DIR)
set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
+ set(CMAKE_REQUIRED_FLAGS -fno-builtin-dgettext)
check_function_exists(dgettext LIBC_HAS_DGETTEXT)
if(LIBC_HAS_DGETTEXT)
set(GETTEXT_FOUND TRUE)
else()
find_library(LIBINTL_LIBRARY NAMES intl libintl)
- check_library_exists(${LIBINTL_LIBRARY} "dgettext" "" LIBINTL_HAS_DGETTEXT)
- if(LIBINTL_HAS_DGETTEXT)
- set(GETTEXT_LIBRARIES ${LIBINTL_LIBRARY} ${ICONV_LIBRARIES})
- set(GETTEXT_FOUND TRUE)
+ if(LIBINTL_LIBRARY)
+ check_library_exists(${LIBINTL_LIBRARY} "dgettext" "" LIBINTL_HAS_DGETTEXT)
+ if(LIBINTL_HAS_DGETTEXT)
+ set(GETTEXT_LIBRARIES ${LIBINTL_LIBRARY} ${ICONV_LIBRARIES})
+ set(GETTEXT_FOUND TRUE)
+ endif()
endif()
endif()
set(CMAKE_REQUIRED_LIBRARIES)
+ set(CMAKE_REQUIRED_FLAGS)
endif()
endif()
diff --git a/contrib/packages/rpm/el6/SOURCES/nettle-2.7.1-ecc-cve.patch b/contrib/packages/rpm/el6/SOURCES/nettle-2.7.1-ecc-cve.patch
new file mode 100644
index 0000000..130f2fc
--- /dev/null
+++ b/contrib/packages/rpm/el6/SOURCES/nettle-2.7.1-ecc-cve.patch
@@ -0,0 +1,275 @@
+diff --git a/ecc-256.c b/ecc-256.c
+index 571cf73..07841b1 100644
+--- a/ecc-256.c
++++ b/ecc-256.c
+@@ -108,7 +108,10 @@ ecc_256_modp (const struct ecc_curve *ecc, mp_limb_t *rp)
+ u0 -= t;
+ t = (u1 < cy);
+ u1 -= cy;
+- u1 += cnd_add_n (t, rp + n - 4, ecc->p, 3);
++
++ cy = cnd_add_n (t, rp + n - 4, ecc->p, 2);
++ u0 += cy;
++ u1 += (u0 < cy);
+ u1 -= (-t) & 0xffffffff;
+ }
+ rp[2] = u0;
+@@ -195,7 +198,7 @@ ecc_256_modq (const struct ecc_curve *ecc, mp_limb_t *rp)
+
+ /* Conditional add of p */
+ u1 += t;
+- u2 += (t<<32) + (u0 < t);
++ u2 += (t<<32) + (u1 < t);
+
+ t = cnd_add_n (t, rp + n - 4, ecc->q, 2);
+ u1 += t;
+diff --git a/x86_64/ecc-384-modp.asm b/x86_64/ecc-384-modp.asm
+index 698838f..31b739e 100644
+--- a/x86_64/ecc-384-modp.asm
++++ b/x86_64/ecc-384-modp.asm
+@@ -20,7 +20,7 @@ C MA 02111-1301, USA.
+ .file "ecc-384-modp.asm"
+
+ define(<RP>, <%rsi>)
+-define(<D4>, <%rax>)
++define(<D5>, <%rax>)
+ define(<T0>, <%rbx>)
+ define(<T1>, <%rcx>)
+ define(<T2>, <%rdx>)
+@@ -35,8 +35,8 @@ define(<H4>, <%r13>)
+ define(<H5>, <%r14>)
+ define(<C2>, <%r15>)
+ define(<C0>, H5) C Overlap
+-define(<D0>, RP) C Overlap
+-define(<TMP>, H4) C Overlap
++define(<TMP>, RP) C Overlap
++
+
+ PROLOGUE(nettle_ecc_384_modp)
+ W64_ENTRY(2, 0)
+@@ -48,34 +48,38 @@ PROLOGUE(nettle_ecc_384_modp)
+ push %r14
+ push %r15
+
+- C First get top 2 limbs, which need folding twice
++ C First get top 2 limbs, which need folding twice.
++ C B^10 = B^6 + B^4 + 2^32 (B-1)B^4.
++ C We handle the terms as follow:
+ C
+- C H5 H4
+- C -H5
+- C ------
+- C H0 D4
++ C B^6: Folded immediatly.
+ C
+- C Then shift right, (H1,H0,D4) <-- (H0,D4) << 32
+- C and add
++ C B^4: Delayed, added in in the next folding.
+ C
+- C H5 H4
+- C H1 H0
+- C ----------
+- C C2 H1 H0
+-
+- mov 80(RP), D4
+- mov 88(RP), H0
+- mov D4, H4
+- mov H0, H5
+- sub H0, D4
+- sbb $0, H0
+-
+- mov D4, T2
+- mov H0, H1
+- shl $32, H0
+- shr $32, T2
++ C 2^32(B-1) B^4: Low half limb delayed until the next
++ C folding. Top 1.5 limbs subtracted and shifter now, resulting
++ C in 2.5 limbs. The low limb saved in D5, high 1.5 limbs added
++ C in.
++
++ mov 80(RP), H4
++ mov 88(RP), H5
++ C Shift right 32 bits, into H1, H0
++ mov H4, H0
++ mov H5, H1
++ mov H5, D5
+ shr $32, H1
+- or T2, H0
++ shl $32, D5
++ shr $32, H0
++ or D5, H0
++
++ C H1 H0
++ C - H1 H0
++ C --------
++ C H1 H0 D5
++ mov H0, D5
++ neg D5
++ sbb H1, H0
++ sbb $0, H1
+
+ xor C2, C2
+ add H4, H0
+@@ -114,118 +118,95 @@ PROLOGUE(nettle_ecc_384_modp)
+ adc H3, T5
+ adc $0, C0
+
+- C H3 H2 H1 H0 0
+- C - H4 H3 H2 H1 H0
+- C ---------------
+- C H3 H2 H1 H0 D0
+-
+- mov XREG(D4), XREG(D4)
+- mov H0, D0
+- neg D0
+- sbb H1, H0
+- sbb H2, H1
+- sbb H3, H2
+- sbb H4, H3
+- sbb $0, D4
+-
+- C Shift right. High bits are sign, to be added to C0.
+- mov D4, TMP
+- sar $32, TMP
+- shl $32, D4
+- add TMP, C0
+-
++ C Shift left, including low half of H4
+ mov H3, TMP
++ shl $32, H4
+ shr $32, TMP
+- shl $32, H3
+- or TMP, D4
++ or TMP, H4
+
+ mov H2, TMP
++ shl $32, H3
+ shr $32, TMP
+- shl $32, H2
+ or TMP, H3
+
+ mov H1, TMP
++ shl $32, H2
+ shr $32, TMP
+- shl $32, H1
+ or TMP, H2
+
+ mov H0, TMP
++ shl $32, H1
+ shr $32, TMP
+- shl $32, H0
+ or TMP, H1
+
+- mov D0, TMP
+- shr $32, TMP
+- shl $32, D0
+- or TMP, H0
++ shl $32, H0
++
++ C H4 H3 H2 H1 H0 0
++ C - H4 H3 H2 H1 H0
++ C ---------------
++ C H4 H3 H2 H1 H0 TMP
+
+- add D0, T0
++ mov H0, TMP
++ neg TMP
++ sbb H1, H0
++ sbb H2, H1
++ sbb H3, H2
++ sbb H4, H3
++ sbb $0, H4
++
++ add TMP, T0
+ adc H0, T1
+ adc H1, T2
+ adc H2, T3
+ adc H3, T4
+- adc D4, T5
++ adc H4, T5
+ adc $0, C0
+
+ C Remains to add in C2 and C0
+- C C0 C0<<32 (-2^32+1)C0
+- C C2 C2<<32 (-2^32+1)C2
+- C where C2 is always positive, while C0 may be -1.
++ C Set H1, H0 = (2^96 - 2^32 + 1) C0
+ mov C0, H0
+ mov C0, H1
+- mov C0, H2
+- sar $63, C0 C Get sign
+ shl $32, H1
+- sub H1, H0 C Gives borrow iff C0 > 0
++ sub H1, H0
+ sbb $0, H1
+- add C0, H2
+
++ C Set H3, H2 = (2^96 - 2^32 + 1) C2
++ mov C2, H2
++ mov C2, H3
++ shl $32, H3
++ sub H3, H2
++ sbb $0, H3
++ add C0, H2 C No carry. Could use lea trick
++
++ xor C0, C0
+ add H0, T0
+ adc H1, T1
+- adc $0, H2
+- adc $0, C0
+-
+- C Set (H1 H0) <-- C2 << 96 - C2 << 32 + 1
+- mov C2, H0
+- mov C2, H1
+- shl $32, H1
+- sub H1, H0
+- sbb $0, H1
+-
+- add H2, H0
+- adc C0, H1
+- adc C2, C0
+- mov C0, H2
+- sar $63, C0
+- add H0, T2
+- adc H1, T3
+- adc H2, T4
+- adc C0, T5
+- sbb C0, C0
++ adc H2, T2
++ adc H3, T3
++ adc C2, T4
++ adc D5, T5 C Value delayed from initial folding
++ adc $0, C0 C Use sbb and switch sign?
+
+ C Final unlikely carry
+ mov C0, H0
+ mov C0, H1
+- mov C0, H2
+- sar $63, C0
+ shl $32, H1
+ sub H1, H0
+ sbb $0, H1
+- add C0, H2
+
+ pop RP
+
+- sub H0, T0
++ add H0, T0
+ mov T0, (RP)
+- sbb H1, T1
++ adc H1, T1
+ mov T1, 8(RP)
+- sbb H2, T2
++ adc C0, T2
+ mov T2, 16(RP)
+- sbb C0, T3
++ adc $0, T3
+ mov T3, 24(RP)
+- sbb C0, T4
++ adc $0, T4
+ mov T4, 32(RP)
+- sbb C0, T5
++ adc $0, T5
+ mov T5, 40(RP)
+
+ pop %r15
diff --git a/contrib/packages/rpm/el6/SPECS/tigervnc.spec b/contrib/packages/rpm/el6/SPECS/tigervnc.spec
index 67bd82d..16d1ba5 100644
--- a/contrib/packages/rpm/el6/SPECS/tigervnc.spec
+++ b/contrib/packages/rpm/el6/SPECS/tigervnc.spec
@@ -10,7 +10,7 @@
Name: tigervnc
Version: @VERSION@
-Release: 3%{?snap:.%{snap}}%{?dist}
+Release: 4%{?snap:.%{snap}}%{?dist}
Summary: A TigerVNC remote display system
Group: User Interface/Desktops
@@ -60,6 +60,7 @@
Obsoletes: tightvnc < 1.5.0-0.15.20090204svn3586
Patch16: tigervnc-xorg-manpages.patch
+Patch17: nettle-2.7.1-ecc-cve.patch
%description
Virtual Network Computing (VNC) is a remote display system which
@@ -165,6 +166,9 @@
tar xjf %SOURCE14
tar xzf %SOURCE15
tar xzf %SOURCE16
+pushd nettle-*
+%patch17 -p1 -b .ecc-cve
+popd
xzcat %SOURCE17 | tar xf -
%endif
@@ -456,6 +460,9 @@
%endif
%changelog
+* Sat Apr 02 2016 Brian P. Hinz <bphinz@users.sourceforge.net> 1.6.80-4
+- Fixed CVE-2015-8803 CVE-2015-8804 CVE-2015-8805 secp256r1 and secp384r1 bugs
+
* Fri Dec 11 2015 Brian P. Hinz <bphinz@users.sourceforge.net> 1.6.80-3
- Configure with --host and --build to avoid build host-specific compiler opts
diff --git a/java/com/tigervnc/vncviewer/CConn.java b/java/com/tigervnc/vncviewer/CConn.java
index dbb2a29..b9680ef 100644
--- a/java/com/tigervnc/vncviewer/CConn.java
+++ b/java/com/tigervnc/vncviewer/CConn.java
@@ -78,7 +78,7 @@
public CConn(VncViewer viewer_, Socket sock_,
String vncServerName)
{
- serverHost = null; serverPort = 0; sock = sock_; viewer = viewer_;
+ sock = sock_; viewer = viewer_;
pendingPFChange = false;
currentEncoding = Encodings.encodingTight; lastServerEncoding = -1;
fullColour = viewer.fullColour.getValue();
@@ -121,8 +121,8 @@
} else {
if (vncServerName != null &&
!viewer.alwaysShowServerDialog.getValue()) {
- serverHost = Hostname.getHost(vncServerName);
- serverPort = Hostname.getPort(vncServerName);
+ setServerName(Hostname.getHost(vncServerName));
+ setServerPort(Hostname.getPort(vncServerName));
} else {
ServerDialog dlg = new ServerDialog(options, vncServerName, this);
boolean ret = dlg.showDialog();
@@ -130,20 +130,27 @@
close();
return;
}
- serverHost = viewer.vncServerName.getValueStr();
- serverPort = viewer.vncServerPort.getValue();
+ setServerName(viewer.vncServerName.getValueStr());
+ setServerPort(viewer.vncServerPort.getValue());
}
try {
- sock = new TcpSocket(serverHost, serverPort);
+ if (viewer.tunnel.getValue() || (viewer.via.getValue() != null)) {
+ int localPort = TcpSocket.findFreeTcpPort();
+ if (localPort == 0)
+ throw new Exception("Could not obtain free TCP port");
+ Tunnel.createTunnel(this, localPort);
+ sock = new TcpSocket("localhost", localPort);
+ } else {
+ sock = new TcpSocket(getServerName(), getServerPort());
+ }
} catch (java.lang.Exception e) {
throw new Exception(e.getMessage());
}
- vlog.info("connected to host "+serverHost+" port "+serverPort);
+ vlog.info("connected to host "+getServerName()+" port "+getServerPort());
}
sock.inStream().setBlockCallback(this);
- setServerName(serverHost);
setStreams(sock.inStream(), sock.outStream());
initialiseProtocol();
}
@@ -896,10 +903,47 @@
options.sendLocalUsername.setEnabled(false);
options.cfLoadButton.setEnabled(false);
options.cfSaveAsButton.setEnabled(true);
+ options.sshTunnel.setEnabled(false);
+ options.sshUseGateway.setEnabled(false);
+ options.sshUser.setEnabled(false);
+ options.sshHost.setEnabled(false);
+ options.sshPort.setEnabled(false);
+ options.sshUseExt.setEnabled(false);
+ options.sshClient.setEnabled(false);
+ options.sshClientBrowser.setEnabled(false);
+ options.sshArgsDefault.setEnabled(false);
+ options.sshArgsCustom.setEnabled(false);
+ options.sshArguments.setEnabled(false);
+ options.sshConfig.setEnabled(false);
+ options.sshConfigBrowser.setEnabled(false);
+ options.sshKeyFile.setEnabled(false);
+ options.sshKeyFileBrowser.setEnabled(false);
} else {
options.shared.setSelected(viewer.shared.getValue());
options.sendLocalUsername.setSelected(viewer.sendLocalUsername.getValue());
options.cfSaveAsButton.setEnabled(false);
+ if (viewer.tunnel.getValue() || viewer.via.getValue() != null)
+ options.sshTunnel.setSelected(true);
+ if (viewer.via.getValue() != null)
+ options.sshUseGateway.setSelected(true);
+ options.sshUser.setText(Tunnel.getSshUser(this));
+ options.sshHost.setText(Tunnel.getSshHost(this));
+ options.sshPort.setText(Integer.toString(Tunnel.getSshPort(this)));
+ options.sshUseExt.setSelected(viewer.extSSH.getValue());
+ File client = new File(viewer.extSSHClient.getValue());
+ if (client.exists() && client.canRead())
+ options.sshClient.setText(client.getAbsolutePath());
+ if (viewer.extSSHArgs.getValue() == null) {
+ options.sshArgsDefault.setSelected(true);
+ options.sshArguments.setText("");
+ } else {
+ options.sshArgsCustom.setSelected(true);
+ options.sshArguments.setText(viewer.extSSHArgs.getValue());
+ }
+ File config = new File(viewer.sshConfig.getValue());
+ if (config.exists() && config.canRead())
+ options.sshConfig.setText(config.getAbsolutePath());
+ options.sshKeyFile.setText(Tunnel.getSshKeyFile(this));
/* Process non-VeNCrypt sectypes */
java.util.List<Integer> secTypes = new ArrayList<Integer>();
@@ -990,6 +1034,46 @@
options.secPlain.setEnabled(options.secVeNCrypt.isSelected());
options.sendLocalUsername.setEnabled(options.secPlain.isSelected()||
options.secIdent.isSelected());
+ options.sshTunnel.setEnabled(true);
+ options.sshUseGateway.setEnabled(options.sshTunnel.isSelected());
+ options.sshUser.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseGateway.isEnabled() &&
+ options.sshUseGateway.isSelected());
+ options.sshHost.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseGateway.isEnabled() &&
+ options.sshUseGateway.isSelected());
+ options.sshPort.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseGateway.isEnabled() &&
+ options.sshUseGateway.isSelected());
+ options.sshUseExt.setEnabled(options.sshTunnel.isSelected());
+ options.sshClient.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ options.sshUseExt.isSelected());
+ options.sshClientBrowser.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ options.sshUseExt.isSelected());
+ options.sshArgsDefault.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ options.sshUseExt.isSelected());
+ options.sshArgsCustom.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ options.sshUseExt.isSelected());
+ options.sshArguments.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ options.sshUseExt.isSelected() &&
+ options.sshArgsCustom.isSelected());
+ options.sshConfig.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ !options.sshUseExt.isSelected());
+ options.sshConfigBrowser.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ !options.sshUseExt.isSelected());
+ options.sshKeyFile.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ !options.sshUseExt.isSelected());
+ options.sshKeyFileBrowser.setEnabled(options.sshTunnel.isSelected() &&
+ options.sshUseExt.isEnabled() &&
+ !options.sshUseExt.isSelected());
}
options.fullScreen.setSelected(fullScreen);
@@ -1111,6 +1195,7 @@
if (desktop != null)
desktop.resetLocalCursor();
}
+ viewer.extSSH.setParam(options.sshUseExt.isSelected());
checkEncodings();
@@ -1221,6 +1306,22 @@
Security.DisableSecType(Security.secTypeTLSIdent);
Security.DisableSecType(Security.secTypeX509Ident);
}
+ if (options.sshTunnel.isSelected()) {
+ if (options.sshUseGateway.isSelected()) {
+ String user = options.sshUser.getText();
+ String host = options.sshHost.getText();
+ String port = options.sshPort.getText();
+ viewer.via.setParam(user+"@"+host+":"+port);
+ } else {
+ viewer.tunnel.setParam(true);
+ }
+ }
+ viewer.extSSH.setParam(options.sshUseExt.isSelected());
+ viewer.extSSHClient.setParam(options.sshClient.getText());
+ if (options.sshArgsCustom.isSelected())
+ viewer.extSSHArgs.setParam(options.sshArguments.getText());
+ viewer.sshConfig.setParam(options.sshConfig.getText());
+ viewer.sshKeyFile.setParam(options.sshKeyFile.getText());
}
String desktopSize = (options.desktopSize.isSelected()) ?
options.desktopWidth.getText() + "x" + options.desktopHeight.getText() : "";
@@ -1472,8 +1573,6 @@
// the following are only ever accessed by the GUI thread:
int buttonMask;
- private String serverHost;
- private int serverPort;
private Socket sock;
protected DesktopWindow desktop;
diff --git a/java/com/tigervnc/vncviewer/Dialog.java b/java/com/tigervnc/vncviewer/Dialog.java
index 3d24619..8bf1979 100644
--- a/java/com/tigervnc/vncviewer/Dialog.java
+++ b/java/com/tigervnc/vncviewer/Dialog.java
@@ -99,6 +99,8 @@
for (Component ch : c.getComponents()) {
if (ch instanceof JCheckBox)
((JCheckBox)ch).addItemListener(this);
+ else if (ch instanceof JRadioButton)
+ ((JRadioButton)ch).addActionListener(this);
else if (ch instanceof JButton)
((JButton)ch).addActionListener(this);
else if (ch instanceof JComboBox)
diff --git a/java/com/tigervnc/vncviewer/OptionsDialog.java b/java/com/tigervnc/vncviewer/OptionsDialog.java
index 1681518..369b965 100644
--- a/java/com/tigervnc/vncviewer/OptionsDialog.java
+++ b/java/com/tigervnc/vncviewer/OptionsDialog.java
@@ -31,7 +31,6 @@
import java.util.*;
import java.util.Map.Entry;
-
import com.tigervnc.rfb.*;
import static java.awt.GridBagConstraints.BOTH;
@@ -50,16 +49,16 @@
private class IntegerDocument extends PlainDocument {
private int limit;
- IntegerDocument(int limit) {
+ public IntegerDocument(int max) {
super();
- this.limit = limit;
+ limit = max;
}
- public void insertString(int offset, String str, AttributeSet a)
+ public void insertString(int offset, String str, AttributeSet a)
throws BadLocationException {
if (str == null || !str.matches("^[0-9]+$")) return;
if ((getLength() + str.length()) > limit)
- java.awt.Toolkit.getDefaultToolkit().beep();
+ Toolkit.getDefaultToolkit().beep();
else
super.insertString(offset, str, a);
}
@@ -68,11 +67,11 @@
private class IntegerTextField extends JFormattedTextField {
public IntegerTextField(int digits) {
super();
- this.setDocument(new IntegerDocument(digits));
+ setDocument(new IntegerDocument(digits));
Font f = getFont();
String template = String.format("%0"+digits+"d", 0);
int w = getFontMetrics(f).stringWidth(template) +
- getMargin().left + getMargin().right +
+ getMargin().left + getMargin().right +
getInsets().left + getInsets().right;
int h = getPreferredSize().height;
setPreferredSize(new Dimension(w, h));
@@ -95,17 +94,20 @@
CConn cc;
@SuppressWarnings({"rawtypes"})
JComboBox menuKey, compressLevel, qualityLevel, scalingFactor;
- ButtonGroup encodingGroup, colourGroup;
+ ButtonGroup encodingGroup, colourGroup, sshArgsGroup;
JRadioButton zrle, hextile, tight, raw, fullColour, mediumColour,
- lowColour, veryLowColour;
+ lowColour, veryLowColour, sshArgsDefault, sshArgsCustom;
JCheckBox autoSelect, customCompressLevel, noJpeg, viewOnly,
acceptClipboard, sendClipboard, acceptBell, desktopSize,
fullScreen, fullScreenAllMonitors, shared, useLocalCursor,
secVeNCrypt, encNone, encTLS, encX509, secNone, secVnc,
- secPlain, secIdent, sendLocalUsername;
+ secPlain, secIdent, sendLocalUsername, sshTunnel, sshUseExt,
+ sshUseGateway;
JButton okButton, cancelButton, caButton, crlButton, cfLoadButton,
- cfSaveAsButton, defSaveButton, defReloadButton, defClearButton;
- JTextField desktopWidth, desktopHeight, x509ca, x509crl;
+ cfSaveAsButton, defSaveButton, defReloadButton, defClearButton,
+ sshConfigBrowser, sshKeyFileBrowser, sshClientBrowser;
+ JTextField desktopWidth, desktopHeight, x509ca, x509crl, sshUser, sshHost,
+ sshPort, sshClient, sshArguments, sshConfig, sshKeyFile;
JTabbedPane tabPane;
@SuppressWarnings({"rawtypes","unchecked"})
@@ -123,6 +125,7 @@
encodingGroup = new ButtonGroup();
colourGroup = new ButtonGroup();
+ sshArgsGroup = new ButtonGroup();
int indent = 0;
// Compression tab
@@ -573,6 +576,248 @@
new Insets(0, 0, 0, 0),
NONE, NONE));
+ // SSH tab
+ JPanel sshPanel = new JPanel(new GridBagLayout());
+ sshPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
+ sshTunnel = new JCheckBox("Tunnel VNC over SSH");
+
+ JPanel tunnelPanel = new JPanel(new GridBagLayout());
+
+ sshUseGateway = new JCheckBox("Use SSH gateway");
+ JLabel sshUserLabel = new JLabel("Username");
+ sshUser = new JTextField();
+ JLabel sshUserAtLabel = new JLabel("@");
+ JLabel sshHostLabel = new JLabel("Hostname (or IP address)");
+ sshHost = new JTextField("");
+ JLabel sshPortLabel = new JLabel("Port");
+ sshPort = new IntegerTextField(5);
+
+ sshUseExt = new JCheckBox("Use external SSH client");
+ sshClient = new JTextField();
+ sshClient.setName(Configuration.getParam("extSSHClient").getName());
+ sshClientBrowser = new JButton("Browse");
+ JLabel sshConfigLabel = new JLabel("SSH config file");
+ sshConfig = new JTextField();
+ sshConfig.setName(Configuration.getParam("sshConfig").getName());
+ sshConfigBrowser = new JButton("Browse");
+ JLabel sshKeyFileLabel = new JLabel("SSH identity file");
+ sshKeyFile = new JTextField();
+ sshKeyFile.setName(Configuration.getParam("sshKeyFile").getName());
+ sshKeyFileBrowser = new JButton("Browse");
+ JPanel sshArgsPanel = new JPanel(new GridBagLayout());
+ JLabel sshArgsLabel = new JLabel("Arguments:");
+ sshArgsDefault =
+ new GroupedJRadioButton("Default", sshArgsGroup, sshArgsPanel);
+ sshArgsCustom =
+ new GroupedJRadioButton("Custom", sshArgsGroup, sshArgsPanel);
+ sshArguments = new JTextField();
+
+ JPanel gatewayPanel = new JPanel(new GridBagLayout());
+ gatewayPanel.add(sshUseGateway,
+ new GridBagConstraints(0, 0,
+ REMAINDER, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 0, 4, 0),
+ NONE, NONE));
+ indent = getButtonLabelInset(sshUseGateway);
+ gatewayPanel.add(sshUserLabel,
+ new GridBagConstraints(0, 1,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, indent, 4, 0),
+ NONE, NONE));
+ gatewayPanel.add(sshHostLabel,
+ new GridBagConstraints(2, 1,
+ 1, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 0, 4, 0),
+ NONE, NONE));
+ gatewayPanel.add(sshPortLabel,
+ new GridBagConstraints(3, 1,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 5, 4, 0),
+ NONE, NONE));
+ gatewayPanel.add(sshUser,
+ new GridBagConstraints(0, 2,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, indent, 0, 0),
+ NONE, NONE));
+ gatewayPanel.add(sshUserAtLabel,
+ new GridBagConstraints(1, 2,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 2, 0, 2),
+ NONE, NONE));
+ gatewayPanel.add(sshHost,
+ new GridBagConstraints(2, 2,
+ 1, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 0, 0, 0),
+ NONE, NONE));
+ gatewayPanel.add(sshPort,
+ new GridBagConstraints(3, 2,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 5, 0, 0),
+ NONE, NONE));
+
+ JPanel clientPanel = new JPanel(new GridBagLayout());
+ clientPanel.add(sshUseExt,
+ new GridBagConstraints(0, 0,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 0, 0, 0),
+ NONE, NONE));
+ clientPanel.add(sshClient,
+ new GridBagConstraints(1, 0,
+ 1, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 5, 0, 0),
+ NONE, NONE));
+ clientPanel.add(sshClientBrowser,
+ new GridBagConstraints(2, 0,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 5, 0, 0),
+ NONE, NONE));
+ sshArgsPanel.add(sshArgsLabel,
+ new GridBagConstraints(0, 1,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 0, 0, 0),
+ NONE, NONE));
+ sshArgsPanel.add(sshArgsDefault,
+ new GridBagConstraints(1, 1,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 5, 0, 0),
+ NONE, NONE));
+ sshArgsPanel.add(sshArgsCustom,
+ new GridBagConstraints(2, 1,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 5, 0, 0),
+ NONE, NONE));
+ sshArgsPanel.add(sshArguments,
+ new GridBagConstraints(3, 1,
+ 1, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 5, 0, 0),
+ NONE, NONE));
+ indent = getButtonLabelInset(sshUseExt);
+ clientPanel.add(sshArgsPanel,
+ new GridBagConstraints(0, 1,
+ REMAINDER, 1,
+ LIGHT, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(4, indent, 0, 0),
+ NONE, NONE));
+
+ JPanel opensshPanel = new JPanel(new GridBagLayout());
+ opensshPanel.setBorder(BorderFactory.createTitledBorder("Embedded SSH client configuration"));
+ opensshPanel.add(sshConfigLabel,
+ new GridBagConstraints(0, 0,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 0, 5, 0),
+ NONE, NONE));
+ opensshPanel.add(sshConfig,
+ new GridBagConstraints(1, 0,
+ 1, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 5, 5, 0),
+ NONE, NONE));
+ opensshPanel.add(sshConfigBrowser,
+ new GridBagConstraints(2, 0,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, VERTICAL,
+ new Insets(0, 5, 5, 0),
+ NONE, NONE));
+ opensshPanel.add(sshKeyFileLabel,
+ new GridBagConstraints(0, 1,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 0, 0, 0),
+ NONE, NONE));
+ opensshPanel.add(sshKeyFile,
+ new GridBagConstraints(1, 1,
+ 1, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 5, 0, 0),
+ NONE, NONE));
+ opensshPanel.add(sshKeyFileBrowser,
+ new GridBagConstraints(2, 1,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, VERTICAL,
+ new Insets(0, 5, 0, 0),
+ NONE, NONE));
+ tunnelPanel.add(gatewayPanel,
+ new GridBagConstraints(0, 0,
+ REMAINDER, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 0, 4, 0),
+ NONE, NONE));
+ tunnelPanel.add(clientPanel,
+ new GridBagConstraints(0, 1,
+ REMAINDER, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 0, 4, 0),
+ NONE, NONE));
+ tunnelPanel.add(opensshPanel,
+ new GridBagConstraints(0, 2,
+ REMAINDER, 1,
+ HEAVY, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, 0, 0, 0),
+ NONE, NONE));
+
+ sshPanel.add(sshTunnel,
+ new GridBagConstraints(0, 0,
+ REMAINDER, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 0, 4, 0),
+ NONE, NONE));
+ indent = getButtonLabelInset(sshTunnel);
+ sshPanel.add(tunnelPanel,
+ new GridBagConstraints(0, 2,
+ REMAINDER, 1,
+ LIGHT, LIGHT,
+ LINE_START, HORIZONTAL,
+ new Insets(0, indent, 4, 0),
+ NONE, NONE));
+ sshPanel.add(Box.createRigidArea(new Dimension(5, 0)),
+ new GridBagConstraints(0, RELATIVE,
+ REMAINDER, REMAINDER,
+ HEAVY, HEAVY,
+ LINE_START, BOTH,
+ new Insets(0, 0, 0, 0),
+ NONE, NONE));
// load/save tab
JPanel loadSavePanel = new JPanel(new GridBagLayout());
@@ -659,6 +904,7 @@
tabPane.addTab("Input", inputPanel);
tabPane.addTab("Screen", ScreenPanel);
tabPane.addTab("Misc", MiscPanel);
+ tabPane.addTab("SSH", sshPanel);
tabPane.addTab("Load / Save", loadSavePanel);
tabPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
// Resize the tabPane if necessary to prevent scrolling
@@ -701,8 +947,10 @@
veryLowColour.setEnabled(!autoSelect.isSelected());
compressLevel.setEnabled(customCompressLevel.isSelected());
qualityLevel.setEnabled(noJpeg.isSelected());
- sendLocalUsername.setEnabled(secVeNCrypt.isEnabled()&&
- (secPlain.isSelected()||secIdent.isSelected()));
+ sendLocalUsername.setEnabled(secVeNCrypt.isEnabled() &&
+ (secPlain.isSelected() || secIdent.isSelected()));
+ sshArguments.setEnabled(sshTunnel.isSelected() &&
+ (sshUseExt.isSelected() && sshArgsCustom.isSelected()));
}
private void updatePreferences() {
@@ -782,6 +1030,19 @@
if (!CSecurityTLS.x509crl.getValueStr().equals(""))
UserPreferences.set("viewer", "x509crl",
CSecurityTLS.x509crl.getValueStr());
+ UserPreferences.set("global", "Tunnel", sshTunnel.isSelected());
+ if (sshUseGateway.isSelected()) {
+ String via = sshUser.getText()+"@"+sshHost.getText()+":"+sshPort.getText();
+ UserPreferences.set("global", "Via", via);
+ }
+ if (sshUseExt.isSelected()) {
+ UserPreferences.set("global", "extSSH", sshUseExt.isSelected());
+ UserPreferences.set("global", "extSSHClient", sshClient.getText());
+ if (!sshArguments.getText().isEmpty())
+ UserPreferences.set("global", "extSSHArgs", sshArguments.getText());
+ }
+ UserPreferences.set("global", "SSHConfig", sshConfig.getText());
+ UserPreferences.set("global", "SSHKeyFile", sshKeyFile.getText());
}
private void restorePreferences() {
@@ -832,8 +1093,7 @@
sendClipboard.setSelected(UserPreferences.getBool("global",
"SendClipboard"));
menuKey.setSelectedItem(UserPreferences.get("global", "MenuKey"));
- desktopSize.setSelected(UserPreferences.get("global", "DesktopSize")
- != null);
+ desktopSize.setSelected(!UserPreferences.get("global", "DesktopSize").isEmpty());
if (desktopSize.isSelected()) {
String desktopSizeString = UserPreferences.get("global", "DesktopSize");
desktopWidth.setText(desktopSizeString.split("x")[0]);
@@ -874,6 +1134,70 @@
secNone.setSelected(UserPreferences.getBool("viewer", "secNone", true));
if (secVnc.isEnabled())
secVnc.setSelected(UserPreferences.getBool("viewer", "secVnc", true));
+ sshTunnel.setSelected(UserPreferences.getBool("global", "Tunnel"));
+ sshUseGateway.setSelected(UserPreferences.get("global", "Via") != null);
+ if (sshUseGateway.isSelected())
+ cc.viewer.via.setParam(UserPreferences.get("global", "Via"));
+ sshUser.setText(Tunnel.getSshUser(cc));
+ sshHost.setText(Tunnel.getSshHost(cc));
+ sshPort.setText(Integer.toString(Tunnel.getSshPort(cc)));
+ sshUseExt.setSelected(UserPreferences.getBool("global", "extSSH"));
+ File f = new File(UserPreferences.get("global", "extSSHClient"));
+ if (f.exists() && f.canExecute())
+ sshClient.setText(f.getAbsolutePath());
+ sshArguments.setText(UserPreferences.get("global", "extSSHArgs"));
+ if (sshArguments.getText().isEmpty())
+ sshArgsDefault.setSelected(true);
+ else
+ sshArgsCustom.setSelected(true);
+ f = new File(UserPreferences.get("global", "SSHConfig"));
+ if (f.exists() && f.canRead())
+ sshConfig.setText(f.getAbsolutePath());
+ if (UserPreferences.get("global", "SSHKeyFile") != null) {
+ f = new File(UserPreferences.get("global", "SSHKeyFile"));
+ if (f.exists() && f.canRead())
+ sshKeyFile.setText(f.getAbsolutePath());
+ } else {
+ sshKeyFile.setText(Tunnel.getSshKeyFile(cc));
+ }
+ sshUseGateway.setEnabled(sshTunnel.isSelected());
+ sshUser.setEnabled(sshTunnel.isSelected() &&
+ sshUseGateway.isEnabled() &&
+ sshUseGateway.isSelected());
+ sshHost.setEnabled(sshTunnel.isSelected() &&
+ sshUseGateway.isEnabled() &&
+ sshUseGateway.isSelected());
+ sshPort.setEnabled(sshTunnel.isSelected() &&
+ sshUseGateway.isEnabled() &&
+ sshUseGateway.isSelected());
+ sshUseExt.setEnabled(sshTunnel.isSelected());
+ sshClient.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled());
+ sshClientBrowser.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected());
+ sshArgsDefault.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected());
+ sshArgsCustom.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected());
+ sshArguments.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected() &&
+ sshArgsCustom.isSelected());
+ sshConfig.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled() &&
+ !sshUseExt.isSelected());
+ sshConfigBrowser.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled() &&
+ !sshUseExt.isSelected());
+ sshKeyFile.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled() &&
+ !sshUseExt.isSelected());
+ sshKeyFileBrowser.setEnabled(sshTunnel.isSelected() &&
+ sshUseExt.isEnabled() &&
+ !sshUseExt.isSelected());
}
public void endDialog() {
@@ -890,15 +1214,15 @@
JButton button = (JButton)s;
if (button == okButton) {
JTextField[] fields =
- { x509ca, x509crl };
+ { x509ca, x509crl, sshClient, sshConfig, sshKeyFile };
for (JTextField field : fields) {
if (field.getText() != null && !field.getText().equals("")) {
File f = new File(field.getText());
if (!f.exists() || !f.canRead()) {
String msg = new String("The file "+f.getAbsolutePath()+
" specified for option "+field.getName()+
- " does not exist or cannot be read. Please "+
- "correct before proceeding.");
+ " does not exist or cannot be read. Please"+
+ " correct before proceeding.");
JOptionPane.showMessageDialog(this, msg, "WARNING",
JOptionPane.WARNING_MESSAGE);
return;
@@ -958,6 +1282,35 @@
int ret = fc.showOpenDialog(this);
if (ret == JFileChooser.APPROVE_OPTION)
x509crl.setText(fc.getSelectedFile().toString());
+ } else if (button == sshClientBrowser) {
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle("Path to external SSH client");
+ fc.setApproveButtonText("OK");
+ fc.setFileHidingEnabled(false);
+ int ret = fc.showOpenDialog(this);
+ if (ret == JFileChooser.APPROVE_OPTION)
+ sshClient.setText(fc.getSelectedFile().toString());
+ } else if (button == sshConfigBrowser) {
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle("Path to OpenSSH client config file");
+ fc.setApproveButtonText("OK");
+ fc.setFileHidingEnabled(false);
+ int ret = fc.showOpenDialog(this);
+ if (ret == JFileChooser.APPROVE_OPTION)
+ sshConfig.setText(fc.getSelectedFile().toString());
+ } else if (button == sshKeyFileBrowser) {
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle("Path to SSH key file");
+ fc.setApproveButtonText("OK");
+ fc.setFileHidingEnabled(false);
+ int ret = fc.showOpenDialog(this);
+ if (ret == JFileChooser.APPROVE_OPTION)
+ sshKeyFile.setText(fc.getSelectedFile().toString());
+ }
+ } else if (s instanceof JRadioButton) {
+ JRadioButton button = (JRadioButton)s;
+ if (button == sshArgsCustom || button == sshArgsDefault) {
+ sshArguments.setEnabled(sshArgsCustom.isSelected());
}
}
}
@@ -983,16 +1336,16 @@
qualityLevel.setEnabled(enable);
} else if (item == encX509) {
x509ca.setEnabled(enable);
- x509crl.setEnabled(enable);
caButton.setEnabled(enable);
+ x509crl.setEnabled(enable);
crlButton.setEnabled(enable);
} else if (item == secVeNCrypt) {
encNone.setEnabled(enable);
encTLS.setEnabled(enable);
encX509.setEnabled(enable);
x509ca.setEnabled(enable && encX509.isSelected());
- x509crl.setEnabled(enable && encX509.isSelected());
caButton.setEnabled(enable && encX509.isSelected());
+ x509crl.setEnabled(enable && encX509.isSelected());
crlButton.setEnabled(enable && encX509.isSelected());
secIdent.setEnabled(enable);
secPlain.setEnabled(enable);
@@ -1005,6 +1358,60 @@
} else if (item == secIdent || item == secPlain) {
sendLocalUsername.setEnabled(secIdent.isSelected() ||
secPlain.isSelected());
+ } else if (item == sshTunnel) {
+ sshUseGateway.setEnabled(enable);
+ sshUser.setEnabled(enable &&
+ sshUseGateway.isEnabled() &&
+ sshUseGateway.isSelected());
+ sshHost.setEnabled(enable &&
+ sshUseGateway.isEnabled() &&
+ sshUseGateway.isSelected());
+ sshPort.setEnabled(enable &&
+ sshUseGateway.isEnabled() &&
+ sshUseGateway.isSelected());
+ sshUseExt.setEnabled(enable);
+ sshClient.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected());
+ sshClientBrowser.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected());
+ sshArgsDefault.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected());
+ sshArgsCustom.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected());
+ sshArguments.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ sshUseExt.isSelected() &&
+ sshArgsCustom.isSelected());
+ sshConfig.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ !sshUseExt.isSelected());
+ sshConfigBrowser.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ !sshUseExt.isSelected());
+ sshKeyFile.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ !sshUseExt.isSelected());
+ sshKeyFileBrowser.setEnabled(enable &&
+ sshUseExt.isEnabled() &&
+ !sshUseExt.isSelected());
+ } else if (item == sshUseExt) {
+ sshClient.setEnabled(enable);
+ sshClientBrowser.setEnabled(enable);
+ sshArgsDefault.setEnabled(enable);
+ sshArgsCustom.setEnabled(enable);
+ sshArguments.setEnabled(enable && sshArgsCustom.isSelected());
+ sshConfig.setEnabled(!enable);
+ sshConfigBrowser.setEnabled(!enable);
+ sshKeyFile.setEnabled(!enable);
+ sshKeyFileBrowser.setEnabled(!enable);
+ } else if (item == sshUseGateway) {
+ sshUser.setEnabled(enable);
+ sshHost.setEnabled(enable);
+ sshPort.setEnabled(enable);
}
}
}
diff --git a/java/com/tigervnc/vncviewer/PasswdDialog.java b/java/com/tigervnc/vncviewer/PasswdDialog.java
index 26a138d..fbaf991 100644
--- a/java/com/tigervnc/vncviewer/PasswdDialog.java
+++ b/java/com/tigervnc/vncviewer/PasswdDialog.java
@@ -120,6 +120,8 @@
if (userEntry.isEnabled())
if (userEntry.getText().equals(""))
return false;
+ else if (!passwdEntry.isEnabled())
+ return true;
if (passwdEntry.isEnabled())
if (!passwdEntry.getText().equals(""))
return true;
diff --git a/java/com/tigervnc/vncviewer/Tunnel.java b/java/com/tigervnc/vncviewer/Tunnel.java
new file mode 100644
index 0000000..90ab38e
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/Tunnel.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2012-2016 All Rights Reserved.
+ * Copyright (C) 2000 Const Kaplinsky. All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+/*
+ * tunnel.java - SSH tunneling support
+ */
+
+package com.tigervnc.vncviewer;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.*;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+import com.tigervnc.network.*;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.ConfigRepository;
+import com.jcraft.jsch.Logger;
+import com.jcraft.jsch.OpenSSHConfig;
+import com.jcraft.jsch.Session;
+
+public class Tunnel {
+
+ private final static String DEFAULT_TUNNEL_TEMPLATE
+ = "-f -L %L:localhost:%R %H sleep 20";
+ private final static String DEFAULT_VIA_TEMPLATE
+ = "-f -L %L:%H:%R %G sleep 20";
+
+ public static void createTunnel(CConn cc, int localPort) throws Exception {
+ int remotePort;
+ String gatewayHost;
+ String remoteHost;
+
+ remotePort = cc.getServerPort();
+ if (cc.viewer.tunnel.getValue()) {
+ gatewayHost = cc.getServerName();
+ remoteHost = "localhost";
+ } else {
+ gatewayHost = getSshHost(cc);
+ remoteHost = cc.getServerName();
+ }
+
+ String pattern = cc.viewer.extSSHArgs.getValue();
+ if (pattern == null) {
+ if (cc.viewer.tunnel.getValue())
+ pattern = System.getProperty("VNC_TUNNEL_CMD");
+ else
+ pattern = System.getProperty("VNC_VIA_CMD");
+ }
+
+ if (cc.viewer.extSSH.getValue() ||
+ (pattern != null && pattern.length() > 0)) {
+ createTunnelExt(gatewayHost, remoteHost, remotePort, localPort, pattern, cc);
+ } else {
+ createTunnelJSch(gatewayHost, remoteHost, remotePort, localPort, cc);
+ }
+ }
+
+ private static class MyJSchLogger implements Logger {
+ public boolean isEnabled(int level){
+ return true;
+ }
+
+ public void log(int level, String msg){
+ switch (level) {
+ case Logger.INFO:
+ vlog.info(msg);
+ break;
+ case Logger.ERROR:
+ vlog.error(msg);
+ break;
+ default:
+ vlog.debug(msg);
+ }
+ }
+ }
+
+ public static String getSshHost(CConn cc) {
+ String sshHost = cc.viewer.via.getValue();
+ if (sshHost == null)
+ return cc.getServerName();
+ int end = sshHost.indexOf(":");
+ if (end < 0)
+ end = sshHost.length();
+ sshHost = sshHost.substring(sshHost.indexOf("@")+1, end);
+ return sshHost;
+ }
+
+ public static String getSshUser(CConn cc) {
+ String sshUser = (String)System.getProperties().get("user.name");
+ String via = cc.viewer.via.getValue();
+ if (via != null && via.indexOf("@") > 0)
+ sshUser = via.substring(0, via.indexOf("@"));
+ return sshUser;
+ }
+
+ public static int getSshPort(CConn cc) {
+ String sshPort = "22";
+ String via = cc.viewer.via.getValue();
+ if (via != null && via.indexOf(":") > 0)
+ sshPort = via.substring(via.indexOf(":")+1, via.length());
+ return Integer.parseInt(sshPort);
+ }
+
+ public static String getSshKeyFile(CConn cc) {
+ if (cc.viewer.sshKeyFile.getValue() != null)
+ return cc.viewer.sshKeyFile.getValue();
+ String[] ids = { "id_dsa", "id_rsa" };
+ for (String id : ids) {
+ File f = new File(FileUtils.getHomeDir()+".ssh/"+id);
+ if (f.exists() && f.canRead())
+ return(f.getAbsolutePath());
+ }
+ return null;
+ }
+
+ private static void createTunnelJSch(String gatewayHost, String remoteHost,
+ int remotePort, int localPort,
+ CConn cc) throws Exception {
+ JSch.setLogger(new MyJSchLogger());
+ JSch jsch=new JSch();
+
+ try {
+ // NOTE: jsch does not support all ciphers. User may be
+ // prompted to accept host key authenticy even if
+ // the key is in the known_hosts file.
+ File knownHosts = new File(FileUtils.getHomeDir()+".ssh/known_hosts");
+ if (knownHosts.exists() && knownHosts.canRead())
+ jsch.setKnownHosts(knownHosts.getAbsolutePath());
+ ArrayList<File> privateKeys = new ArrayList<File>();
+ String sshKeyFile = cc.options.sshKeyFile.getText();
+ String sshKey = cc.viewer.sshKey.getValue();
+ if (sshKey != null) {
+ String sshKeyPass = cc.viewer.sshKeyPass.getValue();
+ byte[] keyPass = null, key;
+ if (sshKeyPass != null)
+ keyPass = sshKeyPass.getBytes();
+ sshKey = sshKey.replaceAll("\\\\n", "\n");
+ key = sshKey.getBytes();
+ jsch.addIdentity("TigerVNC", key, null, keyPass);
+ } else if (!sshKeyFile.equals("")) {
+ File f = new File(sshKeyFile);
+ if (!f.exists() || !f.canRead())
+ throw new Exception("Cannot access SSH key file "+ sshKeyFile);
+ privateKeys.add(f);
+ }
+ for (Iterator<File> i = privateKeys.iterator(); i.hasNext();) {
+ File privateKey = (File)i.next();
+ if (privateKey.exists() && privateKey.canRead())
+ if (cc.viewer.sshKeyPass.getValue() != null)
+ jsch.addIdentity(privateKey.getAbsolutePath(),
+ cc.viewer.sshKeyPass.getValue());
+ else
+ jsch.addIdentity(privateKey.getAbsolutePath());
+ }
+
+ String user = getSshUser(cc);
+ String label = new String("SSH Authentication");
+ PasswdDialog dlg =
+ new PasswdDialog(label, (user == null ? false : true), false);
+ dlg.userEntry.setText(user != null ? user : "");
+ File ssh_config = new File(cc.viewer.sshConfig.getValue());
+ if (ssh_config.exists() && ssh_config.canRead()) {
+ ConfigRepository repo =
+ OpenSSHConfig.parse(ssh_config.getAbsolutePath());
+ jsch.setConfigRepository(repo);
+ }
+ Session session=jsch.getSession(user, gatewayHost, getSshPort(cc));
+ session.setUserInfo(dlg);
+ // OpenSSHConfig doesn't recognize StrictHostKeyChecking
+ if (session.getConfig("StrictHostKeyChecking") == null)
+ session.setConfig("StrictHostKeyChecking", "ask");
+ session.connect();
+ session.setPortForwardingL(localPort, remoteHost, remotePort);
+ } catch (java.lang.Exception e) {
+ throw new Exception(e.getMessage());
+ }
+ }
+
+ private static class MyExtProcess implements Runnable {
+
+ private String cmd = null;
+ private Process pid = null;
+
+ private static class MyProcessLogger extends Thread {
+ private final BufferedReader err;
+
+ public MyProcessLogger(Process p) {
+ InputStreamReader reader =
+ new InputStreamReader(p.getErrorStream());
+ err = new BufferedReader(reader);
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ String msg = err.readLine();
+ if (msg != null)
+ vlog.info(msg);
+ }
+ } catch(java.io.IOException e) {
+ vlog.info(e.getMessage());
+ } finally {
+ try {
+ if (err != null)
+ err.close();
+ } catch (java.io.IOException e ) { }
+ }
+ }
+ }
+
+ private static class MyShutdownHook extends Thread {
+
+ private Process proc = null;
+
+ public MyShutdownHook(Process p) {
+ proc = p;
+ }
+
+ @Override
+ public void run() {
+ try {
+ proc.exitValue();
+ } catch (IllegalThreadStateException e) {
+ try {
+ // wait for CConn to shutdown the socket
+ Thread.sleep(500);
+ } catch(InterruptedException ie) { }
+ proc.destroy();
+ }
+ }
+ }
+
+ public MyExtProcess(String command) {
+ cmd = command;
+ }
+
+ public void run() {
+ try {
+ Runtime runtime = Runtime.getRuntime();
+ pid = runtime.exec(cmd);
+ runtime.addShutdownHook(new MyShutdownHook(pid));
+ new MyProcessLogger(pid).start();
+ pid.waitFor();
+ } catch(InterruptedException e) {
+ vlog.info(e.getMessage());
+ } catch(java.io.IOException e) {
+ vlog.info(e.getMessage());
+ }
+ }
+ }
+
+ private static void createTunnelExt(String gatewayHost, String remoteHost,
+ int remotePort, int localPort,
+ String pattern, CConn cc) throws Exception {
+ if (pattern == null || pattern.length() < 1) {
+ if (cc.viewer.tunnel.getValue())
+ pattern = DEFAULT_TUNNEL_TEMPLATE;
+ else
+ pattern = DEFAULT_VIA_TEMPLATE;
+ }
+ String cmd = fillCmdPattern(pattern, gatewayHost, remoteHost,
+ remotePort, localPort, cc);
+ try {
+ Thread t = new Thread(new MyExtProcess(cmd));
+ t.start();
+ // wait for the ssh process to start
+ Thread.sleep(1000);
+ } catch (java.lang.Exception e) {
+ throw new Exception(e.getMessage());
+ }
+ }
+
+ private static String fillCmdPattern(String pattern, String gatewayHost,
+ String remoteHost, int remotePort,
+ int localPort, CConn cc) {
+ boolean H_found = false, G_found = false, R_found = false, L_found = false;
+ boolean P_found = false;
+ String cmd = cc.options.sshClient.getText() + " ";
+ pattern.replaceAll("^\\s+", "");
+
+ String user = getSshUser(cc);
+ int sshPort = getSshPort(cc);
+ gatewayHost = user + "@" + gatewayHost;
+
+ for (int i = 0; i < pattern.length(); i++) {
+ if (pattern.charAt(i) == '%') {
+ switch (pattern.charAt(++i)) {
+ case 'H':
+ cmd += (cc.viewer.tunnel.getValue() ? gatewayHost : remoteHost);
+ H_found = true;
+ continue;
+ case 'G':
+ cmd += gatewayHost;
+ G_found = true;
+ continue;
+ case 'R':
+ cmd += remotePort;
+ R_found = true;
+ continue;
+ case 'L':
+ cmd += localPort;
+ L_found = true;
+ continue;
+ case 'P':
+ cmd += sshPort;
+ P_found = true;
+ continue;
+ }
+ }
+ cmd += pattern.charAt(i);
+ }
+
+ if (pattern.length() > 1024)
+ throw new Exception("Tunneling command is too long.");
+
+ if (!H_found || !R_found || !L_found)
+ throw new Exception("%H, %R or %L absent in tunneling command template.");
+
+ if (!cc.viewer.tunnel.getValue() && !G_found)
+ throw new Exception("%G pattern absent in tunneling command template.");
+
+ vlog.info("SSH command line: "+cmd);
+ if (VncViewer.os.startsWith("windows"))
+ cmd.replaceAll("\\\\", "\\\\\\\\");
+ return cmd;
+ }
+
+ static LogWriter vlog = new LogWriter("Tunnel");
+}
diff --git a/java/com/tigervnc/vncviewer/VncViewer.java b/java/com/tigervnc/vncviewer/VncViewer.java
index 3179971..fc9c7b5 100644
--- a/java/com/tigervnc/vncviewer/VncViewer.java
+++ b/java/com/tigervnc/vncviewer/VncViewer.java
@@ -168,13 +168,6 @@
continue;
}
- if (argv[i].equalsIgnoreCase("-tunnel") || argv[i].equalsIgnoreCase("-via")) {
- if (!tunnel.createTunnel(argv.length, argv, i))
- exit(1);
- if (argv[i].equalsIgnoreCase("-via")) i++;
- continue;
- }
-
if (Configuration.setParam(argv[i]))
continue;
@@ -614,30 +607,71 @@
"Produce a system beep when requested to by the server.",
true);
StringParameter via
- = new StringParameter("via",
+ = new StringParameter("Via",
"Automatically create an encrypted TCP tunnel to "+
- "machine gateway, then use that tunnel to connect "+
- "to a VNC server running on host. By default, "+
- "this option invokes SSH local port forwarding and "+
- "assumes that the SSH client binary is located at "+
- "/usr/bin/ssh. Note that when using the -via "+
- "option, the host machine name should be specified "+
- "from the point of view of the gateway machine. "+
- "For example, \"localhost\" denotes the gateway, "+
- "not the machine on which vncviewer was launched. "+
+ "the gateway machine, then connect to the VNC host "+
+ "through that tunnel. By default, this option invokes "+
+ "SSH local port forwarding using the embedded JSch "+
+ "client, however an external SSH client may be specified "+
+ "using the \"-extSSH\" parameter. Note that when using "+
+ "the -via option, the VNC host machine name should be "+
+ "specified from the point of view of the gateway machine, "+
+ "e.g. \"localhost\" denotes the gateway, "+
+ "not the machine on which the viewer was launched. "+
"See the System Properties section below for "+
- "information on configuring the -via option.",
+ "information on configuring the -Via option.", null);
+ BoolParameter tunnel
+ = new BoolParameter("Tunnel",
+ "The -Tunnel command is basically a shorthand for the "+
+ "-via command when the VNC server and SSH gateway are "+
+ "one and the same. -Tunnel creates an SSH connection "+
+ "to the server and forwards the VNC through the tunnel "+
+ "without the need to specify anything else.", false);
+ BoolParameter extSSH
+ = new BoolParameter("extSSH",
+ "By default, SSH tunneling uses the embedded JSch client "+
+ "for tunnel creation. This option causes the client to "+
+ "invoke an external SSH client application for all tunneling "+
+ "operations. By default, \"/usr/bin/ssh\" is used, however "+
+ "the path to the external application may be specified using "+
+ "the -SSHClient option.", false);
+ StringParameter extSSHClient
+ = new StringParameter("extSSHClient",
+ "Specifies the path to an external SSH client application "+
+ "that is to be used for tunneling operations when the -extSSH "+
+ "option is in effect.", "/usr/bin/ssh");
+ StringParameter extSSHArgs
+ = new StringParameter("extSSHArgs",
+ "Specifies the arguments string or command template to be used "+
+ "by the external SSH client application when the -extSSH option "+
+ "is in effect. The string will be processed according to the same "+
+ "pattern substitution rules as the VNC_TUNNEL_CMD and VNC_VIA_CMD "+
+ "system properties, and can be used to override those in a more "+
+ "command-line friendly way. If not specified, then the appropriate "+
+ "VNC_TUNNEL_CMD or VNC_VIA_CMD command template will be used.", null);
+ StringParameter sshConfig
+ = new StringParameter("SSHConfig",
+ "Specifies the path to an OpenSSH configuration file that to "+
+ "be parsed by the embedded JSch SSH client during tunneling "+
+ "operations.", FileUtils.getHomeDir()+".ssh/config");
+ StringParameter sshKey
+ = new StringParameter("SSHKey",
+ "When using the Via or Tunnel options with the embedded SSH client, "+
+ "this parameter specifies the text of the SSH private key to use when "+
+ "authenticating with the SSH server. You can use \\n within the string "+
+ "to specify a new line.", null);
+ StringParameter sshKeyFile
+ = new StringParameter("SSHKeyFile",
+ "When using the Via or Tunnel options with the embedded SSH client, "+
+ "this parameter specifies a file that contains an SSH private key "+
+ "(or keys) to use when authenticating with the SSH server. If not "+
+ "specified, ~/.ssh/id_dsa or ~/.ssh/id_rsa will be used (if they exist). "+
+ "Otherwise, the client will fallback to prompting for an SSH password.",
null);
-
- StringParameter tunnelMode
- = new StringParameter("tunnel",
- "Automatically create an encrypted TCP tunnel to "+
- "remote gateway, then use that tunnel to connect "+
- "to the specified VNC server port on the remote "+
- "host. See the System Properties section below "+
- "for information on configuring the -tunnel option.",
- null);
-
+ StringParameter sshKeyPass
+ = new StringParameter("SSHKeyPass",
+ "When using the Via or Tunnel options with the embedded SSH client, "+
+ "this parameter specifies the passphrase for the SSH key.", null);
BoolParameter customCompressLevel
= new BoolParameter("CustomCompressLevel",
"Use custom compression level. "+
diff --git a/java/com/tigervnc/vncviewer/tunnel.java b/java/com/tigervnc/vncviewer/tunnel.java
deleted file mode 100644
index 6d55fec..0000000
--- a/java/com/tigervnc/vncviewer/tunnel.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2012 Brian P. Hinz. All Rights Reserved.
- * Copyright (C) 2000 Const Kaplinsky. All Rights Reserved.
- * Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-/*
- * tunnel.java - SSH tunneling support
- */
-
-package com.tigervnc.vncviewer;
-
-import java.io.File;
-import java.lang.Character;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import com.tigervnc.rdr.*;
-import com.tigervnc.rfb.*;
-import com.tigervnc.network.*;
-
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.Session;
-
-public class tunnel
-{
- private final static Integer SERVER_PORT_OFFSET = 5900;;
- private final static String DEFAULT_SSH_CMD = "/usr/bin/ssh";
- private final static String DEFAULT_TUNNEL_CMD
- = DEFAULT_SSH_CMD+" -f -L %L:localhost:%R %H sleep 20";
- private final static String DEFAULT_VIA_CMD
- = DEFAULT_SSH_CMD+" -f -L %L:%H:%R %G sleep 20";
-
- private final static int H = 17;
- private final static int G = 16;
- private final static int R = 27;
- private final static int L = 21;
-
- /* True if there was -tunnel or -via option in the command line. */
- private static boolean tunnelSpecified = false;
-
- /* True if it was -tunnel, not -via option. */
- private static boolean tunnelOption = false;
-
- /* "Hostname:display" pair in the command line will be substituted
- by this fake argument when tunneling is used. */
- private static String lastArgv;
-
- private static String tunnelEndpoint;
-
- public static Boolean
- createTunnel(int pargc, String[] argv, int tunnelArgIndex)
- {
- char[] pattern;
- char[] cmd = new char[1024];
- int[] localPort = new int[1];
- int[] remotePort = new int[1];
- char[] localPortStr = new char[8];
- char[] remotePortStr = new char[8];
- StringBuilder gatewayHost = new StringBuilder("");
- StringBuilder remoteHost = new StringBuilder("localhost");
-
- tunnelSpecified = true;
- if (argv[tunnelArgIndex].equalsIgnoreCase("-tunnel"))
- tunnelOption = true;
-
- pattern = getCmdPattern();
- if (pattern == null)
- return false;
-
- localPort[0] = TcpSocket.findFreeTcpPort();
- if (localPort[0] == 0)
- return false;
-
- if (tunnelOption) {
- processTunnelArgs(remoteHost, remotePort, localPort,
- pargc, argv, tunnelArgIndex);
- } else {
- processViaArgs(gatewayHost, remoteHost, remotePort, localPort,
- pargc, argv, tunnelArgIndex);
- }
-
- localPortStr = Integer.toString(localPort[0]).toCharArray();
- remotePortStr = Integer.toString(remotePort[0]).toCharArray();
-
- if (!fillCmdPattern(cmd, pattern, gatewayHost.toString().toCharArray(),
- remoteHost.toString().toCharArray(), remotePortStr, localPortStr))
- return false;
-
- if (!runCommand(new String(cmd)))
- return false;
-
- return true;
- }
-
- private static void
- processTunnelArgs(StringBuilder remoteHost, int[] remotePort,
- int[] localPort, int pargc, String[] argv,
- int tunnelArgIndex)
- {
- String pdisplay;
-
- if (tunnelArgIndex >= pargc - 1)
- VncViewer.usage();
-
- pdisplay = argv[pargc - 1].split(":")[1];
- if (pdisplay == null || pdisplay == argv[pargc - 1])
- VncViewer.usage();
-
- if (pdisplay.matches("/[^0-9]/"))
- VncViewer.usage();
-
- remotePort[0] = Integer.parseInt(pdisplay);
- if (remotePort[0] < 100)
- remotePort[0] = remotePort[0] + SERVER_PORT_OFFSET;
-
- lastArgv = new String("localhost::"+localPort[0]);
-
- remoteHost.setLength(0);
- remoteHost.insert(0, argv[pargc - 1].split(":")[0]);
- argv[pargc - 1] = lastArgv;
-
- //removeArgs(pargc, argv, tunnelArgIndex, 1);
- }
-
- private static void
- processViaArgs(StringBuilder gatewayHost, StringBuilder remoteHost,
- int[] remotePort, int[] localPort,
- int pargc, String[] argv, int tunnelArgIndex)
- {
- String colonPos;
- int len, portOffset;
- int disp;
-
- if (tunnelArgIndex >= pargc - 2)
- VncViewer.usage();
-
- colonPos = argv[pargc - 1].split(":", 2)[1];
- if (colonPos == null) {
- /* No colon -- use default port number */
- remotePort[0] = SERVER_PORT_OFFSET;
- } else {
- len = colonPos.length();
- portOffset = SERVER_PORT_OFFSET;
- if (colonPos.startsWith(":")) {
- /* Two colons -- interpret as a port number */
- colonPos.replaceFirst(":", "");
- len--;
- portOffset = 0;
- }
- if (len == 0 || colonPos.matches("/[^0-9]/")) {
- VncViewer.usage();
- }
- disp = Integer.parseInt(colonPos);
- if (portOffset != 0 && disp >= 100)
- portOffset = 0;
- remotePort[0] = disp + portOffset;
- }
-
- lastArgv = "localhost::"+localPort[0];
-
- gatewayHost.setLength(0);
- gatewayHost.insert(0, argv[tunnelArgIndex + 1]);
-
- if (!argv[pargc - 1].split(":", 2)[0].equals("")) {
- remoteHost.setLength(0);
- remoteHost.insert(0, argv[pargc - 1].split(":", 2)[0]);
- }
-
- argv[pargc - 1] = lastArgv;
-
- //removeArgs(pargc, argv, tunnelArgIndex, 2);
- }
-
- private static char[]
- getCmdPattern()
- {
- String pattern = "";
-
- try {
- if (tunnelOption) {
- pattern = System.getProperty("VNC_TUNNEL_CMD");
- } else {
- pattern = System.getProperty("VNC_VIA_CMD");
- }
- } catch (java.lang.Exception e) {
- vlog.info(e.toString());
- }
- if (pattern == null || pattern.equals(""))
- pattern = (tunnelOption) ? DEFAULT_TUNNEL_CMD : DEFAULT_VIA_CMD;
-
- return pattern.toCharArray();
- }
-
- /* Note: in fillCmdPattern() result points to a 1024-byte buffer */
-
- private static boolean
- fillCmdPattern(char[] result, char[] pattern,
- char[] gatewayHost, char[] remoteHost,
- char[] remotePort, char[] localPort)
- {
- int i, j;
- boolean H_found = false, G_found = false, R_found = false, L_found = false;
-
- for (i=0, j=0; i < pattern.length && j<1023; i++, j++) {
- if (pattern[i] == '%') {
- switch (pattern[++i]) {
- case 'H':
- System.arraycopy(remoteHost, 0, result, j, remoteHost.length);
- j += remoteHost.length;
- H_found = true;
- tunnelEndpoint = new String(remoteHost);
- continue;
- case 'G':
- System.arraycopy(gatewayHost, 0, result, j, gatewayHost.length);
- j += gatewayHost.length;
- G_found = true;
- tunnelEndpoint = new String(gatewayHost);
- continue;
- case 'R':
- System.arraycopy(remotePort, 0, result, j, remotePort.length);
- j += remotePort.length;
- R_found = true;
- continue;
- case 'L':
- System.arraycopy(localPort, 0, result, j, localPort.length);
- j += localPort.length;
- L_found = true;
- continue;
- case '\0':
- i--;
- continue;
- }
- }
- result[j] = pattern[i];
- }
-
- if (pattern.length > 1024) {
- vlog.error("Tunneling command is too long.");
- return false;
- }
-
- if (!H_found || !R_found || !L_found) {
- vlog.error("%H, %R or %L absent in tunneling command.");
- return false;
- }
- if (!tunnelOption && !G_found) {
- vlog.error("%G pattern absent in tunneling command.");
- return false;
- }
-
- return true;
- }
-
- private static Boolean
- runCommand(String cmd)
- {
- try{
- JSch jsch=new JSch();
- String homeDir = new String("");
- try {
- homeDir = System.getProperty("user.home");
- } catch(java.security.AccessControlException e) {
- System.out.println("Cannot access user.home system property");
- }
- // NOTE: jsch does not support all ciphers. User may be
- // prompted to accept host key authenticy even if
- // the key is in the known_hosts file.
- File knownHosts = new File(homeDir+"/.ssh/known_hosts");
- if (knownHosts.exists() && knownHosts.canRead())
- jsch.setKnownHosts(knownHosts.getAbsolutePath());
- ArrayList<File> privateKeys = new ArrayList<File>();
- privateKeys.add(new File(homeDir+"/.ssh/id_rsa"));
- privateKeys.add(new File(homeDir+"/.ssh/id_dsa"));
- for (Iterator<File> i = privateKeys.iterator(); i.hasNext();) {
- File privateKey = (File)i.next();
- if (privateKey.exists() && privateKey.canRead())
- jsch.addIdentity(privateKey.getAbsolutePath());
- }
- // username and passphrase will be given via UserInfo interface.
- PasswdDialog dlg = new PasswdDialog(new String("SSH Authentication"), false, false);
- dlg.promptPassword(new String("SSH Authentication"));
-
- Session session=jsch.getSession(dlg.userEntry.getText(), tunnelEndpoint, 22);
- session.setPassword(new String(dlg.passwdEntry.getPassword()));
- session.connect();
-
- String[] tokens = cmd.split("\\s");
- for (int i = 0; i < tokens.length; i++) {
- if (tokens[i].equals("-L")) {
- String[] par = tokens[++i].split(":");
- int localPort = Integer.parseInt(par[0].trim());
- String remoteHost = par[1].trim();
- int remotePort = Integer.parseInt(par[2].trim());
- session.setPortForwardingL(localPort, remoteHost, remotePort);
- } else if (tokens[i].equals("-R")) {
- String[] par = tokens[++i].split(":");
- int remotePort = Integer.parseInt(par[0].trim());
- String localHost = par[1].trim();
- int localPort = Integer.parseInt(par[2].trim());
- session.setPortForwardingR(remotePort, localHost, localPort);
- }
- }
- } catch (java.lang.Exception e) {
- System.out.println(" Tunneling command failed: "+e.toString());
- return false;
- }
- return true;
- }
-
- static LogWriter vlog = new LogWriter("tunnel");
-}
diff --git a/po/ru.po b/po/ru.po
index 89db1de..a35981e 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -1,780 +1,719 @@
-# Copyright (C) 2011 TigerVNC Team
+# Russian translation for tigervnc.
+# Copyright © 2016 the TigerVNC Team (msgids)
+# This file is distributed under the same license as the tigervnc package.
+# Constantin Kaplinsky <const@tightvnc.com>, 2011.
+# PuppyRus linux team <www.puppyrus.org>.
+# Pavel Maryanov <acid@jack.kiev.ua>, 2016.
msgid ""
msgstr ""
-"Project-Id-Version: TigerVNC 0.0.91\n"
+"Project-Id-Version: tigervnc 1.5.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2014-09-22 11:15+0000\n"
-"PO-Revision-Date: 2011-11-24 13:31+0100\n"
-"Last-Translator: Constantin Kaplinsky <const@tightvnc.com>\n"
-"Language-Team: Russian\n"
-"Language: \n"
+"POT-Creation-Date: 2015-11-26 11:33+0000\n"
+"PO-Revision-Date: 2016-04-07 16:08+0300\n"
+"Last-Translator: Pavel Maryanov <acid@jack.kiev.ua>\n"
+"Language-Team: Russian <gnu@d07.ru>\n"
+"Language: ru_UA\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"X-Generator: Poedit 1.8.7.1\n"
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:194
+#: vncviewer/CConn.cxx:111
#, c-format
-msgid "(server default %s)"
-msgstr ""
+msgid "connected to host %s port %d"
+msgstr "подключен к компьютеру %s, порт %d"
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:227
-msgid "About"
-msgstr "О программе"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:103
-#, fuzzy
-msgid "About TigerVNC Viewer"
-msgstr "О VNC Viewer"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1086
-#, fuzzy
-msgid "About TigerVNC viewer..."
-msgstr "О VNC Viewer..."
-
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:86
-msgid "About..."
-msgstr "О программе..."
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:704
-msgid "Accept clipboard from server"
-msgstr "Принимать буфер обмена с сервера"
-
-#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:327
-msgid "Adjusting window size to avoid accidental full screen request"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:563
-msgid "Allow JPEG compression:"
-msgstr "Разрешить сжатие JPEG:"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1070
-msgid "Alt"
-msgstr "Alt"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:648
-msgid "Authentication"
-msgstr "Аутентификация"
-
-#: /home/ossman/devel/tigervnc/vncviewer/UserDialog.cxx:89
-msgid "Authentication cancelled"
-msgstr "Аутентификация отменена"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:437
-msgid "Auto select"
-msgstr "Автоматический выбор"
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:651
-#, c-format
-msgid "Bad Name/Value pair on line: %d in file: %s"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:92
-msgid "BitBlt failed"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:91
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:221
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:83
-msgid "Cancel"
-msgstr "Отмена"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:116
-msgid "CleanupSignalHandler called"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:222
-msgid "Close"
-msgstr "Закрыть"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:499
-msgid "Color level"
-msgstr "Уровень цветности"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:421
-#, fuzzy
-msgid "Compression"
-msgstr "Нестандартный уровень сжатия:"
-
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:96
-msgid "Connect"
-msgstr "Подключ."
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1085
-msgid "Connection info..."
-msgstr "Информация о соединении..."
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:362
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:404
-#, c-format
-msgid ""
-"Could not convert the parameter-name %s to wchar_t* when reading from the "
-"Registry, the buffersize is to small."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:302
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:340
-#, c-format
-msgid ""
-"Could not convert the parameter-name %s to wchar_t* when writing to the "
-"Registry, the buffersize is to small."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:318
-#, c-format
-msgid ""
-"Could not convert the parameter-value %s to wchar_t* when writing to the "
-"Registry, the buffersize is to small."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:381
-#, c-format
-msgid ""
-"Could not convert the parameter-value for %s to utf8 char* when reading from "
-"the Registry, the buffer dest is to small."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:256
-#, c-format
-msgid "Could not create VNC home directory: %s."
-msgstr "Не удается создать домашний каталог VNC: %s."
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:251
-msgid "Could not create VNC home directory: can't obtain home directory path."
-msgstr ""
-"Не удается создать домашний каталог VNC: не удается получить путь к "
-"домашнему каталогу."
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:310
-#, c-format
-msgid "Could not encode the parameter-value %s when writing to the Registry."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:613
-#, c-format
-msgid ""
-"Could not read the line(%d) in the configuration file,the buffersize is to "
-"small."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:80
-msgid "CreateCompatibleDC failed"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1068
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:550
-msgid "Custom compression level:"
-msgstr "Нестандартный уровень сжатия:"
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:283
-msgid ""
-"Decoding: The size of the buffer dest is to small, it needs to be 1 byte "
-"bigger."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:172
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Desktop name: %.80s"
-msgstr ""
+msgstr "Имя компьютера: %.80s"
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1088
-msgid "Dismiss menu"
-msgstr "Закрыть меню"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:778
-msgid "Enable full-screen mode over all monitors"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:469
-msgid "Enabling continuous updates"
-msgstr "Включение регулярного обновления"
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:200
-#, c-format
-msgid ""
-"Encoding backslash: The size of the buffer dest is to small, it needs to be "
-"more than %d bytes bigger."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:214
-#, c-format
-msgid ""
-"Encoding escape sequence: The size of the buffer dest is to small, it needs "
-"to be more than %d bytes bigger."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:234
-#, c-format
-msgid ""
-"Encoding normal character: The size of the buffer dest is to small, it needs "
-"to be more than %d bytes bigger."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:595
-msgid "Encryption"
-msgstr "Шифрование"
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:503
-#, c-format
-msgid "Error(%d) closing key: Software\\TigerVNC\\vncviewer"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:455
-#, c-format
-msgid "Error(%d) closing key: Software\\TigerVNC\\vncviewer"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:434
-#, c-format
-msgid "Error(%d) creating key: Software\\TigerVNC\\vncviewer"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:471
-#, c-format
-msgid "Error(%d) opening key: Software\\TigerVNC\\vncviewer"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:373
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:415
-#, c-format
-msgid "Error(%d) reading %s from Registry."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:348
-#, c-format
-msgid "Error(%d) writing %d(REG_DWORD) to Registry."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:326
-#, c-format
-msgid "Error(%d) writing %s(REG_SZ) to Registry."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/OSXPixelBuffer.cxx:50
-#: /home/ossman/devel/tigervnc/vncviewer/FLTKPixelBuffer.cxx:33
-msgid "Error: Not enough memory for framebuffer"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:69
-msgid "Error: couldn't find suitable pixmap format"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:60
-msgid "Error: display lacks pixmap format for default depth"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:78
-msgid "Error: only true colour displays supported"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1056
-msgid "Exit viewer"
-msgstr "Выход"
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:588
-#, fuzzy
-msgid "Failed to read configuration file, can't obtain home directory path."
-msgstr ""
-"Не удается создать домашний каталог VNC: не удается получить путь к "
-"домашнему каталогу."
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:602
-#, c-format
-msgid "Failed to read configuration file, can't open %s"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:621
-#, c-format
-msgid "Failed to read line %d in file %s"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:528
-#, fuzzy
-msgid "Failed to write configuration file, can't obtain home directory path."
-msgstr ""
-"Не удается создать домашний каталог VNC: не удается получить путь к "
-"домашнему каталогу."
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:542
-#, c-format
-msgid "Failed to write configuration file, can't open %s"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:526
-#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:538
-#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:551
-msgid "Failure grabbing keyboard"
-msgstr "Ошибка при перехвате для клавиатуры"
-
-#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:563
-msgid "Failure grabbing mouse"
-msgstr "Ошибка при перехвате для мыши"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:512
-msgid "Full (all available colors)"
-msgstr "Многоцветный режим (все доступные цвета)"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1059
-msgid "Full screen"
-msgstr "Полноэкранный режим"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:770
-msgid "Full-screen mode"
-msgstr "Полноэкранный режим"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:230
-msgid "Hide"
-msgstr "Скрыть"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:238
-msgid "Hide Others"
-msgstr "Скрыть прочее"
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:177
+#: vncviewer/CConn.cxx:178
#, c-format
msgid "Host: %.80s port: %d"
-msgstr ""
+msgstr "Компьютер: %.80s порт: %d"
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:690
-#, fuzzy
-msgid "Input"
-msgstr "Ввод:"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:510
-msgid "Internal FLTK error. Exiting."
-msgstr "Внутренняя ошибка FLTK. Выполняется выход."
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:384
-msgid "Invalid SetColourMapEntries from server!"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:106
-msgid "Invalid geometry specified!"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:708
+#: vncviewer/CConn.cxx:183
#, c-format
-msgid "Invalid parameter name on line: %d in file: %s"
-msgstr ""
+msgid "Size: %d x %d"
+msgstr "Размер: %d x %d"
-#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:797
-msgid "Invalid screen layout computed for resize request!"
-msgstr ""
+#: vncviewer/CConn.cxx:191
+#, c-format
+msgid "Pixel format: %s"
+msgstr "Формат пикселей: %s"
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:204
-#, fuzzy, c-format
+#: vncviewer/CConn.cxx:198
+#, c-format
+msgid "(server default %s)"
+msgstr "(сервер по умолчанию %s)"
+
+#: vncviewer/CConn.cxx:203
+#, c-format
+msgid "Requested encoding: %s"
+msgstr "Запрошено кодирование: %s"
+
+#: vncviewer/CConn.cxx:208
+#, c-format
msgid "Last used encoding: %s"
-msgstr "Использование кодирования %s"
+msgstr "Используется кодирование: %s"
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:631
-#, c-format
-msgid ""
-"Line 1 in file %s\n"
-"must contain the TigerVNC configuration file identifier string:\n"
-"\"%s\""
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:209
+#: vncviewer/CConn.cxx:213
#, c-format
msgid "Line speed estimate: %d kbit/s"
-msgstr ""
+msgstr "Скорость соединения: %d кбит/с"
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:478
-#, c-format
-msgid "Listening on port %d\n"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:69
-msgid "Load..."
-msgstr "Загрузка..."
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:526
-msgid "Low (64 colors)"
-msgstr "Низкое качество цвета (64 цвета)"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:519
-msgid "Medium (256 colors)"
-msgstr "Среднее качество цвета (256 цветов)"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:725
-msgid "Menu key"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:791
-msgid "Misc."
-msgstr "Разное"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1026
-#, c-format
-msgid "Multiple characters given for key code %d (0x%04x): '%s'"
-msgstr "Несколько символов для кода ключа %d (0x%04x): '%s'"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:218
-msgid "No"
-msgstr "Нет"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:688
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:690
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:701
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:765
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:739
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:703
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:606
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:659
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:727
-msgid "None"
-msgstr "Нет"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:220
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:88
-msgid "OK"
-msgstr "OK"
-
-#: /home/ossman/devel/tigervnc/vncviewer/UserDialog.cxx:74
-msgid "Opening password file failed"
-msgstr "Ошибка при открытии файла с паролем"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1084
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:64
-msgid "Options..."
-msgstr "Параметры..."
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:463
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:464
-msgid "Parameters -listen and -via are incompatible"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:722
-msgid "Pass system keys directly to server (full screen)"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/UserDialog.cxx:87
-#: /home/ossman/devel/tigervnc/vncviewer/UserDialog.cxx:102
-msgid "Password:"
-msgstr "Пароль:"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:625
-msgid "Path to X509 CA certificate"
-msgstr "Путь к сертификату X509 CA"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:632
-msgid "Path to X509 CRL file"
-msgstr "Путь к файлу X509 CRL"
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:188
-#, fuzzy, c-format
-msgid "Pixel format: %s"
-msgstr "Использование формата точек %s"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:449
-msgid "Preferred encoding"
-msgstr "Предпочтительное кодирование"
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:214
+#: vncviewer/CConn.cxx:218
#, c-format
msgid "Protocol version: %d.%d"
-msgstr ""
+msgstr "Версия протокола: %d.%d"
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:233
-msgid "Quit"
-msgstr "Выход"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1082
-msgid "Refresh screen"
-msgstr "Обновить экран"
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:199
-#, fuzzy, c-format
-msgid "Requested encoding: %s"
-msgstr "Предпочтительное кодирование"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:749
-msgid "Resize remote session on connect"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:762
-msgid "Resize remote session to the local window"
-msgstr "Изменить размер удалённой сессии до местного окна"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1062
-msgid "Resize window to session"
-msgstr "Изменить размер окна сессии"
-
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:74
-msgid "Save As..."
-msgstr "Сохранить как..."
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:741
-msgid "Screen"
-msgstr "Экран"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:580
-msgid "Security"
-msgstr "Безопасность"
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:219
+#: vncviewer/CConn.cxx:223
#, c-format
msgid "Security method: %s"
-msgstr ""
+msgstr "Метод защиты: %s"
-#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:83
-msgid "SelectObject failed"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1075
-#, c-format
-msgid "Send %s"
-msgstr "Послать %s"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1080
-msgid "Send Ctrl-Alt-Del"
-msgstr "Послать Ctrl-Alt-Del"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:710
-msgid "Send clipboard to server"
-msgstr "Посылать буфер обмена на сервер"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:716
-#, fuzzy
-msgid "Send primary selection and cut buffer as clipboard"
-msgstr "Посылать \"primary selection\" и \"cut buffer\" как буфер обмена"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:237
-msgid "Services"
-msgstr "Службы"
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:319
+#: vncviewer/CConn.cxx:329
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "Ошибка SetDesktopSize: %d"
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:799
-msgid "Shared (don't disconnect other viewers)"
-msgstr "Разделяемый режим (не отключать других клиентов)"
+#: vncviewer/CConn.cxx:398
+msgid "Invalid SetColourMapEntries from server!"
+msgstr "С сервера получен недопустмый SetColourMapEntries"
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:239
-msgid "Show All"
-msgstr "Показать все"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:805
-msgid "Show dot when no cursor"
-msgstr "Показывать точку при отсутствии курсора"
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:182
+#. TRANSLATORS: Refers to a VNC protocol encoding type
+#: vncviewer/CConn.cxx:444 vncviewer/CConn.cxx:451
#, c-format
-msgid "Size: %d x %d"
-msgstr ""
+msgid "Unknown encoding %d"
+msgstr "Неизвестное кодирование %d"
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:665
-msgid "Standard VNC (insecure without encryption)"
-msgstr "Стандартный VNC (без защиты и шифрования)"
+#: vncviewer/CConn.cxx:445 vncviewer/CConn.cxx:452
+msgid "Unknown encoding"
+msgstr "Неизвестное кодирование"
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:618
-msgid "TLS with X509 certificates"
-msgstr "TLS с сертификатами X509"
+#: vncviewer/CConn.cxx:484
+msgid "Enabling continuous updates"
+msgstr "Включение непрерывного обновления"
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:612
+#: vncviewer/CConn.cxx:554
+#, c-format
+msgid "Throughput %d kbit/s - changing to quality %d"
+msgstr "Пропускная способность %d кбит/с. Установлено качество %d"
+
+#: vncviewer/CConn.cxx:576
+#, c-format
+msgid "Throughput %d kbit/s - full color is now %s"
+msgstr "Пропускная способность %d кбит/с. Глубина цвета %s"
+
+#: vncviewer/CConn.cxx:578
+msgid "disabled"
+msgstr "отключено"
+
+#: vncviewer/CConn.cxx:578
+msgid "enabled"
+msgstr "включено"
+
+#: vncviewer/CConn.cxx:588
+#, c-format
+msgid "Using %s encoding"
+msgstr "Используется кодирование %s"
+
+#: vncviewer/CConn.cxx:635
+#, c-format
+msgid "Using pixel format %s"
+msgstr "Используется формат пикселей %s"
+
+#: vncviewer/DesktopWindow.cxx:106
+msgid "Invalid geometry specified!"
+msgstr "Указан недопустимый размер экрана."
+
+#: vncviewer/DesktopWindow.cxx:309
+msgid "Adjusting window size to avoid accidental full screen request"
+msgstr "Зафиксировать размер окна, чтобы исключить переключения на полный экран"
+
+#: vncviewer/DesktopWindow.cxx:491 vncviewer/DesktopWindow.cxx:497
+#: vncviewer/DesktopWindow.cxx:510
+msgid "Failure grabbing keyboard"
+msgstr "Не удалось перехватить клавиатуру"
+
+#: vncviewer/DesktopWindow.cxx:522
+msgid "Failure grabbing mouse"
+msgstr "Не удалось перехватить мышь"
+
+#: vncviewer/DesktopWindow.cxx:752
+msgid "Invalid screen layout computed for resize request!"
+msgstr "Для запроса на изменение рамера рассчитан недопустимый макет экрана."
+
+#: vncviewer/FLTKPixelBuffer.cxx:33 vncviewer/OSXPixelBuffer.cxx:48
+#: vncviewer/X11PixelBuffer.cxx:113
+msgid "Not enough memory for framebuffer"
+msgstr "Недостаточно памяти для framebuffer"
+
+#: vncviewer/OSXPixelBuffer.cxx:52
+msgid "Could not create framebuffer device"
+msgstr "Не удалось создать устройство framebuffer"
+
+#: vncviewer/OSXPixelBuffer.cxx:58
+msgid "Could not create framebuffer bitmap"
+msgstr "Не удалось создать framebuffer bitmap"
+
+#: vncviewer/OptionsDialog.cxx:57
+msgid "VNC Viewer: Connection Options"
+msgstr "VNC Viewer: параметры соединения"
+
+#: vncviewer/OptionsDialog.cxx:83 vncviewer/ServerDialog.cxx:91
+#: vncviewer/vncviewer.cxx:268
+msgid "Cancel"
+msgstr "Отмена"
+
+#: vncviewer/OptionsDialog.cxx:88 vncviewer/vncviewer.cxx:267
+msgid "OK"
+msgstr "ОК"
+
+#: vncviewer/OptionsDialog.cxx:413
+msgid "Compression"
+msgstr "Сжатие"
+
+#: vncviewer/OptionsDialog.cxx:429
+msgid "Auto select"
+msgstr "Автоматический выбор"
+
+#: vncviewer/OptionsDialog.cxx:441
+msgid "Preferred encoding"
+msgstr "Вид кодирования"
+
+#: vncviewer/OptionsDialog.cxx:489
+msgid "Color level"
+msgstr "Глубина цвета"
+
+#: vncviewer/OptionsDialog.cxx:500
+msgid "Full (all available colors)"
+msgstr "Полная (все цвета)"
+
+#: vncviewer/OptionsDialog.cxx:507
+msgid "Medium (256 colors)"
+msgstr "Средняя (256 цветов)"
+
+#: vncviewer/OptionsDialog.cxx:514
+msgid "Low (64 colors)"
+msgstr "Низкая (64 цвета)"
+
+#: vncviewer/OptionsDialog.cxx:521
+msgid "Very low (8 colors)"
+msgstr "Минимум цвета (8 цветов)"
+
+#: vncviewer/OptionsDialog.cxx:538
+msgid "Custom compression level:"
+msgstr "Задать уровень сжатия:"
+
+#: vncviewer/OptionsDialog.cxx:544
+msgid "level (1=fast, 6=best [4-6 are rarely useful])"
+msgstr "уровень (1=мин, 6=макс. [4-6 используются редко])"
+
+#: vncviewer/OptionsDialog.cxx:551
+msgid "Allow JPEG compression:"
+msgstr "Разрешить сжатие JPEG:"
+
+#: vncviewer/OptionsDialog.cxx:557
+msgid "quality (0=poor, 9=best)"
+msgstr "качество (0=наихудшее, 9=наилучшее)"
+
+#: vncviewer/OptionsDialog.cxx:568
+msgid "Security"
+msgstr "Безопасность"
+
+#: vncviewer/OptionsDialog.cxx:583
+msgid "Encryption"
+msgstr "Шифрование"
+
+#: vncviewer/OptionsDialog.cxx:594 vncviewer/OptionsDialog.cxx:647
+#: vncviewer/OptionsDialog.cxx:715
+msgid "None"
+msgstr "Нет"
+
+#: vncviewer/OptionsDialog.cxx:600
msgid "TLS with anonymous certificates"
msgstr "TLS с анонимными сертификатами"
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:448
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:497
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:561
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:701
+#: vncviewer/OptionsDialog.cxx:606
+msgid "TLS with X509 certificates"
+msgstr "TLS с сертификатами X509"
+
+#: vncviewer/OptionsDialog.cxx:613
+msgid "Path to X509 CA certificate"
+msgstr "Путь к сертификату X509 CA"
+
+#: vncviewer/OptionsDialog.cxx:620
+msgid "Path to X509 CRL file"
+msgstr "Путь к файлу X509 CRL"
+
+#: vncviewer/OptionsDialog.cxx:636
+msgid "Authentication"
+msgstr "Авторизация"
+
+#: vncviewer/OptionsDialog.cxx:653
+msgid "Standard VNC (insecure without encryption)"
+msgstr "Стандартный VNC (без защиты и шифрования)"
+
+#: vncviewer/OptionsDialog.cxx:659
+msgid "Username and password (insecure without encryption)"
+msgstr "Имя пользователя и пароль (без защиты и шифрования)"
+
+#: vncviewer/OptionsDialog.cxx:678
+msgid "Input"
+msgstr "Ввод"
+
+#: vncviewer/OptionsDialog.cxx:686
+msgid "View only (ignore mouse and keyboard)"
+msgstr "Только просмотр (не перехватывать мышь и клавиатуру)"
+
+#: vncviewer/OptionsDialog.cxx:692
+msgid "Accept clipboard from server"
+msgstr "Принимать буфер обмена с сервера"
+
+#: vncviewer/OptionsDialog.cxx:698
+msgid "Send clipboard to server"
+msgstr "Отправлять буфер обмена на сервер"
+
+#: vncviewer/OptionsDialog.cxx:704
+msgid "Send primary selection and cut buffer as clipboard"
+msgstr "Отправлять выделение в терминале в буфер обмена сервера"
+
+#: vncviewer/OptionsDialog.cxx:710
+msgid "Pass system keys directly to server (full screen)"
+msgstr "Отправлять сочетания клавиш (для полного экрана)"
+
+#: vncviewer/OptionsDialog.cxx:713
+msgid "Menu key"
+msgstr "Вызов меню:"
+
+#: vncviewer/OptionsDialog.cxx:729
+msgid "Screen"
+msgstr "Экран"
+
+#: vncviewer/OptionsDialog.cxx:737
+msgid "Resize remote session on connect"
+msgstr "Изменить размер удалённого экрана"
+
+#: vncviewer/OptionsDialog.cxx:750
+msgid "Resize remote session to the local window"
+msgstr "Изменить размер удалённого сеанса до локального окна"
+
+#: vncviewer/OptionsDialog.cxx:756
+msgid "Full-screen mode"
+msgstr "Полноэкранный режим"
+
+#: vncviewer/OptionsDialog.cxx:762
+msgid "Enable full-screen mode over all monitors"
+msgstr "Расширить режим полного экрана на все мониторы"
+
+#: vncviewer/OptionsDialog.cxx:771
+msgid "Misc."
+msgstr "Разное"
+
+#: vncviewer/OptionsDialog.cxx:779
+msgid "Shared (don't disconnect other viewers)"
+msgstr "Совместная работа (не отключать других клиентов)"
+
+#: vncviewer/OptionsDialog.cxx:785
+msgid "Show dot when no cursor"
+msgstr "Показывать точку при отсутствии курсора"
+
+#: vncviewer/ServerDialog.cxx:42
+msgid "VNC Viewer: Connection Details"
+msgstr "VNC Viewer: информация о соединении"
+
+#: vncviewer/ServerDialog.cxx:49 vncviewer/ServerDialog.cxx:54
+msgid "VNC server:"
+msgstr "Сервер VNC:"
+
+#: vncviewer/ServerDialog.cxx:64
+msgid "Options..."
+msgstr "Параметры"
+
+#: vncviewer/ServerDialog.cxx:69
+msgid "Load..."
+msgstr "Загрузить"
+
+#: vncviewer/ServerDialog.cxx:74
+msgid "Save As..."
+msgstr "Сохранить"
+
+#: vncviewer/ServerDialog.cxx:86
+msgid "About..."
+msgstr "О программе"
+
+#: vncviewer/ServerDialog.cxx:96
+msgid "Connect"
+msgstr "Подключ."
+
+#: vncviewer/UserDialog.cxx:74
+msgid "Opening password file failed"
+msgstr "Не удалось открыть файл с паролем"
+
+#: vncviewer/UserDialog.cxx:86 vncviewer/UserDialog.cxx:96
+msgid "VNC authentication"
+msgstr "Авторизация VNC"
+
+#: vncviewer/UserDialog.cxx:87 vncviewer/UserDialog.cxx:102
+msgid "Password:"
+msgstr "Пароль:"
+
+#: vncviewer/UserDialog.cxx:89
+msgid "Authentication cancelled"
+msgstr "Авторизация отменена"
+
+#: vncviewer/UserDialog.cxx:99
+msgid "Username:"
+msgstr "Имя пользователя:"
+
+#: vncviewer/Viewport.cxx:433
#, c-format
-msgid "The parameterArray contains a object of a invalid type at line %d."
-msgstr ""
+msgid "Unable to create platform specific framebuffer: %s"
+msgstr "Не удаётся создать framebuffer: %s"
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:664
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:680
+#: vncviewer/Viewport.cxx:434
+msgid "Using platform independent framebuffer"
+msgstr "Используется универсальный framebuffer"
+
+#: vncviewer/Viewport.cxx:668
#, c-format
-msgid "The value of the parameter %s on line %d in file %s is invalid."
-msgstr ""
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Нет скан-кода для дополнительной виртуальной клавиши 0x%02x"
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:539
+#: vncviewer/Viewport.cxx:670
#, c-format
-msgid "Throughput %d kbit/s - changing to quality %d"
-msgstr "Пропускная способность %d Кбит/с - изменяется на качество %d"
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Нет скан-кода для виртуальной клавиши 0x%02x"
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:561
+#: vncviewer/Viewport.cxx:687
#, c-format
-msgid "Throughput %d kbit/s - full color is now %s"
-msgstr "Пропускная способность %d Кбит/с - теперь полноцветный режим %s"
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Нет символа для расширенной виртуальной клавиши 0x%02x"
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:210
-#, fuzzy
-msgid "TigerVNC Viewer"
-msgstr "О VNC Viewer"
+#: vncviewer/Viewport.cxx:689
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Нет символа для виртуальной клавиши 0x%02x"
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:80
-#, fuzzy, c-format
+#: vncviewer/Viewport.cxx:727
+#, c-format
+msgid "No symbol for key code 0x%02x (in the current state)"
+msgstr "Нет символа для кода клавиши 0x%02x (в текущем состоянии)"
+
+#: vncviewer/Viewport.cxx:753
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Нет символа для кода клавиши %d (в текущем состоянии)"
+
+#: vncviewer/Viewport.cxx:790
+msgctxt "ContextMenu|"
+msgid "E&xit viewer"
+msgstr "В&ыход"
+
+#: vncviewer/Viewport.cxx:793
+msgctxt "ContextMenu|"
+msgid "&Full screen"
+msgstr "&Полный экран"
+
+#: vncviewer/Viewport.cxx:796
+msgctxt "ContextMenu|"
+msgid "Minimi&ze"
+msgstr "&Свернуть"
+
+#: vncviewer/Viewport.cxx:798
+msgctxt "ContextMenu|"
+msgid "Resize &window to session"
+msgstr "Изменить размер окна"
+
+#: vncviewer/Viewport.cxx:803
+msgctxt "ContextMenu|"
+msgid "&Ctrl"
+msgstr "&CTRL"
+
+#: vncviewer/Viewport.cxx:806
+msgctxt "ContextMenu|"
+msgid "&Alt"
+msgstr "&ALT"
+
+#: vncviewer/Viewport.cxx:812
+#, c-format
+msgctxt "ContextMenu|"
+msgid "Send %s"
+msgstr "Отправить %s"
+
+#: vncviewer/Viewport.cxx:818
+msgctxt "ContextMenu|"
+msgid "Send Ctrl-Alt-&Del"
+msgstr "Отправить CTRL-ALT-&DEL"
+
+#: vncviewer/Viewport.cxx:821
+msgctxt "ContextMenu|"
+msgid "&Refresh screen"
+msgstr "&Обновить экран"
+
+#: vncviewer/Viewport.cxx:824
+msgctxt "ContextMenu|"
+msgid "&Options..."
+msgstr "&Параметры"
+
+#: vncviewer/Viewport.cxx:826
+msgctxt "ContextMenu|"
+msgid "Connection &info..."
+msgstr "Сведения о соединении"
+
+#: vncviewer/Viewport.cxx:828
+msgctxt "ContextMenu|"
+msgid "About &TigerVNC viewer..."
+msgstr "О &TigerVNC viewer"
+
+#: vncviewer/Viewport.cxx:831
+msgctxt "ContextMenu|"
+msgid "Dismiss &menu"
+msgstr "Закрыть &меню"
+
+#: vncviewer/Viewport.cxx:915
+msgid "VNC connection info"
+msgstr "Сведения о соединении VNC"
+
+#: vncviewer/Win32PixelBuffer.cxx:62
+msgid "unable to create DIB section"
+msgstr "не удаётся создать выбор DIB"
+
+#: vncviewer/Win32PixelBuffer.cxx:79
+msgid "CreateCompatibleDC failed"
+msgstr "Ошибка CreateCompatibleDC"
+
+#: vncviewer/Win32PixelBuffer.cxx:82
+msgid "SelectObject failed"
+msgstr "Ошибка SelectObject"
+
+#: vncviewer/Win32PixelBuffer.cxx:91
+msgid "BitBlt failed"
+msgstr "Ошибка BitBlt"
+
+#. TRANSLATORS: "pixmap" is an X11 concept and may not be suitable
+#. to translate.
+#: vncviewer/X11PixelBuffer.cxx:61
+msgid "Display lacks pixmap format for default depth"
+msgstr "Неправильный формат pixmap для выбранной глубины цвета"
+
+#. TRANSLATORS: "pixmap" is an X11 concept and may not be suitable
+#. to translate.
+#: vncviewer/X11PixelBuffer.cxx:72
+msgid "Couldn't find suitable pixmap format"
+msgstr "Не удалось найти допустимый формат pixmap"
+
+#: vncviewer/X11PixelBuffer.cxx:81
+msgid "Only true colour displays supported"
+msgstr "Поддерживаются только полноцветные экраны"
+
+#: vncviewer/X11PixelBuffer.cxx:83
+#, c-format
+msgid "Using default colormap and visual, TrueColor, depth %d."
+msgstr "Используется стандартная цветовая карта и визуальное оформление, TrueColor, глубина %d."
+
+#: vncviewer/X11PixelBuffer.cxx:109
+msgid "Could not create framebuffer image"
+msgstr "Не удалось создать изображение в framebuffer"
+
+#: vncviewer/parameters.cxx:279 vncviewer/parameters.cxx:313
+#, c-format
+msgid "The name of the parameter %s was too large to write to the registry"
+msgstr "Название параметра %s слишком длинное для записи в реестр"
+
+#: vncviewer/parameters.cxx:285 vncviewer/parameters.cxx:292
+#, c-format
+msgid "The parameter %s was too large to write to the registry"
+msgstr "Параметр %s слишком длинный для записи в реестр"
+
+#: vncviewer/parameters.cxx:298 vncviewer/parameters.cxx:319
+#, c-format
+msgid "Failed to write parameter %s of type %s to the registry: %ld"
+msgstr "Не удалось записать параметр %s типа %s в реестр: %ld"
+
+#: vncviewer/parameters.cxx:334 vncviewer/parameters.cxx:373
+#, c-format
+msgid "The name of the parameter %s was too large to read from the registry"
+msgstr "Название параметра %s слишком длинное для чтения из реестра"
+
+#: vncviewer/parameters.cxx:343 vncviewer/parameters.cxx:382
+#, c-format
+msgid "Failed to read parameter %s from the registry: %ld"
+msgstr "Не удалось прочитать параметр %s из реестра: %ld"
+
+#: vncviewer/parameters.cxx:352
+#, c-format
+msgid "The parameter %s was too large to read from the registry"
+msgstr "Параметр %s слишком длинный для чтения из реестра"
+
+#: vncviewer/parameters.cxx:402
+#, c-format
+msgid "Failed to create registry key: %ld"
+msgstr "Не удалось создать ключ реестра: %ld"
+
+#: vncviewer/parameters.cxx:416 vncviewer/parameters.cxx:465
+#: vncviewer/parameters.cxx:527 vncviewer/parameters.cxx:658
+#, c-format
+msgid "Unknown parameter type for parameter %s"
+msgstr "Неизвестный тип для параметра %s"
+
+#: vncviewer/parameters.cxx:423 vncviewer/parameters.cxx:472
+#, c-format
+msgid "Failed to close registry key: %ld"
+msgstr "Не удалось закрыть ключ реестра: %ld"
+
+#: vncviewer/parameters.cxx:439
+#, c-format
+msgid "Failed to open registry key: %ld"
+msgstr "Не удалось открыть ключ реестра: %ld"
+
+#: vncviewer/parameters.cxx:496
+msgid "Failed to write configuration file, can't obtain home directory path."
+msgstr "Не удалось создать домашний каталог VNC: не удаётся получить путь к домашнему каталогу."
+
+#: vncviewer/parameters.cxx:509
+#, c-format
+msgid "Failed to write configuration file, can't open %s: %s"
+msgstr "Не удалось записать файл конфигурации: не удаётся открыть %s: %s"
+
+#: vncviewer/parameters.cxx:552
+msgid "Failed to read configuration file, can't obtain home directory path."
+msgstr "Не удалось прочитать файл конфигурации: не удаётся получить путь к домашнему каталогу."
+
+#: vncviewer/parameters.cxx:565
+#, c-format
+msgid "Failed to read configuration file, can't open %s: %s"
+msgstr "Не удалось прочитать файл конфигурации: не удаётся открыть %s: %s"
+
+#: vncviewer/parameters.cxx:578 vncviewer/parameters.cxx:583
+#: vncviewer/parameters.cxx:608 vncviewer/parameters.cxx:621
+#: vncviewer/parameters.cxx:637
+#, c-format
+msgid "Failed to read line %d in file %s: %s"
+msgstr "Не удалось прочитать строку %d из файла %s: %s"
+
+#: vncviewer/parameters.cxx:584
+msgid "Line too long"
+msgstr "Строка слишком длинная"
+
+#: vncviewer/parameters.cxx:591
+#, c-format
+msgid "Configuration file %s is in an invalid format"
+msgstr "Недопустимый формат файла конфигурации %s"
+
+#: vncviewer/parameters.cxx:609
+msgid "Invalid format"
+msgstr "Недопустимый формат"
+
+#: vncviewer/parameters.cxx:622 vncviewer/parameters.cxx:638
+msgid "Invalid format or too large value"
+msgstr "Недопустимый формат или слишком большое значение"
+
+#: vncviewer/parameters.cxx:665
+#, c-format
+msgid "Unknown parameter %s on line %d in file %s"
+msgstr "Неизвестный параметр %s в строке %d файла %s"
+
+#: vncviewer/vncviewer.cxx:100
+#, c-format
msgid ""
"TigerVNC Viewer %d-bit v%s\n"
"Built on: %s\n"
"Copyright (C) 1999-%d TigerVNC Team and many others (see README.txt)\n"
"See http://www.tigervnc.org for information on TigerVNC."
msgstr ""
-"TigerVNC Viewer %d-bit версия %s (%s)\n"
-"%s\n"
-"Copyright (C) 1999-2011 TigerVNC Team and many others (see README.txt)\n"
-"Ищите информацию о TigerVNC на сайте http://www.tigervnc.org"
+"TigerVNC Viewer (%d-разрядная версия) %s\n"
+"Сборка от: %s\n"
+"© 1999-%d, TigerVNC Team и многие другие (см. README.txt).\n"
+"Информацию о TigerVNC на сайте http://www.tigervnc.org"
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1004
+#: vncviewer/vncviewer.cxx:127
+msgid "About TigerVNC Viewer"
+msgstr "О TigerVNC viewer"
+
+#: vncviewer/vncviewer.cxx:144 vncviewer/vncviewer.cxx:156
#, c-format
-msgid "Unknown FLTK key code %d (0x%04x)"
-msgstr "Неизвестный код ключа FLTK %d (0x%04x)"
+msgid "Error starting new TigerVNC Viewer: %s"
+msgstr "Не удалось запустить новый TigerVNC Viewer: %s"
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:878
+#: vncviewer/vncviewer.cxx:165
#, c-format
-msgid "Unknown decimal separator: '%s'"
-msgstr "Неизвестный десятичный разделитель: '%s'"
+msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgstr "Получен сигнал завершения работы %d. TigerVNC Viewer будет закрыт."
-#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:271
-#, fuzzy, c-format
-msgid "Unknown escape sequence at character %d"
-msgstr "Неизвестный десятичный разделитель: '%s'"
+#: vncviewer/vncviewer.cxx:257
+msgid "TigerVNC Viewer"
+msgstr "TigerVNC Viewer"
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:430
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:437
-#, fuzzy
-msgid "Unknown rect encoding"
-msgstr "Использование кодирования %s"
+#: vncviewer/vncviewer.cxx:265
+msgid "No"
+msgstr "Нет"
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:429
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:436
-#, c-format
-msgid "Unknown rect encoding %d"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:671
-msgid "Username and password (insecure without encryption)"
-msgstr "Имя пользователя и пароль (без защиты и шифрования)"
-
-#: /home/ossman/devel/tigervnc/vncviewer/UserDialog.cxx:99
-msgid "Username:"
-msgstr "Имя пользователя:"
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:573
-#, c-format
-msgid "Using %s encoding"
-msgstr "Использование кодирования %s"
-
-#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:80
-#, c-format
-msgid "Using default colormap and visual, %sdepth %d."
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:620
-#, c-format
-msgid "Using pixel format %s"
-msgstr "Использование формата точек %s"
-
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:42
-msgid "VNC Viewer: Connection Details"
-msgstr "VNC Viewer: детали соединения"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:57
-msgid "VNC Viewer: Connection Options"
-msgstr "VNC Viewer: параметры соединения"
-
-#: /home/ossman/devel/tigervnc/vncviewer/UserDialog.cxx:86
-#: /home/ossman/devel/tigervnc/vncviewer/UserDialog.cxx:96
-msgid "VNC authentication"
-msgstr "Аутентификация VNC"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1176
-msgid "VNC connection info"
-msgstr "Информация о соединении VNC"
-
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:49
-#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:54
-msgid "VNC server:"
-msgstr "Сервер VNC:"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:533
-msgid "Very low (8 colors)"
-msgstr "Минимум цвета (8 цветов)"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:698
-#, fuzzy
-msgid "View only (ignore mouse and keyboard)"
-msgstr "Только просмотр (игнорировать мышь и клавиатуру)"
-
-#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:219
+#: vncviewer/vncviewer.cxx:266
msgid "Yes"
msgstr "Да"
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:111
+#: vncviewer/vncviewer.cxx:269
+msgid "Close"
+msgstr "Закрыть"
+
+#: vncviewer/vncviewer.cxx:274
+msgid "About"
+msgstr "О программе"
+
+#: vncviewer/vncviewer.cxx:277
+msgid "Hide"
+msgstr "Скрыть"
+
+#: vncviewer/vncviewer.cxx:280
+msgid "Quit"
+msgstr "Выход"
+
+#: vncviewer/vncviewer.cxx:284
+msgid "Services"
+msgstr "Службы"
+
+#: vncviewer/vncviewer.cxx:285
+msgid "Hide Others"
+msgstr "Скрыть прочее"
+
+#: vncviewer/vncviewer.cxx:286
+msgid "Show All"
+msgstr "Показать все"
+
+#: vncviewer/vncviewer.cxx:295
+msgctxt "SysMenu|"
+msgid "&File"
+msgstr "&Файл"
+
+#: vncviewer/vncviewer.cxx:298
+msgctxt "SysMenu|File|"
+msgid "&New Connection"
+msgstr "&Новое соединение"
+
+#: vncviewer/vncviewer.cxx:310
+msgid "Could not create VNC home directory: can't obtain home directory path."
+msgstr "Не удалось создать домашний каталог VNC: не удаётся получить путь к домашнему каталогу."
+
+#: vncviewer/vncviewer.cxx:315
#, c-format
-msgid "connected to host %s port %d"
-msgstr "подключен к хосту %s, порт %d"
+msgid "Could not create VNC home directory: %s."
+msgstr "Не удалось создать домашний каталог VNC: %s."
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:563
-msgid "disabled"
-msgstr "отключено"
+#. TRANSLATORS: "Parameters" are command line arguments, or settings
+#. from a file or the Windows registry.
+#: vncviewer/vncviewer.cxx:520 vncviewer/vncviewer.cxx:521
+msgid "Parameters -listen and -via are incompatible"
+msgstr "Параметры -listen и -via несовместимы"
-#: /home/ossman/devel/tigervnc/vncviewer/CConn.cxx:563
-msgid "enabled"
-msgstr "включено"
+#: vncviewer/vncviewer.cxx:536
+#, c-format
+msgid "Listening on port %d"
+msgstr "Прослушивается порт %d"
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:556
-msgid "level (1=fast, 6=best [4-6 are rarely useful])"
-msgstr ""
-"уровень (1=высокая скорость, 6=высокое качество [4-6 используются редко])"
-
-#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:569
-msgid "quality (0=poor, 9=best)"
-msgstr "качество (0=наихудшее, 9=наилучшее)"
-
-#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:63
-msgid "unable to create DIB section"
-msgstr ""
-
-#~ msgid ""
-#~ "Desktop name: %.80s\n"
-#~ "Host: %.80s port: %d\n"
-#~ "Size: %d x %d\n"
-#~ "Pixel format: %s\n"
-#~ "(server default %s)\n"
-#~ "Requested encoding: %s\n"
-#~ "Last used encoding: %s\n"
-#~ "Line speed estimate: %d kbit/s\n"
-#~ "Protocol version: %d.%d\n"
-#~ "Security method: %s\n"
-#~ msgstr ""
-#~ "Имя сеанса: %.80s\n"
-#~ "Машина: %.80s порт: %d\n"
-#~ "Размер: %d x %d\n"
-#~ "Формат цвета: %s\n"
-#~ "(значение сервера %s)\n"
-#~ "Запрошенная схема кодирования: %s\n"
-#~ "Последняя схема кодирования: %s\n"
-#~ "Скорость линии связи: %d кбит/с\n"
-#~ "Версия протокола: %d.%d\n"
-#~ "Схема безопасности: %s\n"
+#: vncviewer/vncviewer.cxx:601
+msgid "Internal FLTK error. Exiting."
+msgstr "Внутренняя ошибка FLTK. Выход."
diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx
index bffdfbe..2d6adf5 100644
--- a/unix/vncconfig/vncconfig.cxx
+++ b/unix/vncconfig/vncconfig.cxx
@@ -51,6 +51,8 @@
StringParameter displayname("display", "The X display", "");
BoolParameter noWindow("nowin", "Don't display a window", 0);
BoolParameter iconic("iconic", "Start with window iconified", 0);
+BoolParameter setPrimary("SetPrimary", "Set the PRIMARY as well "
+ "as the CLIPBOARD selection", true);
BoolParameter sendPrimary("SendPrimary", "Send the PRIMARY as well as the "
"CLIPBOARD selection", true);
IntParameter pollTime("poll",
@@ -87,6 +89,8 @@
VncConfigWindow(Display* dpy)
: TXWindow(dpy, 300, 100), cutText(0), cutTextLen(0),
acceptClipboard(dpy, "Accept clipboard from viewers", this, false, this),
+ setPrimaryCB(dpy, "Also set primary selection",
+ this, false, this),
sendClipboard(dpy, "Send clipboard to viewers", this, false, this),
sendPrimaryCB(dpy, "Send primary selection to viewers", this,false,this),
pollTimer(this),
@@ -98,6 +102,10 @@
acceptClipboard.move(xPad, y);
acceptClipboard.checked(getBoolParam(dpy, ACCEPT_CUT_TEXT));
y += acceptClipboard.height();
+ setPrimaryCB.move(xPad + 10, y);
+ setPrimaryCB.checked(setPrimary);
+ setPrimaryCB.disabled(!acceptClipboard.checked());
+ y += setPrimaryCB.height();
sendClipboard.move(xPad, y);
sendClipboard.checked(getBoolParam(dpy, SEND_CUT_TEXT));
y += sendClipboard.height();
@@ -136,7 +144,9 @@
cutTextLen<9?cutTextLen:8, cutText,
cutTextLen<9?"":"...");
XStoreBytes(dpy, cutText, cutTextLen);
- ownSelection(XA_PRIMARY, cutEv->time);
+ if (setPrimaryCB.checked()) {
+ ownSelection(XA_PRIMARY, cutEv->time);
+ }
ownSelection(xaCLIPBOARD, cutEv->time);
delete [] selection[0];
delete [] selection[1];
@@ -238,6 +248,7 @@
if (checkbox == &acceptClipboard) {
XVncExtSetParam(dpy, (acceptClipboard.checked()
? ACCEPT_CUT_TEXT "=1" : ACCEPT_CUT_TEXT "=0"));
+ setPrimaryCB.disabled(!acceptClipboard.checked());
} else if (checkbox == &sendClipboard) {
XVncExtSetParam(dpy, (sendClipboard.checked()
? SEND_CUT_TEXT "=1" : SEND_CUT_TEXT "=0"));
@@ -269,7 +280,7 @@
int cutTextLen;
char* selection[2];
int selectionLen[2];
- TXCheckbox acceptClipboard, sendClipboard, sendPrimaryCB;
+ TXCheckbox acceptClipboard, setPrimaryCB, sendClipboard, sendPrimaryCB;
rfb::Timer pollTimer;
QueryConnectDialog* queryConnectDialog;
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index 262dd2c..140b1d6 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -439,7 +439,8 @@
// RFB doesn't have separate selection and clipboard concepts, so we
// dump the data into both variants.
- Fl::copy(buffer, ret, 0);
+ if (setPrimary)
+ Fl::copy(buffer, ret, 0);
Fl::copy(buffer, ret, 1);
delete [] buffer;
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
index f112a52..2f9df9c 100644
--- a/vncviewer/OptionsDialog.cxx
+++ b/vncviewer/OptionsDialog.cxx
@@ -263,6 +263,9 @@
viewOnlyCheckbox->value(viewOnly);
acceptClipboardCheckbox->value(acceptClipboard);
+#if !defined(WIN32) && !defined(__APPLE__)
+ setPrimaryCheckbox->value(setPrimary);
+#endif
sendClipboardCheckbox->value(sendClipboard);
#if !defined(WIN32) && !defined(__APPLE__)
sendPrimaryCheckbox->value(sendPrimary);
@@ -373,6 +376,9 @@
/* Input */
viewOnly.setParam(viewOnlyCheckbox->value());
acceptClipboard.setParam(acceptClipboardCheckbox->value());
+#if !defined(WIN32) && !defined(__APPLE__)
+ setPrimary.setParam(setPrimaryCheckbox->value());
+#endif
sendClipboard.setParam(sendClipboardCheckbox->value());
#if !defined(WIN32) && !defined(__APPLE__)
sendPrimary.setParam(sendPrimaryCheckbox->value());
@@ -696,6 +702,14 @@
_("Accept clipboard from server")));
ty += CHECK_HEIGHT + TIGHT_MARGIN;
+#if !defined(WIN32) && !defined(__APPLE__)
+ setPrimaryCheckbox = new Fl_Check_Button(LBLRIGHT(tx + INDENT, ty,
+ CHECK_MIN_WIDTH,
+ CHECK_HEIGHT,
+ _("Also set primary selection")));
+ ty += CHECK_HEIGHT + TIGHT_MARGIN;
+#endif
+
sendClipboardCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
CHECK_MIN_WIDTH,
CHECK_HEIGHT,
@@ -706,7 +720,7 @@
sendPrimaryCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
CHECK_MIN_WIDTH,
CHECK_HEIGHT,
- _("Send primary selection and cut buffer as clipboard")));
+ _("Send primary selection as clipboard")));
ty += CHECK_HEIGHT + TIGHT_MARGIN;
#endif
diff --git a/vncviewer/OptionsDialog.h b/vncviewer/OptionsDialog.h
index 39bd7af..6984c72 100644
--- a/vncviewer/OptionsDialog.h
+++ b/vncviewer/OptionsDialog.h
@@ -106,6 +106,9 @@
/* Input */
Fl_Check_Button *viewOnlyCheckbox;
Fl_Check_Button *acceptClipboardCheckbox;
+#if !defined(WIN32) && !defined(__APPLE__)
+ Fl_Check_Button *setPrimaryCheckbox;
+#endif
Fl_Check_Button *sendClipboardCheckbox;
#if !defined(WIN32) && !defined(__APPLE__)
Fl_Check_Button *sendPrimaryCheckbox;
diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx
index 9a9b9fd..ad82f27 100644
--- a/vncviewer/parameters.cxx
+++ b/vncviewer/parameters.cxx
@@ -120,11 +120,14 @@
BoolParameter acceptClipboard("AcceptClipboard",
"Accept clipboard changes from the server",
true);
+BoolParameter setPrimary("SetPrimary",
+ "Set the primary selection as well as the "
+ "clipboard selection", true);
BoolParameter sendClipboard("SendClipboard",
"Send clipboard changes to the server", true);
#if !defined(WIN32) && !defined(__APPLE__)
BoolParameter sendPrimary("SendPrimary",
- "Send the primary selection and cut buffer to the "
+ "Send the primary selection to the "
"server as well as the clipboard selection",
true);
#endif
diff --git a/vncviewer/parameters.h b/vncviewer/parameters.h
index e4378c8..682b6d6 100644
--- a/vncviewer/parameters.h
+++ b/vncviewer/parameters.h
@@ -51,6 +51,7 @@
extern rfb::BoolParameter shared;
extern rfb::BoolParameter acceptClipboard;
+extern rfb::BoolParameter setPrimary;
extern rfb::BoolParameter sendClipboard;
#if !defined(WIN32) && !defined(__APPLE__)
extern rfb::BoolParameter sendPrimary;
diff --git a/vncviewer/vncviewer.man b/vncviewer/vncviewer.man
index 5dd3b45..9ee616d 100644
--- a/vncviewer/vncviewer.man
+++ b/vncviewer/vncviewer.man
@@ -153,13 +153,18 @@
Accept clipboard changes from the server. Default is on.
.
.TP
+.B \-SetPrimary
+Set the primary selection as well as the clipboard selection.
+Default is on.
+.
+.TP
.B \-SendClipboard
Send clipboard changes to the server. Default is on.
.
.TP
.B \-SendPrimary
-Send the primary selection and cut buffer to the server as well as the
-clipboard selection. Default is on.
+Send the primary selection to the server as well as the clipboard
+selection. Default is on.
.
.TP
.B \-Maximize