30 Aug, 2013, THUFIR wrote in the 1st comment:
Votes: 0
I'm trying to figure out telnet for a MUD client. The problem is that the second to last line can get parsed fine, because it terminates with CRLF (as per telnet rfc's).

However, if input is expected, the line might *not* terminate, it must just stop on "login" or might stop on whatever.

so, how do you "get" that very last line?

Here's my horrible kludge:

http://stackoverflow.com/a/18521863/2628...

However, that's just horrible, horrible. Surely this is a solved problem. How do MUD clients get all the lines, even ones which don't terminate correctly?
30 Aug, 2013, plamzi wrote in the 2nd comment:
Votes: 0
Is there a particular reason why you want to read the input line by line at this early stage?

The clients I have coded just read all available input. If they need to evaluate the input line by line, they take into account the fact that in the MUD world, exceptions are more than standards, so they try to split by \r\n, \n\r, then just \n, and strip away leftover \r's… You get the picture.

If for some reason you're looking to detect a "prompt for user input" unterminated line, you would normally know something about it that would help you detect it and respond to it. Just looking if the last line doesn't have a CR or LB is not enough–it could be that it's a split packet and there's more input coming.
30 Aug, 2013, Idealiad wrote in the 3rd comment:
Votes: 0
hey THUFIR, nice to see you here at MB, I commented on some of your SO questions. plamzi is exactly right, you seem to be hung up on reading line by line from the input when most (all?) mud clients and servers will read character by character (i.e. byte by byte), scanning for new line characters as plamzi noted.

For prompts some muds (not all?) will send a telnet IAC GA, or some other idiosyncratic combinations…basically you need to follow the principle of 'liberal what you accept, and strict in what you send'.

Anyway, it could be that the examples you're following (that weather app for example from SO) are not good examples for mud client/server stuff. I recommend you look at this instead,

http://cryosphere.net/mud-protocol.html

It's not the last word but it'll give you a good head start.
30 Aug, 2013, THUFIR wrote in the 4th comment:
Votes: 0
Idealiad said:
hey THUFIR, nice to see you here at MB, I commented on some of your SO questions. plamzi is exactly right, you seem to be hung up on reading line by line from the input when most (all?) mud clients and servers will read character by character (i.e. byte by byte), scanning for new line characters as plamzi noted.


Ah, that's fine. I notice that MUD's, and the weather telnet service, will say "press enter to continue", or similar, *without* a corresponding LFCR, which led to this madness:

http://stackoverflow.com/a/18521863/2628...

so, it occurs to, as you say above, and plamzi noted, just read byte by byte (wish I'd known that earlier!). Ok, that's solved :)

Now to handle input. If the terminal is filled with output, there's no prompt, or at least no space to type. So, I think the solution is to split the console into panes:

http://stackoverflow.com/q/18523767/2628...


Thank you very much for for the responses here and at StackOverflow :)


I'll read the guide and think it through….

I'm stuck on, I think, this factor:

"However, GUI apps will need to be able to distinguish a prompt from a line that just hasn't come in yet. "
30 Aug, 2013, plamzi wrote in the 5th comment:
Votes: 0
THUFIR said:
"However, GUI apps will need to be able to distinguish a prompt from a line that just hasn't come in yet. "


Based on experience, you can't rely on a MUD sending you the control characters described in that article, or anything else "by the book" for that matter, unless you're only connecting the client to one MUD server that you can tailor.

What exactly are you making and why do you feel it's important for the client itself (as opposed to the user) to recognize a prompt-type line?

Usually, I find it helpful to start thinking from the result, backward to what it would take to get there.
30 Aug, 2013, Scandum wrote in the 6th comment:
Votes: 0
Some clients will terminate input with \r or \r\0 , so you should treat any combination of \n\r \r \n or \r\n as a linebreak when dealing with input. That should solve your problem.
30 Aug, 2013, quixadhal wrote in the 7th comment:
Votes: 0
It's often useful to normalize input to a known value.

For example, when reading the input buffers, search for \r or \n, and when you find one, look both ahead and behind for the opposite. If you find \r, also look for a \0 following it. Whatever you find, translate it to a single token, either \r\n if you want to remain network friendly, or \n if you want to be unix friendly. That way, all the rest of your MUD code can assume that line ending is what will be there.

The TELNET spec says use CRLF (\r\n), and if you want to send a CR by itself, use CR NUL (\r\0).
30 Aug, 2013, THUFIR wrote in the 8th comment:
Votes: 0
So, what I have is:

thufir@dur:~$
thufir@dur:~$ java -jar NetBeansProjects/WeatherTelnet/dist/WeatherTelnet.jar
—————————————————————————–
* Welcome to THE WEATHER UNDERGROUND telnet service! *
——————————————————————————
* *
* National Weather Service information provided by Alden Electronics, Inc. *
* and updated each minute as reports come in over our data feed. *
* *
* **Note: If you cannot get past this opening screen, you must use a *
* different version of the "telnet" program–some of the ones for IBM *
* compatible PC's have a bug that prevents proper connection. *
* *
* comments: jmasters@wunderground.com *
——————————————————————————

Press Return to continue:
^Cthufir@dur:~$
thufir@dur:~$ cat NetBeansProjects/WeatherTelnet/src/weathertelnet/WeatherTelnet.java
package weathertelnet;

import java.io.Console;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.SocketException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.net.telnet.TelnetClient;

public final class WeatherTelnet implements Runnable {

@Override
public void run() {
new Thread(new Runnable() {

@Override
public void run() {
try {
consoleOutput();
} catch (SocketException ex) {
Logger.getLogger(WeatherTelnet.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(WeatherTelnet.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();


new Thread(new Runnable() {

@Override
public void run() {
consoleInput();
}
}).start();
}

public void consoleInput() {
}

public void consoleOutput() throws SocketException, IOException {
TelnetClient tc;
tc = new TelnetClient();
tc.connect("rainmaker.wunderground.com", 3000);

InputStream inputStream = tc.getInputStream();

char ch = (char) inputStream.read();

while (255 > ch && ch >= 0) {
ch = (char) inputStream.read();
PrintWriter foo = c.writer();
foo.print(ch);
foo.flush();
}
}
private Console c;

public WeatherTelnet() {
c = System.console();
run();
}

public static void main(String[] args) {
new WeatherTelnet();
}
}
thufir@dur:~$


and, maybe I was tired, but last night I thought I needed Swing for both input/output, but I don't think that's necessary. I would rather deal in lines then char, but there you are. I guess I can always parse it later for CRLF. At least I learned something (painfully!) about how telnet works and how to read it (byte by byte).
30 Aug, 2013, THUFIR wrote in the 9th comment:
Votes: 0
Well, that was total red herring. I tried to re-implement the utility class, but didn't realize what was involved. Eventually I gave up, and then went back to look at the sample Apache code and remembered what it was that the utility class was doing! For now, I think I'll leave the utility class alone:


package weathertelnet;

import examples.util.IOUtil;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Properties;
import org.apache.commons.net.telnet.TelnetClient;

public class WeatherTelnet {

private TelnetClient telnetConnection = new TelnetClient();

public WeatherTelnet() throws SocketException, IOException {
System.out.println("weather telnet..");
Properties props = PropertiesReader.getProps();
InetAddress host = InetAddress.getByName(props.getProperty("host"));
int port = Integer.parseInt(props.getProperty("port"));
telnetConnection.connect(host, port);
System.out.println("connected");
IOUtil.readWrite(telnetConnection.getInputStream(), telnetConnection.getOutputStream(), System.in, System.out);
}

public static void main(String[] args) throws SocketException, IOException {
System.out.println("main…");
new WeatherTelnet();
}
}


anyhow, that runs and manages i/o correctly. sigh.
31 Aug, 2013, THUFIR wrote in the 10th comment:
Votes: 0
for what it's worth, here's my "solution":

http://stackoverflow.com/a/18552406/2628...


for how print and store (in order to later parse) the InputStream from the MUD server. Had a very hard time with it, hope that was the big hurdle.
22 Jun, 2016, keevitaja wrote in the 11th comment:
Votes: 0
Hi!

If anyone is wondering, how to detect the lines in nodejs then here is a little snipped.
"use strict";

const net = require('net');

const socket = net.createConnection(6555, '198.178.123.109', ()=> {
process.stdin.pipe(socket);
});

let line = '';

socket.on('data', chunk => {
let str = chunk.toString();

for (let i = 0, len = str.length; i < len; i++) {
let chr = str[i];
line += chr;

process.stdout.write(chr);

if (/[\n\r]$/.test(chr)) {
process.stdout.write(line);
line = '';
}
}
});


So this code just duplicates each line. But you could just fire an event and passing the line variable.
0.0/11