├── LICENSE ├── README ├── example └── index.html ├── fonts └── ansilove_font_pc_80x25.png └── src ├── Term.js ├── parser ├── AnsiParser.js ├── ByteArray.js ├── CharacterCodes.js ├── EscapeSequencer.js ├── Keyboard.js ├── NVTCodes.js ├── SixteenColors.js └── Telnet.js ├── telnet ├── Session.js └── Socket.js └── viewer ├── AnsiViewer.js ├── Cursor.js ├── Font.js └── Point.js /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Peter Nitsch 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pnitsch/jsTerm/ba18c505ea969a331c890b203b0a6f0ac2e789d3/README -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | jsTerm Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 47 | 48 | 49 |
50 | 51 |
52 | 88 | 89 | 90 | 91 |
92 | 93 | 94 | -------------------------------------------------------------------------------- /fonts/ansilove_font_pc_80x25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pnitsch/jsTerm/ba18c505ea969a331c890b203b0a6f0ac2e789d3/fonts/ansilove_font_pc_80x25.png -------------------------------------------------------------------------------- /src/Term.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2010 Peter Nitsch 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * @author Peter Nitsch 23 | * http://jsterm.com 24 | * http://www.peternitsch.net 25 | */ 26 | 27 | var TERM = TERM || { 28 | socket : null, 29 | SERVER_URL : "174.143.154.166", // Your node.js server IP 30 | SERVER_PORT : "8000", // Your node.js server port 31 | VERSION : "0.1 alpha" 32 | }; -------------------------------------------------------------------------------- /src/parser/AnsiParser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Peter Nitsch 3 | */ 4 | 5 | TERM.AnsiParser = function (viewer){ 6 | 7 | var viewer = viewer; 8 | var escapeCommand = []; 9 | var bufferEscapeCommand = false; 10 | 11 | this.escapeCommands = new TERM.EscapeSequencer(viewer); 12 | this._bytes; 13 | 14 | this.parse = function (bytes) { 15 | 16 | if( bytes != null ) this._bytes = new TERM.ByteArray(bytes); 17 | 18 | while( this._bytes.bytesAvailable > 0 ){ 19 | var result = this._bytes.readUnsignedByte(); 20 | 21 | if( result == SUBSTITUTE) { 22 | break; 23 | } else { 24 | this.readByte( result ); 25 | } 26 | } 27 | 28 | this._bytes.position = 0; 29 | }; 30 | 31 | this._exceptionsLib = []; 32 | this._exceptions = []; 33 | 34 | this.hasException = function( code ) { 35 | if( this._exceptions.indexOf(code) != -1 ) 36 | return true; 37 | return false; 38 | }; 39 | 40 | this.writeException = function( code, callback ) { 41 | if( !this.hasException(code) ){ 42 | this._exceptionsLib[code] = callback; 43 | this._exceptions.push(code); 44 | } 45 | }; 46 | 47 | this.readByte = function (b) { 48 | 49 | if(b == ESCAPE) { 50 | escapeCommand = []; 51 | escapeCommand.push(b); 52 | bufferEscapeCommand = true; 53 | } else { 54 | if(bufferEscapeCommand){ 55 | escapeCommand.push(b); 56 | if( this.escapeCommands.checkCommandAction(escapeCommand.length, b) ) { 57 | this.escapeCommands.executeCommand(escapeCommand); 58 | bufferEscapeCommand = false; 59 | } 60 | } else if( this.hasException(b) ) { 61 | this._exceptionsLib[b]( b, this._bytes ); 62 | } else if(b >= SPACE) { 63 | viewer.drawCharacter(b); 64 | } else { 65 | switch(b) { 66 | case BACKSPACE: 67 | viewer.moveBackward(1, true); 68 | break; 69 | 70 | case LINE_FEED: 71 | viewer.carriageReturn(); 72 | viewer.moveDown(1); 73 | break; 74 | 75 | case CARRIAGE_RETURN: 76 | viewer.carriageReturn(); 77 | break; 78 | 79 | case FORM_FEED: 80 | viewer.eraseScreen(); 81 | viewer.reposition(0, 0); 82 | break; 83 | } 84 | } 85 | } 86 | }; 87 | 88 | }; -------------------------------------------------------------------------------- /src/parser/ByteArray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Peter Nitsch 3 | */ 4 | 5 | TERM.ByteArray = function (bytes){ 6 | 7 | this.position = 0; 8 | this.stringdata = bytes; 9 | 10 | this.readUnsignedByte = function(){ 11 | var b = this.stringdata.charCodeAt(this.position); 12 | if(this.position!=this.stringdata.length) this.position++; 13 | return b; 14 | }; 15 | 16 | this.writeByte = function(){ 17 | // TO DO 18 | }; 19 | 20 | }; 21 | 22 | TERM.ByteArray.prototype = { 23 | 24 | get bytesAvailable (){ 25 | return this.stringdata.length - this.position; 26 | }, 27 | get length (){ 28 | return this.stringdata.length; 29 | } 30 | 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /src/parser/CharacterCodes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Peter Nitsch 3 | */ 4 | 5 | const NULL = 0 6 | const START_OF_HEADING = 1; 7 | const START_OF_TEXT = 2; 8 | const END_OF_TEXT = 3; 9 | const END_OF_TRANSMISSION = 4; 10 | const ENQUIRY = 5; 11 | const ACKNOWLEDGE = 6; 12 | const BELL = 7; 13 | const BACKSPACE = 8; 14 | const HORIZONTAL_TABULATION = 9; 15 | const LINE_FEED = 10; 16 | const VERTICAL_TABULATION = 11; 17 | const FORM_FEED = 12; 18 | const CARRIAGE_RETURN = 13; 19 | const SHIFT_OUT = 14; 20 | const SHIFT_IN = 15; 21 | const DATA_LINK_ESCAPE = 16; 22 | const DEVICE_CONTROL_ONE = 17; 23 | const DEVICE_CONTROL_TWO = 18; 24 | const DEVICE_CONTROL_THREE = 19; 25 | const DEVICE_CONTROL_FOUR = 20; 26 | const NEGATIVE_ACKNOWLEDGE = 21; 27 | const SYNCHRONOUS_IDLE = 22; 28 | const END_OF_TRANSMISSION_BLOCK = 23; 29 | const CANCEL = 24; 30 | const END_OF_MEDIUM = 25; 31 | const SUBSTITUTE = 26; 32 | const ESCAPE = 27; 33 | const FILE_SEPARATOR = 28; 34 | const GROUP_SEPARATOR = 29; 35 | const RECORD_SEPARATOR = 30; 36 | const UNIT_SEPARATOR = 31; 37 | const SPACE = 32; 38 | const EXCLAMATION_MARK = 33; 39 | const QUOTATION_MARK = 34; 40 | const uint_SIGN = 35; 41 | const DOLLAR_SIGN = 36; 42 | const PERCENT_SIGN = 37; 43 | const AMPERSAND = 38; 44 | const APOSTROPHE = 39; 45 | const LEFT_PARENTHESIS = 40; 46 | const RIGHT_PARENTHESIS = 41; 47 | const ASTERISK = 42; 48 | const PLUS_SIGN = 43; 49 | const COMMA = 44; 50 | const HYPHEN_MINUS = 45; 51 | const FULL_STOP = 46; 52 | const SOLIDUS = 47; 53 | const DIGIT_ZERO = 48; 54 | const DIGIT_ONE = 49; 55 | const DIGIT_TWO = 50; 56 | const DIGIT_THREE = 51; 57 | const DIGIT_FOUR = 52; 58 | const DIGIT_FIVE = 53; 59 | const DIGIT_SIX = 54; 60 | const DIGIT_SEVEN = 55; 61 | const DIGIT_EIGHT = 56; 62 | const DIGIT_NINE = 57; 63 | const COLON = 58; 64 | const SEMICOLON = 59; 65 | const LESS_THAN_SIGN = 60; 66 | const EQUALS_SIGN = 61; 67 | const GREATER_THAN_SIGN = 62; 68 | const QUESTION_MARK = 63; 69 | const COMMERCIAL_AT = 64; 70 | const LATIN_CAPITAL_LETTER_A = 65; 71 | const LATIN_CAPITAL_LETTER_B = 66; 72 | const LATIN_CAPITAL_LETTER_C = 67; 73 | const LATIN_CAPITAL_LETTER_D = 68; 74 | const LATIN_CAPITAL_LETTER_E = 69; 75 | const LATIN_CAPITAL_LETTER_F = 70; 76 | const LATIN_CAPITAL_LETTER_G = 71; 77 | const LATIN_CAPITAL_LETTER_H = 72; 78 | const LATIN_CAPITAL_LETTER_I = 73; 79 | const LATIN_CAPITAL_LETTER_J = 74; 80 | const LATIN_CAPITAL_LETTER_K = 75; 81 | const LATIN_CAPITAL_LETTER_L = 76; 82 | const LATIN_CAPITAL_LETTER_M = 77; 83 | const LATIN_CAPITAL_LETTER_N = 78; 84 | const LATIN_CAPITAL_LETTER_O = 79; 85 | const LATIN_CAPITAL_LETTER_P = 80; 86 | const LATIN_CAPITAL_LETTER_Q = 81; 87 | const LATIN_CAPITAL_LETTER_R = 82; 88 | const LATIN_CAPITAL_LETTER_S = 83; 89 | const LATIN_CAPITAL_LETTER_T = 84; 90 | const LATIN_CAPITAL_LETTER_U = 85; 91 | const LATIN_CAPITAL_LETTER_V = 86; 92 | const LATIN_CAPITAL_LETTER_W = 87; 93 | const LATIN_CAPITAL_LETTER_X = 88; 94 | const LATIN_CAPITAL_LETTER_Y = 89; 95 | const LATIN_CAPITAL_LETTER_Z = 90; 96 | const LEFT_SQUARE_BRACKET = 91; 97 | const REVERSE_SOLIDUS = 92; 98 | const RIGHT_SQUARE_BRACKET = 93; 99 | const CIRCUMFLEX_ACCENT = 94; 100 | const LOW_LINE = 95; 101 | const GRAVE_ACCENT = 96; 102 | const LATIN_SMALL_LETTER_A = 97; 103 | const LATIN_SMALL_LETTER_B = 98; 104 | const LATIN_SMALL_LETTER_C = 99; 105 | const LATIN_SMALL_LETTER_D = 100; 106 | const LATIN_SMALL_LETTER_E = 101; 107 | const LATIN_SMALL_LETTER_F = 102; 108 | const LATIN_SMALL_LETTER_G = 103; 109 | const LATIN_SMALL_LETTER_H = 104; 110 | const LATIN_SMALL_LETTER_I = 105; 111 | const LATIN_SMALL_LETTER_J = 106; 112 | const LATIN_SMALL_LETTER_K = 107; 113 | const LATIN_SMALL_LETTER_L = 108; 114 | const LATIN_SMALL_LETTER_M = 109; 115 | const LATIN_SMALL_LETTER_N = 110; 116 | const LATIN_SMALL_LETTER_O = 111; 117 | const LATIN_SMALL_LETTER_P = 112; 118 | const LATIN_SMALL_LETTER_Q = 113; 119 | const LATIN_SMALL_LETTER_R = 114; 120 | const LATIN_SMALL_LETTER_S = 115; 121 | const LATIN_SMALL_LETTER_T = 116; 122 | const LATIN_SMALL_LETTER_U = 117; 123 | const LATIN_SMALL_LETTER_V = 118; 124 | const LATIN_SMALL_LETTER_W = 119; 125 | const LATIN_SMALL_LETTER_X = 120; 126 | const LATIN_SMALL_LETTER_Y = 121; 127 | const LATIN_SMALL_LETTER_Z = 122; 128 | const LEFT_CURLY_BRACKET = 123; 129 | const VERTICAL_LINE = 124; 130 | const RIGHT_CURLY_BRACKET = 125; 131 | const TILDE = 126; 132 | const DELETE = 127; 133 | const LATIN_CAPITAL_LETTER_C_WITH_CEDILLA = 128; 134 | const LATIN_SMALL_LETTER_U_WITH_DIAERESIS = 129; 135 | const LATIN_SMALL_LETTER_E_WITH_ACUTE = 130; 136 | const LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX = 131; 137 | const LATIN_SMALL_LETTER_A_WITH_DIAERESIS = 132; 138 | const LATIN_SMALL_LETTER_A_WITH_GRAVE = 133; 139 | const LATIN_SMALL_LETTER_A_WITH_RING_ABOVE = 134; 140 | const LATIN_SMALL_LETTER_C_WITH_CEDILLA = 135; 141 | const LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX = 136; 142 | const LATIN_SMALL_LETTER_E_WITH_DIAERESIS = 137; 143 | const LATIN_SMALL_LETTER_E_WITH_GRAVE = 138; 144 | const LATIN_SMALL_LETTER_I_WITH_DIAERESIS = 139; 145 | const LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX = 140; 146 | const LATIN_SMALL_LETTER_I_WITH_GRAVE = 141; 147 | const LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS = 142; 148 | const LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE = 143; 149 | const LATIN_CAPITAL_LETTER_E_WITH_ACUTE = 144; 150 | const LATIN_SMALL_LETTER_AE = 145; 151 | const LATIN_CAPITAL_LETTER_AE = 146; 152 | const LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX = 147; 153 | const LATIN_SMALL_LETTER_O_WITH_DIAERESIS = 148; 154 | const LATIN_SMALL_LETTER_O_WITH_GRAVE = 149; 155 | const LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX = 150; 156 | const LATIN_SMALL_LETTER_U_WITH_GRAVE = 151; 157 | const LATIN_SMALL_LETTER_Y_WITH_DIAERESIS = 152; 158 | const LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS = 153; 159 | const LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS = 154; 160 | const CENT_SIGN = 155; 161 | const POUND_SIGN = 156; 162 | const YEN_SIGN = 157; 163 | const PESETA_SIGN = 158; 164 | const LATIN_SMALL_LETTER_F_WITH_HOOK = 159; 165 | const LATIN_SMALL_LETTER_A_WITH_ACUTE = 160; 166 | const LATIN_SMALL_LETTER_I_WITH_ACUTE = 161; 167 | const LATIN_SMALL_LETTER_O_WITH_ACUTE = 162; 168 | const LATIN_SMALL_LETTER_U_WITH_ACUTE = 163; 169 | const LATIN_SMALL_LETTER_N_WITH_TILDE = 164; 170 | const LATIN_CAPITAL_LETTER_N_WITH_TILDE = 165; 171 | const FEMININE_ORDINAL_INDICATOR = 166; 172 | const MASCULINE_ORDINAL_INDICATOR = 167; 173 | const INVERTED_QUESTION_MARK = 168; 174 | const REVERSED_NOT_SIGN = 169; 175 | const NOT_SIGN = 170; 176 | const VULGAR_FRACTION_ONE_HALF = 171; 177 | const VULGAR_FRACTION_ONE_QUARTER = 172; 178 | const INVERTED_EXCLAMATION_MARK = 173; 179 | const LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK = 174; 180 | const RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK = 175; 181 | const LIGHT_SHADE = 176; 182 | const MEDIUM_SHADE = 177; 183 | const DARK_SHADE = 178; 184 | const BOX_DRAWINGS_LIGHT_VERTICAL = 179; 185 | const BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT = 180; 186 | const BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE = 181; 187 | const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE = 182; 188 | const BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE = 183; 189 | const BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE = 184; 190 | const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT = 185; 191 | const BOX_DRAWINGS_DOUBLE_VERTICAL = 186; 192 | const BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT = 187; 193 | const BOX_DRAWINGS_DOUBLE_UP_AND_LEFT = 188; 194 | const BOX_DRAWINGS_UP_DOUBLE_AND_LEFT_SINGLE = 189; 195 | const BOX_DRAWINGS_UP_SINGLE_AND_LEFT_DOUBLE = 190; 196 | const BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT = 191; 197 | const BOX_DRAWINGS_LIGHT_UP_AND_RIGHT = 192; 198 | const BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL = 193; 199 | const BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL = 194; 200 | const BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT = 195; 201 | const BOX_DRAWINGS_LIGHT_HORIZONTAL = 196; 202 | const BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL = 197; 203 | const BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE = 198; 204 | const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE = 199; 205 | const BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT = 200; 206 | const BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT = 201; 207 | const BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL = 202; 208 | const BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL = 203; 209 | const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT = 204; 210 | const BOX_DRAWINGS_DOUBLE_HORIZONTAL = 205; 211 | const BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL = 206; 212 | const BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE = 207; 213 | const BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE = 208; 214 | const BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE = 209; 215 | const BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE = 210; 216 | const BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE = 211; 217 | const BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE = 212; 218 | const BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE = 213; 219 | const BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE = 214; 220 | const BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE = 215; 221 | const BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE = 216; 222 | const BOX_DRAWINGS_LIGHT_UP_AND_LEFT = 217; 223 | const BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT = 218; 224 | const FULL_BLOCK = 219; 225 | const LOWER_HALF_BLOCK = 220; 226 | const LEFT_HALF_BLOCK = 221; 227 | const RIGHT_HALF_BLOCK = 222; 228 | const UPPER_HALF_BLOCK = 223; 229 | const GREEK_SMALL_LETTER_ALPHA = 224; 230 | const LATIN_SMALL_LETTER_SHARP_S = 225; 231 | const GREEK_CAPITAL_LETTER_GAMMA = 226; 232 | const GREEK_SMALL_LETTER_PI = 227; 233 | const GREEK_CAPITAL_LETTER_SIGMA = 228; 234 | const GREEK_SMALL_LETTER_SIGMA = 229; 235 | const MICRO_SIGN = 230; 236 | const GREEK_SMALL_LETTER_TAU = 231; 237 | const GREEK_CAPITAL_LETTER_PHI = 232; 238 | const GREEK_CAPITAL_LETTER_THETA = 233; 239 | const GREEK_CAPITAL_LETTER_OMEGA = 234; 240 | const GREEK_SMALL_LETTER_DELTA = 235; 241 | const INFINITY = 236; 242 | const GREEK_SMALL_LETTER_PHI = 237; 243 | const GREEK_SMALL_LETTER_EPSILON = 238; 244 | const INTERSECTION = 239; 245 | const IDENTICAL_TO = 240; 246 | const PLUS_MINUS_SIGN = 241; 247 | const GREATER_THAN_OR_EQUAL_TO = 242; 248 | const LESS_THAN_OR_EQUAL_TO = 243; 249 | const TOP_HALF_INTEGRAL = 244; 250 | const BOTTOM_HALF_INTEGRAL = 245; 251 | const DIVISION_SIGN = 246; 252 | const ALMOST_EQUAL_TO = 247; 253 | const DEGREE_SIGN = 248; 254 | const BULLET_OPERATOR = 249; 255 | const MIDDLE_DOT = 250; 256 | const SQUARE_ROOT = 251; 257 | const SUPERSCRIPT_LATIN_SMALL_LETTER_N = 252; 258 | const SUPERSCRIPT_TWO = 253; 259 | const BLACK_SQUARE = 254; 260 | const NO_BREAK_SPACE = 255; -------------------------------------------------------------------------------- /src/parser/EscapeSequencer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Peter Nitsch 3 | */ 4 | 5 | TERM.EscapeSequencer = function (viewer){ 6 | 7 | var viewer = viewer; 8 | var telnet; 9 | 10 | var _customCommand; 11 | var _currentCustomCommand = {}; 12 | 13 | this.actionCharacterLib = []; 14 | 15 | this.init = function() { 16 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_H ] = this.cursorPosition; 17 | this.actionCharacterLib[ LATIN_SMALL_LETTER_F ] = this.cursorPosition; 18 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_A ] = this.cursorUp; 19 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_B ] = this.cursorDown; 20 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_C] = this.cursorForward; 21 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_D ] = this.cursorBackward; 22 | this.actionCharacterLib[ LATIN_SMALL_LETTER_S ] = this.saveCursorPosition; 23 | this.actionCharacterLib[ LATIN_SMALL_LETTER_U ] = this.restoreCursorPosition; 24 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_K ] = this.eraseLine; 25 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_J ] = this.eraseDisplay; 26 | this.actionCharacterLib[ LATIN_SMALL_LETTER_N ] = this.deviceRequest; 27 | this.actionCharacterLib[ LATIN_SMALL_LETTER_M ] = this.setGraphicsMode; 28 | this.actionCharacterLib[ LATIN_SMALL_LETTER_H ] = this.setMode; 29 | this.actionCharacterLib[ LATIN_SMALL_LETTER_L ] = this.resetMode; 30 | this.actionCharacterLib[ LATIN_SMALL_LETTER_P ] = this.setKeyboardStrings; 31 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_M ] = this.scrollUp; 32 | this.actionCharacterLib[ LATIN_SMALL_LETTER_R ] = this.scrollScreen; 33 | 34 | // TO DO 35 | this.actionCharacterLib[ LATIN_SMALL_LETTER_A ] = this.unused; 36 | this.actionCharacterLib[ LATIN_SMALL_LETTER_D ] = this.unused; 37 | this.actionCharacterLib[ LATIN_SMALL_LETTER_E ] = this.unused; 38 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_L ] = this.unused; 39 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_P ] = this.unused; 40 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_E ] = this.unused; 41 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_F ] = this.unused; 42 | this.actionCharacterLib[ LATIN_CAPITAL_LETTER_X ] = this.unused; 43 | 44 | }; 45 | 46 | this.executeCommand = function(command) { 47 | try { 48 | this.actionCharacterLib[ command[command.length-1] ]( command ); 49 | } catch(error) { 50 | console.log(error); 51 | } 52 | }; 53 | 54 | this.checkCommandAction = function(position, character) { 55 | if( this.actionCharacterLib[character] != undefined ) 56 | return true; 57 | 58 | return false; 59 | }; 60 | 61 | this.unused = function(params) { 62 | // EMPTY 63 | }; 64 | 65 | this.deviceRequest = function(params) { 66 | if( params[2]==DIGIT_FIVE ){ 67 | TERM.socket.writeByte(ESCAPE); 68 | TERM.socket.writeByte(LEFT_SQUARE_BRACKET); 69 | TERM.socket.writeByte(DIGIT_ZERO); 70 | TERM.socket.writeByte(LATIN_SMALL_LETTER_N); 71 | } else if( params[2]==DIGIT_SIX ) { 72 | var i; 73 | var rows = "" + viewer.cursor.y; 74 | var cols = "" + viewer.cursor.x; 75 | 76 | TERM.socket.writeByte(ESCAPE); 77 | TERM.socket.writeByte(LEFT_SQUARE_BRACKET); 78 | for(i=0;i 0){ 120 | lineArray = params.slice(2, params.length-1); 121 | for( i=0; i0) ? column-1 : 0; 128 | line = (line>0) ? line-1 : 0; 129 | 130 | viewer.reposition(column, line); 131 | } 132 | }; 133 | 134 | this.cursorUp = function(params) { 135 | var valueArray = params.slice(2, params.length-1); 136 | var valueStr = ""; 137 | for( i=0; i 0) ? parseInt(valueStr) : 1; 141 | 142 | viewer.moveUp(value); 143 | }; 144 | 145 | this.cursorDown = function(params) { 146 | var valueArray = params.slice(2, params.length-1); 147 | var valueStr = ""; 148 | for( i=0; i 0) ? parseInt(valueStr) : 1; 152 | 153 | viewer.moveDown(value); 154 | }; 155 | 156 | this.cursorForward = function(params) { 157 | var valueArray = params.slice(2, params.length-1); 158 | var valueStr = ""; 159 | for( i=0; i 0) ? parseInt(valueStr) : 1; 163 | 164 | viewer.moveForward(value); 165 | }; 166 | 167 | this.cursorBackward = function(params) { 168 | var valueArray = params.slice(2, params.length-1); 169 | var valueStr = ""; 170 | for( i=0; i 0) ? parseInt(valueStr) : 1; 174 | 175 | viewer.moveBackward(value); 176 | }; 177 | 178 | this.saveCursorPosition = function(params) { 179 | viewer.savePosition(); 180 | }; 181 | 182 | this.restoreCursorPosition = function(params) { 183 | viewer.restorePosition(); 184 | }; 185 | 186 | // Set Graphic Mode functions 187 | var _bold = false; 188 | var _reverse = false; 189 | 190 | var _boldColors = [BLACK_BOLD, RED_BOLD, GREEN_BOLD, YELLOW_BOLD, BLUE_BOLD, MAGENTA_BOLD, CYAN_BOLD, WHITE_BOLD]; 191 | var _normalColors = [BLACK_NORMAL, RED_NORMAL, GREEN_NORMAL, YELLOW_NORMAL, BLUE_NORMAL, MAGENTA_NORMAL, CYAN_NORMAL, WHITE_NORMAL]; 192 | 193 | var _currentForegroundColor = WHITE_NORMAL; 194 | var _currentBackgroundColor = BLACK_NORMAL; 195 | 196 | this.setGraphicsMode = function(params) { 197 | for( i=2; i= NE_VAR_NAME_MAXLENGTH) { 385 | return NE_IN_ERROR; 386 | } else { 387 | sbuf.concat(i); 388 | } 389 | } 390 | } while (true); 391 | 392 | return i; 393 | }; 394 | 395 | function readNEVariableValue(sbuf) { 396 | var i = bytes.readUnsignedByte(); 397 | if (i == -1) { 398 | return NE_IN_ERROR; 399 | } else if (i == IAC) { 400 | i = bytes.readUnsignedByte(); 401 | if (i == IAC) { 402 | return NE_VAR_DEFINED_EMPTY; 403 | } else if (i == SE) { 404 | return NE_IN_END; 405 | } else { 406 | return NE_IN_ERROR; 407 | } 408 | } else if (i == NE_VAR || i == NE_USERVAR) { 409 | return NE_VAR_DEFINED_EMPTY; 410 | } else if (i == NE_ESC) { 411 | i = bytes.readUnsignedByte(); 412 | if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) { 413 | sbuf.concat(i); 414 | } else { 415 | return NE_IN_ERROR; 416 | } 417 | } else { 418 | sbuf.concat(i); 419 | } 420 | 421 | do { 422 | i = bytes.readUnsignedByte(); 423 | if (i == -1) { 424 | return NE_IN_ERROR; 425 | } else if (i == IAC) { 426 | i = bytes.readUnsignedByte(); 427 | if (i == IAC) { 428 | sbuf.concat(i); 429 | } else if (i == SE) { 430 | return NE_IN_END; 431 | } else { 432 | return NE_IN_ERROR; 433 | } 434 | } else if (i == NE_ESC) { 435 | i = bytes.readUnsignedByte(); 436 | if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) { 437 | sbuf.concat(i); 438 | } else { 439 | return NE_IN_ERROR; 440 | } 441 | } else if (i == NE_VAR || i == NE_USERVAR) { 442 | return NE_VAR_OK; 443 | } else { 444 | if (sbuf.length > NE_VAR_VALUE_MAXLENGTH) { 445 | return NE_IN_ERROR; 446 | } else { 447 | sbuf.concat(i); 448 | } 449 | } 450 | } while (true); 451 | 452 | return i; 453 | }; 454 | 455 | 456 | function readNEVariables() { 457 | var sbuf = ""; 458 | var i = bytes.readUnsignedByte(); 459 | if (i == IAC) { 460 | skipToSE(); 461 | console.log("readNEVariables()::INVALID VARIABLE"); 462 | return; 463 | } 464 | var cont = true; 465 | if (i == NE_VAR || i == NE_USERVAR) { 466 | do { 467 | switch (readNEVariableName(sbuf)) { 468 | case NE_IN_ERROR: 469 | console.log("readNEVariables()::NE_IN_ERROR"); 470 | return; 471 | case NE_IN_END: 472 | console.log("readNEVariables()::NE_IN_END"); 473 | return; 474 | case NE_VAR_DEFINED: 475 | console.log("readNEVariables()::NE_VAR_DEFINED"); 476 | var str = sbuf; 477 | sbuf = ""; 478 | switch (readNEVariableValue(sbuf)) { 479 | case NE_IN_ERROR: 480 | console.log("readNEVariables()::NE_IN_ERROR"); 481 | return; 482 | case NE_IN_END: 483 | console.log("readNEVariables()::NE_IN_END"); 484 | return; 485 | case NE_VAR_DEFINED_EMPTY: 486 | console.log("readNEVariables()::NE_VAR_DEFINED_EMPTY"); 487 | break; 488 | case NE_VAR_OK: 489 | console.log("readNEVariables()::NE_VAR_OK:VAR=" + str + " VAL=" + sbuf.toString()); 490 | sbuf = ""; 491 | break; 492 | } 493 | break; 494 | case NE_VAR_UNDEFINED: 495 | console.log("readNEVariables()::NE_VAR_UNDEFINED"); 496 | break; 497 | } 498 | } while (cont); 499 | } 500 | }; 501 | 502 | function handleNEIs() { 503 | if (isEnabled(NEWENV)) { 504 | readNEVariables(); 505 | } 506 | }; 507 | 508 | function handleNEInfo() { 509 | if (isEnabled(NEWENV)) { 510 | readNEVariables(); 511 | } 512 | }; 513 | 514 | function getTTYPE() { 515 | if (isEnabled(TTYPE)) { 516 | TERM.socket.writeByte(IAC); 517 | TERM.socket.writeByte(SB); 518 | TERM.socket.writeByte(TTYPE); 519 | TERM.socket.writeByte(SEND); 520 | TERM.socket.writeByte(IAC); 521 | TERM.socket.writeByte(SE); 522 | } 523 | }; 524 | 525 | function negotiateLineMode() { 526 | if (isEnabled(LINEMODE)) { 527 | TERM.socket.writeByte(IAC); 528 | TERM.socket.writeByte(SB); 529 | TERM.socket.writeByte(LINEMODE); 530 | TERM.socket.writeByte(LM_MODE); 531 | TERM.socket.writeByte(LM_EDIT | LM_TRAPSIG); 532 | TERM.socket.writeByte(IAC); 533 | TERM.socket.writeByte(SE); 534 | WAIT_LM_MODE_ACK = true; 535 | 536 | TERM.socket.writeByte(IAC); 537 | TERM.socket.writeByte(SB); 538 | TERM.socket.writeByte(LINEMODE); 539 | TERM.socket.writeByte(DONT); 540 | TERM.socket.writeByte(LM_FORWARDMASK); 541 | TERM.socket.writeByte(IAC); 542 | TERM.socket.writeByte(SE); 543 | WAIT_LM_DO_REPLY_FORWARDMASK = true; 544 | } 545 | }; 546 | 547 | function negotiateEnvironment() { 548 | if (isEnabled(NEWENV)) { 549 | ba.TERM.socket.writeByte(IAC); 550 | ba.TERM.socket.writeByte(SB); 551 | ba.TERM.socket.writeByte(NEWENV); 552 | ba.TERM.socket.writeByte(SEND); 553 | ba.TERM.socket.writeByte(NE_VAR); 554 | ba.TERM.socket.writeByte(NE_USERVAR); 555 | ba.TERM.socket.writeByte(IAC); 556 | ba.TERM.socket.writeByte(SE); 557 | WAIT_NE_SEND_REPLY = true; 558 | } 559 | }; 560 | 561 | function skipToSE() { 562 | while (bytes.readUnsignedByte() != SE) ; 563 | }; 564 | 565 | function readTriple(triple) { 566 | triple[0] = bytes.readUnsignedByte(); 567 | triple[1] = bytes.readUnsignedByte(); 568 | if ((triple[0] == IAC) && (triple[1] == SE)) { 569 | return false; 570 | } else { 571 | triple[2] = bytes.readUnsignedByte(); 572 | return true; 573 | } 574 | 575 | return false; 576 | }; 577 | 578 | 579 | function readIACSETerminatedString(maxlength) { 580 | var where = 0; 581 | var cbuf = []; 582 | var b = ' '; 583 | var cont = true; 584 | 585 | do { 586 | var i; 587 | i = bytes.readUnsignedByte(); 588 | switch (i) { 589 | case IAC: 590 | i = bytes.readUnsignedByte(); 591 | if (i == SE) { 592 | cont = false; 593 | } 594 | break; 595 | case -1: 596 | return ("default"); 597 | default: 598 | } 599 | if (cont) { 600 | b = i.toString(); 601 | if (b == '\n' || b == '\r' || where == maxlength) { 602 | cont = false; 603 | } else { 604 | cbuf[where++] = b; 605 | } 606 | } 607 | } while (cont); 608 | 609 | var str = ""; 610 | for(var j=0; j this.cursor.maxColumnwidth * this.cursor.columnwidth){ 57 | this.moveDown(1); 58 | this.cursor.carriageReturn(); 59 | } 60 | }; 61 | 62 | this.draw = function(charCode) { 63 | //console.log(charCode +" "+ this.cursor.x +" "+ this.cursor.y) 64 | 65 | ctx.fillStyle = this.cursor.backgroundColor; 66 | ctx.fillRect(this.cursor.x, this.cursor.y, font.width, font.height); 67 | 68 | ctx.drawImage(fontmap, 69 | charCode*(font.width+1), this.colorTable(this.cursor.foregroundColor)*font.height, font.width, font.height, 70 | this.cursor.x, this.cursor.y, font.width, font.height); 71 | }; 72 | 73 | this.carriageReturn = function() { 74 | this.cursor.carriageReturn(); 75 | }; 76 | 77 | this.formFeed = function() { 78 | this.cursor.x = 0; 79 | this.cursor.y = 0; 80 | }; 81 | 82 | this.moveBackward = function(val, erase) { 83 | var movements = val; 84 | 85 | while( movements > 0 ) { 86 | this.cursor.moveBackward(1); 87 | if(erase) this.draw(SPACE); 88 | movements--; 89 | } 90 | }; 91 | 92 | this.moveDown = function(val) { 93 | if(this.cursor.y >= this.cursor.lineheight*(botMargin-1) && scroll){ 94 | this.scrollUp(1); 95 | } else { 96 | this.cursor.moveDown(val); 97 | } 98 | }; 99 | 100 | this.moveForward = function(val) { 101 | this.cursor.moveForward(val); 102 | }; 103 | 104 | this.moveUp = function(val) { 105 | this.cursor.moveUp(val); 106 | }; 107 | 108 | this.reposition = function(x, y) { 109 | this.cursor.x = x * this.cursor.columnwidth; 110 | this.cursor.y = y * this.cursor.lineheight; 111 | }; 112 | 113 | this.restorePosition = function() { 114 | this.cursor.x = _savedPosition.x; 115 | this.cursor.y = _savedPosition.y; 116 | }; 117 | 118 | this.savePosition = function() { 119 | _savedPosition.x = this.cursor.x; 120 | _savedPosition.y = this.cursor.y; 121 | }; 122 | 123 | this.displayCleared = function() { 124 | ctx.fillStyle = BLACK_NORMAL; 125 | ctx.fillRect(0, 0, this.cursor.maxColumnwidth * this.cursor.columnwidth, this.cursor.maxLineheight * this.cursor.lineheight); 126 | }; 127 | 128 | this.eraseUp = function() { 129 | ctx.fillStyle = BLACK_NORMAL; 130 | ctx.fillRect(0, 0, this.cursor.maxColumnwidth * this.cursor.columnwidth, this.cursor.y); 131 | }; 132 | 133 | this.eraseScreen = function() { 134 | ctx.fillStyle = this.cursor.backgroundColor; 135 | ctx.fillRect(0, 0, this.cursor.maxColumnwidth * this.cursor.columnwidth, this.cursor.maxLineheight * this.cursor.lineheight); 136 | }; 137 | 138 | this.eraseDown = function() { 139 | ctx.fillStyle = BLACK_NORMAL; 140 | ctx.fillRect(0, this.cursor.y, this.cursor.maxColumnwidth * this.cursor.columnwidth, (this.cursor.maxLineheight * this.cursor.lineheight) - this.cursor.y); 141 | }; 142 | 143 | this.eraseEndOfLine = function() { 144 | ctx.fillStyle = BLACK_NORMAL; 145 | var w = (this.cursor.maxColumnwidth * this.cursor.columnwidth) - (this.cursor.x - this.cursor.columnwidth); 146 | ctx.fillRect(this.cursor.x, this.cursor.y, w, this.cursor.lineheight); 147 | }; 148 | 149 | this.eraseStartOfLine = function() { 150 | ctx.fillStyle = BLACK_NORMAL; 151 | ctx.fillRect(0, this.cursor.y, this.cursor.x, this.cursor.lineheight); 152 | }; 153 | 154 | this.eraseLine = function() { 155 | ctx.fillStyle = BLACK_NORMAL; 156 | ctx.fillRect(0, this.cursor.y, this.cursor.maxColumnwidth * this.cursor.columnwidth, this.cursor.lineheight); 157 | }; 158 | 159 | this.backgroundColorChanged = function(color) { 160 | this.cursor.backgroundColor = color; 161 | }; 162 | 163 | this.foregroundColorChanged = function(color) { 164 | this.cursor.foregroundColor = color; 165 | }; 166 | 167 | this.home = function() { 168 | this.cursor.x = 0; 169 | this.cursor.y = (topMargin-1) * this.cursor.maxLineHeight; 170 | }; 171 | 172 | this.scrollScreen = function(start, end) { 173 | topMargin = start; 174 | botMargin = end; 175 | 176 | handleHome(); 177 | }; 178 | 179 | this.scrollUp = function(val) { 180 | var canvasData = ctx.getImageData(0, topMargin * this.cursor.lineheight, this.cursor.maxColumnwidth*this.cursor.columnwidth, this.cursor.lineheight * (botMargin-topMargin)); 181 | this.displayCleared(); 182 | ctx.putImageData(canvasData, 0, this.cursor.lineheight*(topMargin-1)); 183 | }; 184 | 185 | this.clearCanvas(); 186 | 187 | }; -------------------------------------------------------------------------------- /src/viewer/Cursor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Peter Nitsch 3 | */ 4 | 5 | TERM.Cursor = function (){ 6 | 7 | this.foregroundColor = WHITE_NORMAL; 8 | this.backgroundColor = BLACK_NORMAL; 9 | this.position = new TERM.Point(); 10 | this.maxColumnWidth = 80; 11 | this.maxLineHeight = 25; 12 | this.columnWidth = 8; 13 | this.lineHeight = 16; 14 | this.maxColumns = 80; 15 | this.infiniteWidth = false; 16 | this.infiniteHeight = false; 17 | 18 | this.moveForward = function(columns) { 19 | if( this.position.x + (columns*this.columnWidth) <= this.maxColumns * this.columnWidth ) 20 | this.position.x = this.position.x + (columns*this.columnWidth); 21 | else 22 | this.position.x = (this.maxColumns * this.columnWidth) - this.columnWidth; 23 | }; 24 | 25 | this.moveBackward = function(columns) { 26 | if( this.position.x - (columns*this.columnWidth) >= 0 ) 27 | this.position.x = this.position.x - (columns*this.columnWidth); 28 | else 29 | this.position.x = 0; 30 | }; 31 | 32 | this.moveDown = function(lines) { 33 | this.position.y = this.position.y + (lines*this.lineHeight); 34 | }; 35 | 36 | this.moveUp = function(lines) { 37 | if( this.position.y - (lines*this.lineHeight) >= 0 ) 38 | this.position.y = this.position.y - (lines*this.lineHeight); 39 | else 40 | this.position.y = 0; 41 | }; 42 | 43 | this.carriageReturn = function() { 44 | this.position.x = 0; 45 | }; 46 | 47 | }; 48 | 49 | TERM.Cursor.prototype = { 50 | 51 | get x (){ 52 | return this.position.x; 53 | }, 54 | set x (val){ 55 | this.position.x = val; 56 | }, 57 | 58 | get y (){ 59 | return this.position.y; 60 | }, 61 | set y (val){ 62 | this.position.y = val; 63 | } 64 | 65 | }; -------------------------------------------------------------------------------- /src/viewer/Font.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Peter Nitsch 3 | */ 4 | 5 | TERM.Font = function() { 6 | 7 | this.width = 8; 8 | this.height = 16; 9 | this.lineHeight = 23; 10 | 11 | }; -------------------------------------------------------------------------------- /src/viewer/Point.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Peter Nitsch 3 | */ 4 | 5 | TERM.Point = function() { 6 | 7 | this.x = 0; 8 | this.y = 0; 9 | 10 | }; --------------------------------------------------------------------------------