org.jline.builtins.telnet.ConnectionData Maven / Gradle / Ivy
/*
* Copyright (c) 2002-2018, the original author(s).
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*
* https://opensource.org/licenses/BSD-3-Clause
*/
package org.jline.builtins.telnet;
/*
* Java TelnetD library (embeddable telnet daemon)
* Copyright (c) 2000-2005 Dieter Wimberger
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
***/
import java.net.InetAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* An utility class that is used to store and allow retrieval
* of all data associated with a connection.
*
* @author Dieter Wimberger
* @version 2.0 (16/07/2006)
* @see Connection
*/
public class ConnectionData {
// Associations
private ConnectionManager connectionManager; // the connection's ConnectionManager
private Socket socket; // the connection's socket
private InetAddress address; // the connection's IP Address Object
private Map environment; // the environment
// Members
private String hostName; // cache for the hostname
private String hostAddress; // cache for the host ip
private int port; // port of the connection
private Locale locale; // locale of the connection
private long lastActivity; // timestamp for the last activity
private boolean warned; // warned flag
private String negotiatedTerminalType; // negotiated TerminalType as String
private int[] terminalGeometry; // negotiated terminal geometry
private boolean terminalGeometryChanged = true; // flag for changes in the terminal geometry
private String loginShell; // the login shell
private boolean lineMode = false;
/**
* Constructs a ConnectionData instance storing vital
* information about a connection.
*
* @param sock Socket of the inbound connection.
* @param cm the connection manager
*/
@SuppressWarnings("this-escape")
public ConnectionData(Socket sock, ConnectionManager cm) {
socket = sock;
connectionManager = cm;
address = sock.getInetAddress();
setHostName();
setHostAddress();
setLocale();
port = sock.getPort();
// this will set a default geometry and terminal type for the terminal
terminalGeometry = new int[2];
terminalGeometry[0] = 80; // width
terminalGeometry[1] = 25; // height
negotiatedTerminalType = "default";
environment = new HashMap(20);
// this will stamp the first activity for validity :)
activity();
} // ConnectionData
/**
* Returns a reference to the ConnectionManager the
* connection is associated with.
*
* @return Reference to the associated ConnectionManager.
* @see ConnectionManager
*/
public ConnectionManager getManager() {
return connectionManager;
} // getManager
/**
* Returns a reference to the socket the Connection
* is associated with.
*
* @return Reference to the associated Socket.
* @see java.net.Socket
*/
public Socket getSocket() {
return socket;
} // getSocket
/**
* Returns the remote port to which the socket is connected.
*
* @return String that contains the remote port number to which the socket is connected.
*/
public int getPort() {
return port;
} // getPort
/**
* Returns the fully qualified host name for the connection's IP address.
* The name is cached on creation for performance reasons. Subsequent calls
* will not result in resolve queries.
*
* @return String that contains the fully qualified host name for this address.
*/
public String getHostName() {
return hostName;
} // getHostName
/**
* Returns the IP address of the connection.
*
* @return String that contains the connection's IP address.
* The format "%d.%d.%d.%d" is well known, where %d goes from zero to 255.
*/
public String getHostAddress() {
return hostAddress;
} // getHostAddress
/**
* Returns the InetAddress object associated with the connection.
*
* @return InetAddress associated with the connection.
*/
public InetAddress getInetAddress() {
return address;
} // getInetAddress
/**
* Returns the Locale object associated with the connection
* by carrying out a simple domain match.
* This can either be effective, if your users are really
* home in the country they are connecting from,
* or ineffective if they are on the move getting connected
* from anywhere in the world.
*
* Yet this gives the chance of capturing a default locale
* and starting from some point. On application context
* this can be by far better handled, so be aware that
* it makes sense to spend some thoughts on that thing when you
* build your application.
*
* @return the Locale object "guessed" for the connection based
* on its host name.
*/
public Locale getLocale() {
return locale;
} // getLocale
/**
* Returns a timestamp of the last activity that happened on
* the associated connection.
*
* @return the timestamp as a long representing the difference,
* measured in milliseconds, between the current time and
* midnight, January 1, 1970 UTC.
*/
public long getLastActivity() {
return lastActivity;
} // getLastActivity
/**
* Sets a new timestamp to the actual time in millis
* retrieved from the System. This will remove an idle warning
* flag if it has been set. Note that you can use this behaviour
* to implement your own complex idle timespan policies within
* the context of your application.
* The check frequency of the ConnectionManager should just be set
* according to the lowest time to warning and time to disconnect
* requirements.
*/
public void activity() {
warned = false;
lastActivity = System.currentTimeMillis();
} // setLastActivity
/**
* Returns the state of the idle warning flag, which
* will be true if a warning has been issued, and false
* if not.
*
* @return the state of the idle warning flag.
*/
public boolean isWarned() {
return warned;
} // isWarned
/**
* Sets the state of the idle warning flag.
* Note that this method will also update the
* the timestamp if the idle warning flag is removed,
* which means its kind of a second way to achieve the
* same thing as with the activity method.
*
* @param bool true if a warning is to be issued,
* false if to be removed.
* @see #activity()
*/
public void setWarned(boolean bool) {
warned = bool;
if (!bool) {
lastActivity = System.currentTimeMillis();
}
} // setWarned
/**
* Sets the terminal geometry data.
* This method should not be called explicitly
* by the application (i.e. the its here for the io subsystem).
* A call will set the terminal geometry changed flag.
*
* @param width of the terminal in columns.
* @param height of the terminal in rows.
*/
public void setTerminalGeometry(int width, int height) {
terminalGeometry[0] = width;
terminalGeometry[1] = height;
terminalGeometryChanged = true;
} // setTerminalGeometry
/**
* Returns the terminal geometry in an array of two integers.
*
* - index 0: Width in columns.
*
- index 1: Height in rows.
*
* A call will reset the terminal geometry changed flag.
*
* @return integer array containing width and height.
*/
public int[] getTerminalGeometry() {
// we toggle the flag because the change should now be known
if (terminalGeometryChanged) terminalGeometryChanged = false;
return terminalGeometry;
} // getTerminalGeometry
/**
* Returns the width of the terminal in columns for convenience.
*
* @return the number of columns.
*/
public int getTerminalColumns() {
return terminalGeometry[0];
} // getTerminalColumns
/**
* Returns the height of the terminal in rows for convenience.
*
* @return the number of rows.
*/
public int getTerminalRows() {
return terminalGeometry[1];
} // getTerminalRows
/**
* Returns the state of the terminal geometry changed flag,
* which will be true if it has been set, and false
* if not.
*
* @return the state of the terminal geometry changed flag.
*/
public boolean isTerminalGeometryChanged() {
return terminalGeometryChanged;
} // isTerminalGeometryChanged
/**
* Returns the terminal type that has been negotiated
* between the telnet client and the telnet server, in
* of a String.
*
* @return the negotiated terminal type as String.
*/
public String getNegotiatedTerminalType() {
return negotiatedTerminalType;
} // getNegotiatedTerminalType
/**
* Sets the terminal type that has been negotiated
* between telnet client and telnet server, in form of
* a String.
*
* This method should not be called explicitly
* by the application (i.e. the its here for the io subsystem).
*
* @param termtype the negotiated terminal type as String.
*/
public void setNegotiatedTerminalType(String termtype) {
negotiatedTerminalType = termtype;
} // setNegotiatedTerminalType
/**
* Returns the hashmap for storing and
* retrieving environment variables to be passed
* between shells.
*
* @return a {@code HashMap} instance.
*/
public Map getEnvironment() {
return environment;
} // getEnvironment
/**
* Returns the login shell name.
*
* @return the shell name as string.
*/
public String getLoginShell() {
return loginShell;
} // getLoginShell
/**
* Sets the login shell name.
*
* @param s the shell name as string.
*/
public void setLoginShell(String s) {
loginShell = s;
} // setLoginShell
/**
* Tests if in line mode.
*
* @return true if in line mode, false otherwise
*/
public boolean isLineMode() {
return lineMode;
} // isLineMode
/**
* Sets the line mode flag for the connection.
* Note that the setting will only be used at
* startup at the moment.
*
* @param b true if to be initialized in linemode,
* false otherwise.
*/
public void setLineMode(boolean b) {
lineMode = b;
} // setLineMode
/**
* Mutator for HostName cache
*/
private void setHostName() {
hostName = address.getHostName();
} // setHostName
/**
* Mutator for HostAddress cache
*/
private void setHostAddress() {
hostAddress = address.getHostAddress();
} // setHostAddress
/**
* Mutator for Locale
* Sets a Locale derived from the hostname,
* or the default which is Locale.ENGLISH if something
* goes wrong.
* The localhost represents a problem for example :)
*/
private void setLocale() {
String country = getHostName();
try {
country = country.substring(country.lastIndexOf(".") + 1);
if (country.equals("at")) {
locale = localeOf("de", "AT");
} else if (country.equals("de")) {
locale = localeOf("de", "DE");
} else if (country.equals("mx")) {
locale = localeOf("es", "MX");
} else if (country.equals("es")) {
locale = localeOf("es", "ES");
} else if (country.equals("it")) {
locale = Locale.ITALY;
} else if (country.equals("fr")) {
locale = Locale.FRANCE;
} else if (country.equals("uk")) {
locale = Locale.UK;
} else if (country.equals("arpa")) {
locale = Locale.US;
} else if (country.equals("com")) {
locale = Locale.US;
} else if (country.equals("edu")) {
locale = Locale.US;
} else if (country.equals("gov")) {
locale = Locale.US;
} else if (country.equals("org")) {
locale = Locale.US;
} else if (country.equals("mil")) {
locale = Locale.US;
} else {
// default to english
locale = Locale.ENGLISH;
}
} catch (Exception ex) {
// default to english
locale = Locale.ENGLISH;
}
} // setLocale
// TODO: {@code new Locale(String, String)} should be replaced with {@code Locale.of(String, String)}
// TODO: when minimum JDK >= 19
@SuppressWarnings("deprecation")
private static Locale localeOf(String language, String country) {
return new Locale(language, country);
}
} // class ConnectionData