RFC 731

Telnet Data Entry Terminal option

πŸ“… published June 1977, from ietf

RFC 731: Telnet Data Entry Terminal Option βœ¨πŸŽ€

  • Author: John Day πŸ’–
  • Date: June 27, 1977 πŸ“…
  • NIC number: 40652 🌸
  • RFC number: 731 πŸ¦‹
  • Category and status: not stated in this title block πŸ€·β€β™€οΈ
  • Obsoletes and updates: nothing is listed in this title block 🫢

1. Command Name and Code πŸŽ€

Okay so the command name is DET and its code is 20. That's the whole ID card, bestie πŸͺͺ

DET             20

2. Command Meanings πŸ’…

Okay, this part is where the four commands come in, and they're giving pairs! πŸ‘―β€β™€οΈ

IAC WILL DET means the sender is REQUESTING or AGREEING to send and receive subcommands that control the Data Entry Terminal. It's basically the "yes, let's do this" move πŸ™‹β€β™€οΈ

IAC WONT DET is the opposite. The sender REFUSES to send and receive those subcommands. Not me, not today πŸ™…β€β™€οΈ

IAC DO DET is the same energy as IAC WILL DET. The sender is REQUESTING or AGREEING to send and receive the subcommands. Yes, both sides can bring the same vibe πŸ’œ

IAC DONT DET mirrors IAC WONT DET. The sender REFUSES to send and receive the subcommands. Periodt πŸ’€

The DET option runs on five classes of subcommands, and they're iconic:

  1. establishing the requirements and capabilities of the application and the terminal
  2. formatting the screen
  3. controlling editing
  4. controlling erasure
  5. controlling transmission

Each of those functions has its own subcommands, and I'll walk you through them below 🧚

The Network Virtual Data Entry Terminal (NVDET) πŸ–₯️

Okay, the NVDET is basically a keyboard plus a rectangular display ✨

The keyboard can type every character in the ASCII character set. It might also have function keys, and pressing one of those sends an FN subcommand. Most DETs also support peripherals like a paper tape reader or a printer, but this option doesn't cover them at all. Peripheral support should be handled by a separate option, so don't look for it here πŸ™ˆ

The screen is a rectangle with M characters across and N lines down. M and N get set by negotiating the Output Line Width option and the Output Page Size option, respectively. Super clean 🌈

The next writing position on the screen is (x,y), where x is the character position and y is the line position. That spot is marked by a special display character called the cursor 🎯 The cursor can move to any position on the screen without messing up the characters already there. Totally non-disruptive, obsessed 😭

Terminals address their cursors in all kinds of different ways. To keep implementing this as easy as possible, the protocol supports two topologies (the finite plane and the helical torus) and three addressing methods: (x,y), x and y, and relative increments. The finite plane with absolute addressing is the least ambiguous, and it's the easiest one to translate to and from the others, so it's the default for the NVDET. The toroidal form works with either relative or absolute addressing, and it's there for convenience πŸ“

The NVDET also has a way to define fields with special attributes on the screen. For example, characters typed into these fields can show up brighter, highlighted with reverse video or blinking, or protected so the user can't change them. The protection feature is one of the most heavily used features, especially for forms the DET shows for the user to fill out πŸ“

All of the NVDET's functions are defined with Telnet option subnegotiations βš™οΈ None of the ASCII characters in the data stream are used to define these functions, which means the DET option can run in a "raw" or even "rare" mode 🌸 If the application knows what kind of terminal is on the other end, it can still send the ASCII characters needed to control functions the option or implementation doesn't support. Generally, though, keeping all NVDET functions out of the data stream gives you better flexibility. Main character energy πŸ‘‘

Facility Functions (for detailed semantics see Section 5.) 🧩

Here's the general format for a facility message:

IAC SB DET <DET facility subcommand><facility map> IAC SE

The <DET facility subcommand> is one 8-bit byte that says which class of facilities is being described. The <facility map> is a field of one or two 8-bit bytes that holds flags for the facilities the sender needs or wants. The bits are numbered from the right, starting at zero. So if bit 2 is set, the field has a decimal value of 4. Easy math 🫢

EDIT FACILITIES (subcommand code: 1) ✏️

The EDIT FACILITIES map looks like this:

facility cmd:  EDIT FACILITIES     subcommand code: 1
  facility map:                              bit numbers
     Toroidal Cursor Addressing                  6
     Incremental Cursor Addressing               5
     Read Cursor Address                         4
     Line Insert/Delete                          3
     Char Insert/Delete                          2
     Back Tab                                    1
     Positive Addressing only                    0

Here's what each bit means:

  • If the Toroidal Cursor Addressing bit is set, the sender requests or provides support for the SKIP TO LINE and SKIP TO CHAR subcommands.
  • If the Incremental Cursor Addressing bit is set, the sender requests or provides support for the UP, DOWN, LEFT, and RIGHT subcommands.
  • If the Read Cursor bit is set, the sender requests or provides the READ CURSOR subcommand.
  • If the Line Insert/Delete bit is set, the sender requests or provides support for the LINE INSERT and LINE DELETE subcommands.
  • If the Char Insert/Delete bit is set, the sender requests or provides support for the CHAR INSERT and CHAR DELETE subcommands.
  • If the Back Tab bit is set, the sender requests or provides support for the BACK TAB subcommand.
  • If the Positive Addressing bit is set, the sender is telling the receiver that the cursor can only move in the positive direction. (Heads up: terminals with this property also have a Home function to get back to the beginning. 🏠)

ERASE FACILITIES (subcommand code: 2) 🧽

The ERASE FACILITIES map looks like this:

facility cmd:  ERASE FACILITIES     subcommand code:  2
  facility map:                                bit numbers
     Erase Field                                     4
     Erase Line                                      3
     Erase Rest of Screen                            2
     Erase Rest of Line                              1
     Erase Rest of Field                             0

If a bit in this facility map is set, the sender requests or provides the facility that bit stands for. The Erase Functions section below has the full details on each one 🫧

TRANSMIT FACILITIES (subcommand code: 3) πŸ“€

The TRANSMIT FACILITIES map looks like this:

facility cmd:  TRANSMIT FACILITIES     subcommand code:  3
  facility map:                      bit numbers
     Data Transmit                         5
     Transmit Line                         4
     Transmit Field                        3
     Transmit Rest of Screen               2
     Transmit Rest of Line                 1
     Transmit Rest of Field                0

Same rule here: if a bit is set, the sender requests or provides that facility. The Transmit Functions section below has the full scoop πŸ’Œ

FORMAT FACILITIES (subcommand code: 4) 🎨

The FORMAT FACILITIES map is the biggest one, and it spans two bytes:

facility cmd:  FORMAT FACILITIES     subcommand code:  4
  facility map:                               bit numbers
                                    byte 0
     Repeat                                         4
     Blinking                                       3
     Reverse Video                                  2
     Right Justification                            1
     Overstrike                                     0

                                    byte 1
     Protection On/Off                              6
     Protection                                     5
     Alphabetic-only Protection                     4
     Numeric-only Protection                        3
     Intensity                                      0-2

Here's the breakdown:

  • If the Repeat bit is set, the sender requests or provides the REPEAT subcommand. πŸ”
  • If the Blinking bit is set, the sender requests or provides the ability to highlight a string of characters by making them blink. ✨
  • If the Reverse Video bit is set, the sender requests or provides the ability to highlight a string by "reversing the video image." So if characters normally show as black on white, they flip to white on black, or the other way around. πŸ–€πŸ€
  • If the Right Justification bit is set, the sender requests or provides the ability to right justify data entries in a field. ➑️
  • If the Overstrike bit is set, the sender requests or provides the ability to layer one character over another on the screen, kind of like a hard copy terminal does when the print mechanism hits the same spot on the paper with different characters. πŸ–¨οΈ
  • If the Protection On/Off bit is set, the sender requests or provides the ability to turn field protection on and off. πŸ”
  • If the Protection bit is set, the sender requests or provides the ability to protect certain strings on the screen from being changed by the terminal user. Setting this bit also implies that the ERASE UNPROTECTED and TRANSMIT UNPROTECTED subcommands (see below) are supported. πŸ›‘οΈ
  • If the Alphabetic-only Protection bit is set, the sender requests or provides the ability to limit the terminal user so they can only enter alphabetic data in certain screen areas. πŸ”€
  • If the Numeric-only Protection bit is set, the sender requests or provides the ability to limit the terminal user so they can only enter numerical data in certain screen areas. πŸ”’
  • The three bits of the Intensity field hold a positive binary integer. That integer is the number of intensity levels the sender requests or provides for displaying the data. The value of this 3-bit field should be interpreted in the following way:

I'm going to start with the intensity table, since it's the tail end of the last section's command meanings. ✨

1        one visible intensity
2        two intensities; normal and bright
3        three intensities; off, normal, and bright
>3        >3 intensities; off, and the remaining levels
          proportioned from dimmest to brightest intensity.

Okay so for all of the commands above, if the matching bit in <facility map> isn't set, then the sender just doesn't request or provide that facility. Simple, but it matters so much 🫢

Editing Functions πŸ’…

Editing is where the cursor gets to be a little diva πŸ’– Here's the whole squad:

MOVE CURSOR 🎯

IAC SB DET MOVE CURSOR <x><y> IAC SE  subcommand code: 5

where <x> is an 8-bit byte holding a positive binary integer for the character position of the cursor, and <y> is an 8-bit byte holding a positive binary integer for the line position of the cursor.

This one jumps the cursor straight to the absolute screen address (x,y), with these boundary conditions:

if x>M-1, set x=M-1 and send an ERROR subcommand
if y>N-1, set y=N-1 and send an  ERROR subcommand

Bestie, this is basically a finite plane topology on the screen 🧚 Nothing wraps around, you just get clamped and an ERROR gets sent back.

SKIP TO LINE ⬇️

IAC SB DET SKIP TO LINE <y> IAC SE    subcommand code: 6

where <y> is a positive 8-bit binary number.

This moves the cursor to the absolute screen line y, and x stays exactly where it was. For values of y>N-1:

y = y mod N

SKIP TO CHAR ➑️

IAC SB DET SKIP TO CHAR <x> IAC SE   subcommand code: 7

where <x> is a positive 8-bit binary number.

This moves the cursor to the absolute character position x. y stays put, unless x>M-1, and then:

x' = (x mod M)
y' = (y+(x DIV N))

where x' and y' are the new values of the cursor.

These last two subcommands together give you a toroidal topology on the screen 🍩 Wrap-around everywhere, no cap.

UP, DOWN, LEFT, RIGHT πŸ•ΉοΈ

IAC SB DET UP IAC SE            subcommand code:  8
IAC SB DET DOWN IAC SE          subcommand code:  9
IAC SB DET LEFT IAC SE          subcommand code: 10
IAC SB DET RIGHT IAC SE         subcommand code: 11

These are here as a little convenience for some terminals πŸ’ They're defined like this:

UP:         (x,y)=(x, y-1 mod N)
DOWN:       (x,y)=(x, y+1 mod N)
LEFT:       (x,y)=(x-1, y); if x=0 then x-1 = 0
RIGHT:      (x,y)=(x+1 mod M, y) and y = y+1 if x+1>M-1
⚠️ Heads up, bestie: DOWN, LEFT, and RIGHT can't always be swapped out for the ASCII codes for linefeed, backspace, and space. Those ASCII codes are format effectors, but these are cursor controls. Different vibes entirely 😭

HOME 🏠

IAC SB DET HOME IAC SE      subcommand code:  12

This one puts the cursor at (0,0). It's the same as a MOVE CURSOR 0,0, or as SKIP TO LINE 0 followed by SKIP TO CHAR 0. It's only here for convenience, since most terminals have it as a separate control 🌸

LINE INSERT πŸ“₯

IAC SB DET LINE INSERT IAC SE     subcommand code:  13

This inserts a line of spaces between line y (the current line, wherever the cursor is) and line y-1. Lines y through N-2 each move down one, so line y becomes line y+1, y+1 becomes y+2, and so on until N-2 becomes N-1. Line N-1 falls off the bottom of the screen and is lost. The cursor doesn't move at all 🫧

LINE DELETE πŸ“€

IAC SB DET LINE DELETE IAC SE     subcommand code:  14

This deletes line y, where y is the cursor's current line. Lines y+1 through N-1 each move up one, so line y+1 becomes line y, y+2 becomes y+1, and so on until N-1 becomes N-2. The N-1st line position is set to all spaces, and the cursor stays right where it was ✨

CHAR INSERT ✍️

IAC SB DET CHAR INSERT IAC SE     subcommand code: 15

This one inserts the next character in the data stream between the xth and x-1st characters, where x is the current character position of the cursor. The xth through M-2nd characters on the line get shifted one character position to the right. The new character goes into the vacated xth position, the M-1st character is lost, and the cursor position stays unchanged πŸ’–

CHAR DELETE πŸ—‘οΈ

IAC SB DET CHAR DELETE IAC SE     subcommand code:  16

This deletes the character at the x-th position. The x-th character is removed, and characters x+1 through M-1 shift one position to the left to become the x-th through M-2nd characters. The M-1st character position is left empty (on most terminals it'll be set to a NUL or space). The cursor stays put πŸŽ€

READ CURSOR πŸ‘€

IAC SB DET READ CURSOR IAC SE     subcommand code:  17

This asks the receiver to send back the present position of the cursor to the sender. Ask and you shall receive 🧚

CURSOR POSITION πŸ“

IAC SB DET CURSOR POSITION <x><y> IAC SE
                                  subcommand code:  18

where <x> and <y> are positive 8-bit binary integers.

This one gets sent by a Telnet implementation in response to a READ CURSOR, so the other side learns where the cursor is. Note: x is less than M and y is less than N 🫢

REVERSE TAB βͺ

IAC SB DET REVERSE TAB IAC SE     subcommand code:  19

This moves the cursor back to the previous tab position. If there isn't one on the present line, the cursor moves to the previous line and keeps going until it finds a tab or hits the address (0,0). When field protection is in effect, the cursor moves to the beginning of the preceding unprotected field πŸ¦‹

Transmit Functions πŸ“€ (For detailed semantics see Section 5.)

Transmit is all about sending data back out, and it's giving main character energy πŸ‘‘

TRANSMIT SCREEN πŸ–₯️

IAC SB DET TRANSMIT SCREEN IAC SE     subcommand code: 20

This makes the terminal transmit every character on the screen, from position (0,0) to (M-1,N-1). The cursor ends up at (0,0) once it's done πŸ’œ

TRANSMIT UNPROTECTED πŸ”“

IAC SB DET TRANSMIT UNPROTECTED IAC SE
                                subcommand code:  21

This makes the terminal transmit all characters in unprotected fields, from position (0,0) to (M-1,N-1). The unprotected fields are separated by the field separator subcommand. Afterwards the cursor will be at (0,0), or at the beginning of the first unprotected field 🌈

TRANSMIT LINE πŸ“

IAC SB DET TRANSMIT LINE IAC SE      subcommand code:  22

This makes the terminal transmit all data on the yth line, where y is determined by the cursor's present position. Data is sent from character position (0,y) to the end of the line or (M-1,y), whichever comes first. The cursor ends up one character position past the end-of-line condition, or at the beginning of the next line, (0,y+1) πŸ“

TRANSMIT FIELD 🏷️

IAC SB DET TRANSMIT FIELD IAC SE     subcommand code:  23

This makes the terminal transmit all data in the field the cursor is currently in. Once it's done, the cursor sits one character position after the end of the field. If that position is protected, the cursor goes to the beginning of the next unprotected field instead 🧁

TRANSMIT REST OF SCREEN πŸŒ…

IAC SB DET TRANSMIT REST OF SCREEN IAC SE
                                subcommand code:  24

This makes the terminal transmit all characters on the screen from position (x,y) to (M-1,N-1), or until the end of text. (x,y) is the current cursor position. Afterwards the cursor is one character position past the last text character, or at (0,0) if the last filled character position is (M-1,N-1) ✨

TRANSMIT REST OF LINE πŸ“

IAC SB DET TRANSMIT REST OF LINE IAC SE
                                subcommand code:  25

This makes the terminal transmit all characters on the yth line from position (x,y) to the end of the line or (M-1,y), whichever comes first. (x,y) is the current cursor position. Once it's done, the cursor is one character position past the last character of the line, or at the first character of the next line 🌷

TRANSMIT REST OF FIELD 🧩

IAC SB DET TRANSMIT REST OF FIELD IAC SE
                                subcommand code:  26

This makes the receiver transmit the rest of the characters in the field the cursor is currently in. Afterwards, the cursor ends up at the beginning of the next field πŸ’…

DATA TRANSMIT πŸ“¨

IAC SB DET DATA TRANSMIT <x><y> IAC SE
                                subcommand code:  27

This one comes right before data that the terminal sends in response to a user action or a TRANSMIT command. The parameters <x> and <y> show the initial position of the cursor. For more detail, check out the Transmit Subcommands subsection in Section 5 🫢

Erase Functions 🫧

Erasing is the dramatic part of the show 🎭

ERASE SCREEN πŸ’₯

IAC SB DET ERASE SCREEN IAC SE     subcommand code: 28

This removes every character from the screen. All fields are deleted, no matter what their attributes are, and the cursor ends up at (0,0). Most terminals set the erased characters to either NUL or space characters 🌌

ERASE LINE 🧽

IAC SB DET ERASE LINE IAC SE     subcommand code:  29

This removes all characters on the yth line, where y is the line the cursor is currently on. All fields are deleted regardless of their attributes, and the cursor ends up at (0,y). Note: you can pretty much copy this with LINE DELETE then LINE INSERT, but order matters so no data falls off the bottom of the screen πŸ™ˆ

ERASE FIELD πŸ«₯

IAC SB DET ERASE FIELD IAC SE     subcommand code:  30

This removes all characters in the field the cursor is in. Afterwards the cursor sits at the beginning of the field πŸŒ™

ERASE REST OF SCREEN 🌠

IAC SB DET ERASE REST OF SCREEN IAC SE
                                subcommand code:  31

This removes all characters from position (x,y) to (M-1,N-1). All fields are deleted regardless of their attributes, and the cursor position stays unchanged. It's the same as doing an ERASE REST OF LINE plus a LINE DELETE for lines greater than y πŸŽ€

ERASE REST OF LINE 🌿

IAC SB DET ERASE REST OF LINE IAC SE
                                subcommand code:  32

This subcommand is the one that clears out the rest of a line. Starting at position (x,y), every character all the way to (M-1,y) gets removed from the screen 🧹. It doesn't matter what attributes the fields have, because all fields get deleted πŸ’…. The cursor stays exactly where it was after the operation, so nothing moves on you πŸ¦‹

IAC SB DET ERASE REST OF FIELD IAC SE
                                subcommand code:  33

This one clears from (x,y) to the end of the current field ✨. Same deal as above, the characters go away and the cursor position after the operation is unchanged πŸŽ€

IAC SB DET ERASE UNPROTECTED IAC SE
                                subcommand code:  34

This subcommand wipes every character in the unprotected fields on the whole screen 🌸. Protected fields are left alone. The cursor ends up at (0,0) 🧚, unless that spot is protected. Then it goes to the beginning of the first unprotected field instead πŸ‘‘

Format Functions

IAC SB DET FORMAT DATA <format map><count> IAC SE
                                subcommand code:  35

Here <format map> is one 8-bit byte with flags packed into it πŸ’œ. Bitch, the layout looks like this:

  Blinking                                 7
  Reverse Video                            6
  Right Justification                      5
  Protection                              3-4
  Intensity                               0-2

Let's break down each flag, because it's giving a lot of detail πŸ”₯

If the Blinking bit is set, the next field of <count> characters should get the Blinking attribute applied by the receiver ✨

If the Reverse Video bit is set, the next field of <count> characters should be shown by the receiver with video reversed πŸ¦‹

If the Right Justification bit is set, the input typed into that field of <count> characters should be right justified 🌈

The Protection field is two bits wide and can be one of these values πŸ’–

  0         no protection
  1         protected
  2         alphabetic only
  3         numeric only

So the protection attribute tells the other side what it's allowed to do with the next <count> bytes 🫢. With no protection it can modify any character. With protected it can't modify any characters at all. With alphabetic only it can only enter letters (A-Z and a-z). With numeric only it can only enter digits (0-9), plus +, ., and - πŸ”’

The Intensity field is 3 bits wide and should be read like this 🌟. The values 0-6 are an indication of relative brightness for displaying (or entering) characters in the following field of <count> characters πŸ’œ. The number of brightness levels available should have been gotten earlier through the Format Facility subcommand πŸ“. How those values get mapped onto the available levels is left up to the implementors πŸ™ˆ. A value of 7 in the intensity field means brightness is off, and any characters in or entered into that field should not be displayed πŸ’€

<count> is 2 bytes that should be read as a positive 16-bit binary integer. It's the number of characters following this command that it affects ✨

Data sent to the terminal or the Using Host for unwritten areas of the screen that fall outside the scope of the count should be displayed with the default values of the format map 🌸. Those defaults are No Blinking, Normal Video, No Justification, No Protection and Normal Intensity πŸŽ€

This subcommand is how you format data that's going to show up on the terminal screen πŸ’…. The <format map> describes what attributes the field of <count> bytes should have. The field starts at the cursor position when the command is acted upon πŸ¦‹. The next <count> displayable characters in the data stream are used to fill it. Subsequent REPEAT subcommands can be used to specify what goes in this field 🧚. If the sender specifies attributes that haven't been agreed upon through the Format Facility subcommand, the Telnet process should send an Error Subcommand to the sender. It still formats the screen as if that bit hadn't been set 😭

IAC SB DET REPEAT <count><char> IAC SE
                                subcommand code:  36

Here <count> is a positive 8-bit binary integer, and <char> is an 8-bit byte holding an ASCII character 🌈

This subcommand is a little data compression trick for data going to the terminal πŸ—œοΈ. Strings of identical characters get encoded as the character plus a count ✨. The repeated characters might be part of a field that was specified

IAC SB DET SUPPRESS PROTECTION <negotiation> IAC SE
                                    subcommand code:  37

Where <negotiation> can have the values from Telnet option negotiation πŸ’œ

            251                 WILL
            252                 WONT
            253                 DO
            254                 DONT

This subcommand suppresses field protection in a non-destructive way 🫧. A lot of data entry terminals let you turn protection on and off without changing what's on the screen or in the terminal's memory πŸ¦‹. So protection can be turned off and back on again without re-sending the whole form πŸŽ€. The default setting is that protection is on, which means

IAC SB DET SUPPRESS PROTECTION WONT IAC SE
IAC SB DET SUPPRESS PROTECTION DONT IAC SE

Negotiating this subcommand follows the same rules as negotiating Telnet options 🀝

IAC SB DET FIELD SEPARATOR IAC SE    subcommand code:  38

When you're only sending the unprotected part of the screen, you need a way to mark where the fields start and stop 🧩. Existing DETs use all kinds of ASCII characters for this, like Tab, Group Separator, Unit Separator, and so on 🌸. To keep the NVDET transparent, this subcommand is used to separate the fields instead. Honestly, that comes with pretty high overhead 😩. You can avoid that overhead by using the Byte Macro Option (see Appendix 3) ✨

Miscellaneous Commands

IAC SB DET FN <code> IAC SE     subcommand code:  39

Where <code> is one byte πŸ”‘

Lots of data-entry terminals have a set of "function" keys. When you press one, it sends a one-character command to the server πŸ’–. This subcommand describes that facility. The values of the <code> field are defined by the user and the server 🫢. The option just gives them a way to transfer the information, nothing more πŸ“

IAC SB DET ERROR <cmd> <error code> IAC SE
                                subcommand code:  40

Where <cmd> is a byte holding the subcommand code of the subcommand that had the error, and <error code> is a byte holding an error code. (The defined error codes are listed in Appendix 2.) πŸ“‹

This subcommand exists so DET option implementations can report the errors they detect to the matching Telnet process 🚨. The philosophy of this option is that when an error is detected, it should be reported πŸ’…. Even so, the implementation should try its best to carry out the intent of the subcommand or the data that was in error 🌈

3. Default and Minimal Implementation Specifications ✨

Default

WON'T DET -- DON'T DET

Neither host wants to use the Data Entry Terminal option πŸ™…β€β™€οΈ

Minimal Implementation

DET EDIT FACILITIES
DET ERASE FACILITIES
DET TRANSMIT FACILITIES
DET FORMAT FACILITIES
DET MOVE CURSOR <x><y>
DET HOME
DET ERASE SCREEN
DET TRANSMIT SCREEN
DET FORMAT DATA
DET ERROR <cmd> <error code>

When it comes to formatting data, a minimal implementation should be able to support a low and a high level of intensity, plus protection for all or none of the characters in a field πŸ”†. Those functions are not required though 🫧

The minimal implementation also requires that the Output Line Width and Output Page Size Telnet options be supported πŸ“


4. Motivation 🌸

The Telnet protocol was originally designed to give scroll-mode terminals, like the standard teletype, a way to talk to processes over the network πŸ–¨οΈ. That was perfect for the vast majority of terminals and users back then πŸ•°οΈ. But as the network spread into other areas, especially ones where it's treated as a production environment for other work, what the user community wanted and needed changed πŸ“ˆ. So it became necessary to think about supporting facilities that weren't supported at the start πŸ’ͺ. This Telnet option tries to do that for applications that need data entry terminals ✨

This option basically defines the Network Virtual Data Entry Terminal πŸ–₯️. The description is pretty long, but that doesn't mean Telnet is a bad vehicle for this facility πŸ™‚. Data Entry Terminals are complex and varied in what they can do πŸŒ€. This option tries to support both the minimal set of useful functions that are common to all terminals (or easy to simulate) and the fancier functions some terminals have πŸ’œ

Most real data entry terminals encode their terminal functions into one or more characters of the native character set πŸ™ƒ. This option is different: it does all of those controls inside the Telnet subnegotiation mechanism πŸ”. That lets programs that know their terminal really well send commands the option or the implementation might not support 🧠. In other words, you can operate in a "raw" or at least "rare" mode using as much of the option as you need πŸ¦‹

Lots of data entry terminals support peripheral devices like printers and cassettes, but considering those is outside the scope of this option πŸ–¨οΈ. A separate option should be defined to handle that side of these devices πŸ“Ό

5. Description πŸŽ€

General Notes πŸ“

okay bestie, every implementation of this option is required to support a certain minimal set of subcommands 🫢 Section 3 has the complete list. Telnet is all about not making you parse commands you don't implement, so every subcommand of this option is either in that minimal set or covered by one of the facility subcommands πŸ’… An implementation must "negotiate" with its correspondent for permission before using any subcommand outside the minimal set. The negotiation details are in the facility subcommands section below ✨

Most data entry terminals run in half duplex mode πŸ¦‹ (most DET's on the market can act as data entry terminals or regular interactive terminals, but we're only talking about them as DET's here). When this option is in use, it is suggested that the Echo, Remote Controlled Transmission and Echoing, and Suppress Go-Ahead options be refused πŸ™ˆ BUT this option could also support a simple full duplex CRT based app using the basic cursor control functions here πŸ–₯️ For those cases, one or more of the options in that list might be required. (Fancy calligraphic interactive apps are out of scope for this option and should be handled by another option or the Network Graphics Protocol 🎨)

In RFC 728, it was noted that a synch sequence can cause messy interactions between Telnet Control functions and the data stream 😭 A synch sequence flushes data but not control functions. So if a control function that affects the data right after it is in the stream when a synch sequence happens, that control function ends up hitting the data after the Data Mark instead of the data it was meant for πŸ’€ The DET subcommands that are vulnerable to this are:

CHAR INSERT
DATA TRANSMIT
FORMAT DATA

The best way to dodge these undesired interactions is for the receiver of the synch sequence to delete these subcommands and all the data attached to them before it keeps processing control functions 🧹 Which means the Data Mark should not show up in the middle of the data tied to these subcommands 🚫


Facility Subcommands ✨

These four subcommands are how the User and Server implementations negotiate which subcommands and attributes of the terminal can be used πŸŽ€ Think of it like this: the terminal (User Host) says what facilities it has, and the Server Host (or application program) says what facilities it wants πŸ’–

When Sent: A Server Telnet implementation using the DET option must send a facility subcommand requesting a subcommand or terminal attribute that's not in the minimal implementation before the first time it uses that subcommand or attribute πŸ“¨ The User Telnet implementation should reply as quickly as possible πŸƒβ€β™€οΈ Neither the User nor the Server is required to negotiate one subcommand at a time πŸ™Œ A Telnet implementation replying to a facility subcommand also doesn't have to only give permission for that one subcommand. It can send a format map listing every facility in that class it supports πŸ—ΊοΈ However, a Telnet implementation that's requesting facilities must send a facility subcommand before its first use of the subcommand, even if earlier negotiations already showed the facility is provided 🫠 The facility can't be used until a matching facility subcommand has been received 🚦 There are no other constraints on when facility subcommands may be sent. In particular, an application doesn't need to know every facility it will use at the very start of a session πŸ₯°

ActionWhenReceived: There are two possible actions when a facility subcommand is received, depending on whether the receiver is a requestor or a provider (User) πŸ‘‘

Requestor: When a requestor gets a facility subcommand while it's in the state of Waiting for a Reply, it should move into the state of Not Waiting βœ… Then it takes the facility map it sent and forms the logical intersection with the facility map it received. (For the Intensity attribute, one should take the minimum of the number received and the number requested πŸ”’) The result shows which facilities were successfully negotiated πŸŽ‰ Note: if the receiver is not in the Waiting for Reply state, then this is the provider case we cover next πŸ‘€

Provider: When a facility subcommand is received, it should send a facility subcommand with a facility map of the facilities it provides as soon as possible ⚑ Then it works out what new facilities it's providing for the Requestor by forming the logical intersection of the facility map it received and the one it sent 🧠

Note: Even though the requestor is usually the Server Host and the provider is usually the User Host supporting the terminal, this distinction isn't always true 🌈


Transmit Subcommands πŸ¦‹

There are two kinds of transmit subcommands πŸ’… The first kind asks for data to be sent to the requestor. The second kind is used to preface data sent to the requestor. The first kind lets the requestor control when, from where, and to some degree how much data gets transmitted from the terminal 🎯 Their explanation is pretty straightforward and you can find it in Section 2 πŸ“–

Data can be sent from the terminal for two reasons: the terminal user caused the transmission, or it's a response to a transmit subcommand πŸ“€ Some programs want to know where on the screen the transmission started πŸ“ (That makes sense, since the terminal user might move the cursor all over the place before hitting transmit πŸƒβ€β™€οΈ) Other programs don't need that info at all πŸ€·β€β™€οΈ The DATA TRANSMIT subcommand exists for when that function is needed πŸŽ€ When it's used, this subcommand prefaces the data coming from the terminal. The parameters <x> and <y> give the screen coordinates of where the transmission begins πŸ“ <x> must be less than or equal to M-1, and <y> must be less than or equal to N-1 πŸ”’ It's assumed that all data between this DATA TRANSMIT and the next one starts at the coordinates given by the first subcommand, and keeps filling each line after that according to the screen's constraints and the format effectors in the data πŸ–οΈ So an intelligent (or sloppy, depending on your point of view 😏) user-host DET implementation only needs to include a DATA TRANSMIT subcommand when the new starting point is different from the last ending point 🫢


6. Sample Interaction 🧚

The nomenclature of RFC 726 will be used to describe this example πŸ“š To quote that RFC:

"S:"  is sent from serving host to using host.
"U:"  is sent from using host to serving host.
"T:"  is entered by the terminal user.
"P:"  is printed on the terminal.

Text surrounded by square brackets([]) is commentary πŸ’¬ Text surrounded by angle brackets (<>) is to be taken as a single unit 🧩 E.g., carriage return is <cr>, and the decimal value 27 is represented <27> πŸ”’

We assume the user has already established the Telnet connection, logged on, and an application program has just started, either by the user directly or through a canned start up procedure 🌸 The layout on the page is only there to group things together, and it doesn't imply where message boundaries are πŸ“„ You should assume any part of the dialogue might be sent as one message or as many πŸ“¬ The very first thing the program or Telnet does is negotiate the DET option 🀝

S: <IAC><DO><DET>

U:  <IAC><WILL><DET>

S:<IAC><DO><OUTPUT PAGE SIZE>           [First negotiate the screen
                                        size.  In this case we are
U:<IAC><WILL><NAOP>                     asking the user the size of the
                                        terminal.  This could have been
U:<IAC><SB><NAOP><DR><25><IAC><SE>      done before the DET option was
                                        negotiated.]
S:<IAC><SB><NAOP><DS><0><IAC><SE>

S:<IAC><DO><OUTPUT LINE WIDTH>

U:<IAC><SB><NAOL><DR><80><IAC><SE>      [Defines the screen to be 25
                                        lines by 80 characters.
S:<IAC><SB><NAOL><DS><0><IAC><SE>       The server may use this
                                        information when formatting
                                        the screen.]
S:<IAC><SB><DET><FORMAT FACILITIES>     [Now set the terminal attributes.]
  <Repeat><Protection, 3 Levels
  Intensity><IAC><SE>

U:<IAC><SB><DET><FORMAT FACILITIES>
  <Repeat, Blinking><Protection, 3
  Levels Intensity><IAC><SE>

S:<IAC><SB><DET><ERASE SCREEN><IAC><SE>     [Erase the screen and
                                            start sending the form.]
  <IAC><SB><DET><FORMAT DATA>
  <Protection=1, Intensity=1><0>
  <5><IAC><SE>Name:

  <IAC><SB><DET><MOVE CURSOR><0><1>
    <IAC><SE>

  <IAC><SB><DET><FORMAT DATA>
    Protection=1, Intensity=1><0>
    <8><IAC><SE>

  Address:
  <IAC><SB><MOVE CURSOR><0><4><IAC>
    <SE>

  <IAC><SB><DET><FORMAT DATA>
    Protection=1, Intensity=1><0>
    <17><IAC><SE>
  Telephone number:

  <IAC><SB><DET><MOVE CURSOR><32><4>
  <IAC><SE>

  <IAC><SB><DET><FORMAT DATA>
    Protection=1, Intensity=1><0>
    <24><IAC><SE>
  Social Security Number:

  <IAC><SB><DET><FORMAT DATA>           [Establish a field that doesn't
    <Protection=1, Intensity=7>         display what is typed into it.]
    <0><11><IAC><SE>

  <IAC><SB><DET><MOVE CURSOR><32>
    <5><IAC><SE>

  <IAC><SB><DET><FORMAT FACILITIES>     [Get permission to use Blinking
    <Blinking><0><IAC><SE>              Attribute.]

U:<IAC><SB><DET><FORMAT FACILITIES>
    <Repeat, Blinking><Protection,
    3 Levels Intensity><IAC><SE>

S:<IAC><SB><DET><FORMAT DATA>
  <Blinking=1, Protection=1,
  Intensity=1><0><29><IAC><SE>

  Your SSN will not be printed.

  <IAC><SB><DET><HOME><IAC><SE>

  <IAC><GA>

The previous exchange has put a form on the screen that looks like this πŸŽ€:

Name:
Address:


Telephone Number:                       Social Security Number:
                                   "Your SSN will not be printed."

where the quoted string is blinking ✨

The terminal user is now free to fill in the form πŸ’– They position the cursor at the beginning of the first field (this is usually done by hitting the tab key ⌨️) and start typing. We do not show

okay so the form is filled in and bestie, this is where it gets cute πŸŽ€ Before the terminal user hits transmit, the User Telnet program negotiates the Byte Macro Option so the Field Separator subcommand can be squished into a single byte πŸ¦‹. Here's how that goes:

U:<IAC><DO><BM>                         [Negotiate Byte Macro Option.]

S:<IAC><WILL><BM>                       [Define decimal 166 to be the
                                        Field Separator subcommand
U:<IAC><SB><BM><DEFINE>                 (see Appendix 3)]
  <166><6><IAC SB DET FIELD
  SEPARATOR IAC SE><IAC><SE>

S:<IAC><SB><BM><ACCEPT><166>            [The server accepts the macro.]
  <IAC><SE>


U:<IAC><SB><DET><DATA TRANSMIT><0><6>
  <IAC><SE>
  John Doe <166> 1515 Elm St., Urbana, Il 61801
  <166> 217-333-9999 <166> 123-45-6789 <166>

S:<IAC><SB><DET><ERASE SCREEN><IAC><SE>
  Thank you.

And so on. ✨


Appendix 1 - Subcommands, opcodes and syntax πŸ“‹

Here's the full subcommand menu, opcodes and all πŸ’… Yes, it's a lot, but every single one of these is a little character with a job 🧚

               1    EDIT FACILITIES     <Facilty map>
               2    ERASE FACILITIES    <Facility map>
               3    TRANSMIT FACILITIES <Facility map>
               4    FORMAT FACILITIES    <Facility map 1> <Facility map 2>
               5    MOVE CURSOR          <x> <y>
               6    SKIP TO LINE         <y>
               7    SKIP TO CHAR         <x>
               8    UP
               9    DOWN
               10   LEFT
               11   RIGHT
               12   HOME
               13   LINE INSERT
               14   LINE DELETE
               15   CHAR INSERT
               16   CHAR DELETE
               17   READ CURSOR
               18   CURSOR POSITION      <x><y>
               19   REVERSE TAB
               20   TRANSMIT SCREEN
               21   TRANSMIT UNPROTECTED
               22   TRANSMIT LINE
               23   TRANSMIT FIELD
               24   TRANSMIT REST OF SCREEN
               25   TRANSMIT REST OF LINE
               26   TRANSMIT REST OF FIELD
               27   DATA TRANSMIT <x><y>
               28   ERASE SCREEN
               29   ERASE LINE
               30   ERASE FIELD
               31   ERASE REST OF SCREEN
               32   ERASE REST OF LINE
               33   ERASE REST OF FIELD
               34   ERASE UNPROTECTED
               35   FORMAT DATA <format map>
               36   REPEAT     <count><char>
               37   SUPPRESS PROTECTION <negotiation>
               38   FIELD SEPARATOR
               39   FN <code>
               40   ERROR  <cmd><error code>

Appendix 2 - Error Codes 🚨

When something goes sideways, these are the codes that tell you what went wrong πŸ™ˆ Note that the list is printed exactly as it appears in the spec, duplicate "4"s included πŸ’€

               1    Facility not previously negotiated.
               2    Illegal subcommand code.
               3    Cursor Address Out of Bounds.
               4    Undefined FN value.
               4    Can't negotiate acceptable line width.
               5    Can't negotiate acceptable page length.
               6    Illegal parameter in subcommand.
               7    Syntax error in parsing subcommand.
               8    Too many parameters in subcommand.
               9    Too few parameters in subcommand.
               10   Undefined parameter value
               11   Unsupported combination of Format Attributes

Appendix 3 - Use of the Byte Macro Option πŸ§šβ€β™€οΈ

Okay, the big problem with the DET option is the overhead 😭 Since every function gets encoded as a Telnet option subnegotiation, a fairly high overhead piles up. A function like Character Insert is a single byte on most terminals, but in the DET option it takes six bytes. The only other way to get the same transparency that subcommands give you would have been to define extra Telnet control functions, but that would mean changing the Telnet protocol itself, and it was felt that this was not a wise move πŸ™…β€β™€οΈ

Then the Telnet Byte Macro Option (RFC 729) came along and saved the day ✨ It lets the user and server Telnets map an arbitrary character string into a single byte that gets sent over the net. So the Byte Macro Option gives implementations a way to skip the overhead for the subcommands that get used a lot. The rest of this appendix suggests how the Byte Macro Option could be applied to the DET option πŸ¦‹

Following the specification of the Byte Macro Option, macro bytes are picked from the range 128 to 239. For the DET option, the suggestion is to choose macro bytes by adding the subcommand code to 128. There's also an idea for an unofficial DET subcommand, which would say that each side is willing to support macro bytes for all subcommands (without necessarily supporting all of the subcommands themselves) using this algorithm. That subcommand would look like this:

IAC SB DET DET-MACRO <negotiation> IAC SE
                                   subcommand code:  254

where <negotiation> may have the values of the Telnet option negotiation:

               251       WILL
               252       WONT
               253       DO
               254       DONT

A Telnet implementation sends this subcommand to say it's willing to adopt byte macros for all of the DET subcommands, following this algorithm:

The macro byte for subcommand i will be i+128 and will represent the following string for parameterless subcommands:

IAC SB DET <subcommand code> IAC SE

and the following string for subcommands with parameters:

IAC SB DET <subcommand code>

The default setting for this subcommand is that the macros are not in effect, in other words:

     IAC SB DET DET-MACRO WONT IAC SE
     IAC SB DET DET-MACRO DONT IAC SE

Negotiation of this subcommand follows the same rules as negotiations of the Telnet options. 🫢


References πŸ“š

  1. ADM-1 Interactive Display Terminal Operator's Handbook, Lear-Siegler, Inc. 7410-31.
  2. ADM-Interactive Display Terminal Operator's Handbook, Lear-Siegler, Inc. EID, 1974.
  3. Burroughs TD 700/800 Reference Manual, Burroughs Corp., 1973
  4. Burroughs TD 820 Reference Manual, Burroughs Corp. 1975.
  5. CC-40 Communications Station: General Information Manual. Computer Communication, Inc. Pub. No. MI-1100. 1974.
  6. Crocker, David. "Telnet Byte Macro Option," RFC 729, 1977.
  7. Data Entry Virtual Terminal Protocol for Euronet, DRAFT, 1977.
  8. Day, John. "A Minor Pitfall in the Telnet Protocol," RFC 728, 1977.
  9. Hazeltine 2000 Desk Top Display Operating Instructions. Hazeltine IB-1866A, 1870.
  10. How to Use the Consul 980: A Terminal Operator's Guide and Interface Manual. Applied Digital Data Systems, Inc. 98-3000.
  11. How to Use the Consul 520: A Terminal Operator's Guide and Interface Manual. Applied Digital Data Systems, Inc. 52-3000.
  12. Honeywell 7700 Series Visual Information Projection (VIP) Systems: Preliminary Edition. 1973.
  13. An Introduction to the IBM 3270 Information Display System. IBM GA27-2739-4. 1973.
  14. Naffah, N. "Protocole Appareil Virtuel type Ecran" Reseau Cyclades. TER 536. 1976.
  15. Postel, Jon and Crocker, David. "Remote Controlled Transmission and Echoing Telnet Option", RFC 726 NIC 39237, Mar. 1977.
  16. Schicker, Peter. "Virtual Terminal Protocol (Proposal 2). INWG Protocol Note #32., 1976.
  17. UNISCOPE Display Terminal: Programmer Reference. Sperry-Univac UP-7807 Rev. 2, 1975.
  18. Universal Terminal System 400: System Description. Sperry-Univac UP-8357, 1976.
  19. Walden, David C. "Telnet Output Line Width Option." NIC # 20196, 1973, also in ARPANET Protocol Handbook, 1976.
  20. Walden, David C. "Telnet Output Page Size" NIC # 20197, 1973, also in ARPANET Protocol Handbook, 1976.

That's the whole RFC, bestie! πŸŒˆπŸ‘‘

πŸ“¦ where this page comes from