/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.sshd.common.channel; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.EnumMap; import java.util.EnumSet; import java.util.Map; import java.util.Set; import java.util.function.Function; import org.apache.sshd.common.util.GenericUtils; /** * A enum describing the tty modes according to * <a href="https://tools.ietf.org/html/rfc4254#section-8">RFC 4254 - section 8</a>. * * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a> */ public enum PtyMode { /////////////////////////////// Chars //////////////////////////////////// /** * Interrupt character; 255 if none. Similarly for the other characters. * Not all of these characters are supported on all systems. */ VINTR(1), /** * The quit character (sends SIGQUIT signal on POSIX systems). */ VQUIT(2), /** * Erase the character to left of the cursor. */ VERASE(3), /** * Kill the current input line. */ VKILL(4), /** * End-of-file character (sends EOF from the terminal). */ VEOF(5), /** * End-of-line character in addition to carriage return and/or line-feed. */ VEOL(6), /** * Additional end-of-line character. */ VEOL2(7), /** * Continues paused output (normally control-Q). */ VSTART(8), /** * Pauses output (normally control-S). */ VSTOP(9), /** * Suspends the current program. */ VSUSP(10), /** * Another suspend character. */ VDSUSP(11), /** * Reprints the current input line. */ VREPRINT(12), /** * Erases a word left of cursor. */ VWERASE(13), /** * Enter the next character typed literally, even if it is a special character */ VLNEXT(14), /** * Character to flush output. */ VFLUSH(15), /** * Switch to a different shell layer. */ VSWTCH(16), /** * Prints system status line (load, command, pid, etc). */ VSTATUS(17), /** * Toggles the flushing of terminal output. */ VDISCARD(18), ///////////////////////////////// I-flags //////////////////////////////// /** * The ignore parity flag. The parameter SHOULD be 0 if this flag * is FALSE, and 1 if it is TRUE. */ IGNPAR(30), /** * Mark parity and framing errors. */ PARMRK(31), /** * Enable checking of parity errors. */ INPCK(32), /** * Strip 8th bit off characters. */ ISTRIP(33), /** * Map NL into CR on input. */ INLCR(34), /** * Ignore CR on input. */ IGNCR(35), /** * Map CR to NL on input. */ ICRNL(36), /** * Translate uppercase characters to lowercase. */ IUCLC(37), /** * Enable output flow control. */ IXON(38), /** * Any char will restart after stop. */ IXANY(39), /** * Enable input flow control. */ IXOFF(40), /** * Ring bell on input queue full. */ IMAXBEL(41), /** * @see <A HREF="https://tools.ietf.org/html/draft-sgtatham-secsh-iutf8-01">IUTF8 Terminal Mode in Secure Shell</A> */ IUTF8(42), /////////////////////////////// L-flags ////////////////////////////////// /** * Enable signals INTR, QUIT, [D]SUSP. */ ISIG(50), /** * Canonicalize input lines. */ ICANON(51), /** * Enable input and output of uppercase characters by preceding their * lowercase equivalents with "\". */ XCASE(52), /** * Enable echoing. */ ECHO(53), /** * Visually erase chars. */ ECHOE(54), /** * Kill character discards current line. */ ECHOK(55), /** * Echo NL even if ECHO is off. */ ECHONL(56), /** * Don't flush after interrupt. */ NOFLSH(57), /** * Stop background jobs from output. */ TOSTOP(58), /** * Enable extensions. */ IEXTEN(59), /** * Echo control characters as ^(Char). */ ECHOCTL(60), /** * Visual erase for line kill. */ ECHOKE(61), /** * Retype pending input. */ PENDIN(62), /////////////////////////// O-flags ////////////////////////////////////// /** * Enable output processing. */ OPOST(70), /** * Convert lowercase to uppercase. */ OLCUC(71), /** * Map NL to CR-NL. */ ONLCR(72), /** * Translate carriage return to newline (output). */ OCRNL(73), /** * Translate newline to carriage return-newline (output). */ ONOCR(74), /** * Newline performs a carriage return (output). */ ONLRET(75), //////////////////////////////// C-flags ///////////////////////////////// /** * 7 bit mode. */ CS7(90), /** * 8 bit mode. */ CS8(91), /** * Parity enable. */ PARENB(92), /** * Odd parity, else even. */ PARODD(93), /////////////////////////// Speed(s) ///////////////////////////////////// /** * Specifies the input baud rate in bits per second. */ TTY_OP_ISPEED(128), /** * Specifies the output baud rate in bits per second. */ TTY_OP_OSPEED(129); public static final byte TTY_OP_END = 0x00; // objects that can be used to set {@link PtyMode}s as {@code true} or {@code false} public static final Integer FALSE_SETTING = 0; public static final Integer TRUE_SETTING = 1; /** * An un-modifiable {@link Set} of all defined {@link PtyMode}s */ public static final Set<PtyMode> MODES = Collections.unmodifiableSet(EnumSet.allOf(PtyMode.class)); private static final Map<Integer, PtyMode> COMMANDS = Collections.unmodifiableMap( GenericUtils.toSortedMap(MODES, PtyMode::toInt, Function.identity(), Comparator.naturalOrder())); private final int v; PtyMode(int v) { this.v = v; } public int toInt() { return v; } /** * @param b The numeric value of the option * @return The matching {@link PtyMode} or {@code null} if no match found * @see #toInt() */ public static PtyMode fromInt(int b) { return COMMANDS.get(0x00FF & b); } /** * @param options The options to enable - ignored if {@code null}/empty * @return A {@link Map} where all the specified {@link PtyMode}s have {@link #TRUE_SETTING} */ public static Map<PtyMode, Integer> createEnabledOptions(PtyMode... options) { return createEnabledOptions(GenericUtils.of(options)); } /** * @param options The options to enable - ignored if {@code null}/empty * @return A {@link Map} where all the specified {@link PtyMode}s have {@link #TRUE_SETTING} */ public static Map<PtyMode, Integer> createEnabledOptions(Collection<PtyMode> options) { if (GenericUtils.isEmpty(options)) { return Collections.emptyMap(); } Map<PtyMode, Integer> modes = new EnumMap<>(PtyMode.class); for (PtyMode m : options) { modes.put(m, TRUE_SETTING); } return modes; } public static Set<PtyMode> resolveEnabledOptions(Map<PtyMode, ?> modes, PtyMode... options) { return resolveEnabledOptions(modes, GenericUtils.of(options)); } /** * @param modes The PTY settings - ignored if {@code null}/empty * @param options The options that should be enabled * @return A {@link Set} of all the {@link PtyMode}s that appeared * in the settings and were enabled * @see #getBooleanSettingValue(Map, PtyMode) */ public static Set<PtyMode> resolveEnabledOptions(Map<PtyMode, ?> modes, Collection<PtyMode> options) { if (GenericUtils.isEmpty(modes) || GenericUtils.isEmpty(options)) { return Collections.emptySet(); } Set<PtyMode> enabled = EnumSet.noneOf(PtyMode.class); for (PtyMode m : options) { if (getBooleanSettingValue(modes, m)) { enabled.add(m); } } return enabled; } /** * @param modes The current modes {@link Map}-ing * @param m The required {@link PtyMode} * @return {@code true} if <U>all</U> of these conditions hold:</BR> * <UL> * <LI>Modes map is not {@code null}/empty</LI> * <LI>Required mode setting is not {@code null}</LI> * <LI>The setting has a mapped value</LI> * <LI>The mapped value is a {@link Number}</LI> * <LI>The {@link Number#intValue()} is non-zero</LI> * </UL> * @see #getBooleanSettingValue(Object) */ public static boolean getBooleanSettingValue(Map<PtyMode, ?> modes, PtyMode m) { if ((m == null) || GenericUtils.isEmpty(modes)) { return false; } else { return getBooleanSettingValue(modes.get(m)); } } /** * @param v The value to be tested * @return {@code true} if <U>all</U> of these conditions hold:</BR> * <UL> * <LI>The mapped value is a {@link Number}</LI> * <LI>The {@link Number#intValue()} is non-zero</LI> * </UL> * @see #getBooleanSettingValue(int) */ public static boolean getBooleanSettingValue(Object v) { return (v instanceof Number) && getBooleanSettingValue(((Number) v).intValue()); } /** * @param v The setting value * @return {@code true} if value is non-zero */ public static boolean getBooleanSettingValue(int v) { return v != 0; } }