Telnet "More?"

I’m trying to use the telnet library. I don’t know Ruby AT ALL
(evaluating it side by side with Python to see which is going to be best
for my admin chores; this is my very first script), and this has got me
stumped:

require ‘net/telnet’
t = Net::Telnet::new(
‘Host’ => ‘somehost.com’,
‘Prompt’ => /:.*>/,
)
out = lambda do |c| print c end
t.login(‘someusername’, ‘somepassword’, &out)
t.cmd(‘dir’, &out)
t.cmd(‘dir’, &out)

The second dir command hangs with the server responding “More?” Here’s
the tail end of the output log, after the first dir command:


04/13/2011 04:21 PM Searches
04/13/2011 04:21 PM Videos
04/16/2011 12:54 AM 6,558 _viminfo
1 File(s) 6,558 bytes
13 Dir(s) 279,022,981,120 bytes free

C:\Users\foo>dir
More?

And it just hangs there.

Full logs here (names changed to protect the innocent):
File Not Found
http://tetzfiles.com/temp/dump_log

This is a bitch to Google (“?” is ignored), but I found someone else
asking the same question on Stackoverflow, but he got no response
(Ruby Telnet Lib - Weird Response - Stack Overflow).
You guys could help both of us out. :slight_smile:


In a slightly unrelated question, I don’t understand why I have to do
this:

out = lambda do |c| print c end
t.login(‘someusername’, ‘somepassword’, &out)
t.cmd(‘dir’, &out)
t.cmd(‘dir’, &out)

Rather than simply this:

t.login(‘someusername’, ‘somepassword’, &print)
t.cmd(‘dir’, &print)
t.cmd(‘dir’, &print)

Seems kinda pointless to make a function which does nothing but pass
it’s arguments unaltered to another function.

On Sun, Apr 17, 2011 at 12:10 AM, Eric T. [email protected] wrote:

out = lambda do |c| print c end
04/16/2011 12:54 AM 6,558 _viminfo
1 File(s) 6,558 bytes
13 Dir(s) 279,022,981,120 bytes free

C:\Users\foo>dir
More?

And it just hangs there.

It looks like the server is sending something other than the default
prompt and expecting a response; you probably need to handle that
case.

If you use telnet directly (from the console, not a script) and do the
same sequence of commands, what happens?

t.login(‘someusername’, ‘somepassword’, &print)
t.cmd(‘dir’, &print)
t.cmd(‘dir’, &print)

Seems kinda pointless to make a function which does nothing but pass
it’s arguments unaltered to another function.

Ruby is unlike Python in that, while it has functions that are objects
(e.g., Proc objects), methods (including Kernel#print) are not
functions (or objects). So you are creating a function that performs a
method call against the object that is the current value of “self”
passing that method the same arguments that the function was called
with, not creating a function that calls a function with the same
arguments the first function is called with.

You could capture the method as a callable, function-like object with
self.method(:print) instead of an explicit lambda declaration, which
makes the difference more clear, but is somewhat less concise in this
case.

Eric T. wrote in post #993311:

In a slightly unrelated question, I don’t understand why I have to do
this:

out = lambda do |c| print c end
t.login(‘someusername’, ‘somepassword’, &out)
t.cmd(‘dir’, &out)
t.cmd(‘dir’, &out)

Rather than simply this:

t.login(‘someusername’, ‘somepassword’, &print)
t.cmd(‘dir’, &print)
t.cmd(‘dir’, &print)

Seems kinda pointless to make a function…

Which function are you referring to??

which does nothing but pass
it’s arguments unaltered to another function.

Yes, that would be pointless, but where does such a function appear in
your code?

In your code, the & does two things:

  1. It calls to_proc() on the specified object. print() is a method of
    the Kernel module, and Kernel doesn’t define to_proc().

  2. It tells ruby to use the resulting Proc object as a block for the
    method call.

Christopher D. wrote in post #993345:

It looks like the server is sending something other than the default
prompt and expecting a response; you probably need to handle that
case.

Yes, but I’m wondering why this happens with the Ruby client. It’s
hard as hell to search the web for the “More?” response, because search
engines ignore the “?” leaving you search for “More” (pun not indented,
but apropos).

If you use telnet directly (from the console, not a script) and do the
same sequence of commands, what happens?

It works fine. It also works fine using the Python client.

But so far, in my extremely superficial comparison of the languages, I’m
liking Ruby better. I like that regex is a first class citizen (/f?o/i
is a hell of a lot better than re.compile(‘f?o’, re.IGNORECASE)), and I
like the implementation of Ruby’s telnet library better (passing blocks
to receive output is a nice touch). Unfortunately, a straight-forward
use of the library is provoking a weird response from the server.

7stud – wrote in post #993403:

Yes, that would be pointless, but where does such a function appear in
your code?

That would be (I thought) the ‘out’ lambda, but as Christopher
explained, print is actually a method (not obvious if you don’t know
Ruby), so it makes more sense that a closure is required.

In Lua, for instance, print is a global function, so making a closure
‘function out(…) print(…) end’ would be utterly superfluous;
anything you could pass ‘out’ to you could just pass ‘print’ to.

It still strikes me odd that Kernel#print is not static (does it modify
Kernel state?), or if it is static that you can’t just pass it as-is
to anything that requires a callable.

On 17-Apr-2011, “mouser” [email protected] wrote:

@telnet_options[“BINARY”] and @telnet_options[“SGA”]

I should have written @telnet_option… not @telnet_options

On 16-Apr-2011, “Eric T.” [email protected] wrote:

This is a bitch to Google (“?” is ignored), but I found someone else
asking the same question on Stackoverflow, but he got no response
(Ruby Telnet Lib - Weird Response - Stack Overflow).
You guys could help both of us out. :slight_smile:

I was able to reproduce your problem in Ruby 1.9.2 but not 1.8.7,
against an
MS telnet server instance. It appears to be some kind of character
encoding
problem that prevents certain telnet options from being set to true
(@telnet_options[“BINARY”] and @telnet_options[“SGA”]). I haven’t tried
any
other telnet servers, so it may not manifest itself against every
server,
and granted MS Telnet services are known to be pretty bad. I may look
into
it further if I have the time, but you might want to continue your
experiments in 1.8.7 for now. For anyone else interested in looking at
this, you might look at some of the string.gsub calls in the preprocess
instance method of Net::Telnet, I suspect this might be part of the
problem.

On Sun, Apr 17, 2011 at 5:48 PM, Eric T. [email protected] wrote:

It still strikes me odd that Kernel#print is not static (does it modify
Kernel state?), or if it is static that you can’t just pass it as-is
to anything that requires a callable.

Methods (like blocks) aren’t objects, though (like blocks) they can be
reified as objects, consequently methods, as such, can’t be passed to
other methods. (One side effect – or possibly motivating reason –
for this is that Ruby methods can be called without parens, including
no-arg methods. If methods were objects accessible by the method name,
reference to the method as an object would be – assuming the most
obvious syntax – ambiguous with a method call without parens.)

And Ruby doesn’t have static methods the way Java does. While Ruby
does have class/module methods, they are just instance methods on an
object (because in Ruby, classes and modules are objects.)

Eric T. wrote in post #993311:

t.cmd(‘dir’, &out)
t.cmd(‘dir’, &out)

t.cmd is really shorthand for t.puts followed by t.waitfor

So you could try something like this:

def cmd_or_more(str, &blk)
t.puts str
loop do
res = t.waitfor(/:.>|More?/, &blk)
break if res =~ /:.
>/
t.puts “”
end
end

t.cmd_or_more(‘dir’, &out)
t.cmd_or_more(‘dir’, &out)

Of course, if the question is really “why does Microsoft hang with a
‘More?’ prompt when dir is issued a second time”, then this isn’t really
the right solution.

It would be better if you could issue some command to the CLI to say “no
pager” - like “term len 0” on a Cisco router.

Regards,

Brian.

On 19-Apr-2011, Brian C. [email protected] wrote:

Of course, if the question is really “why does Microsoft hang with a
‘More?’ prompt when dir is issued a second time”, then this isn’t really
the right solution.

But I found that his code does work in 1.8.7 but not in 1.9.2, so it’s
not
just Microsoft’s fault. It looked to me to be a difference in character
encodings between the two versions of Ruby causing some issues with
regex
matching in the preprocess instance method.

Content preview: On 19.04.2011 18:40, mouser wrote: > On 19-Apr-2011,
Brian
Candler [email protected] wrote: > >> Of course, if the question
is really
“why does Microsoft hang with a >> ‘More?’ prompt when dir is issued
a second
time”, then this isn’t really >> the right solution. > > But I found
that
his code does work in 1.8.7 but not in 1.9.2, so it’s not > just
Microsoft’s
fault. It looked to me to be a difference in character > encodings
between
the two versions of Ruby causing some issues with regex > matching
in the
preprocess instance method. […]

Content analysis details: (-2.9 points, 5.0 required)

pts rule name description



-1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP
-1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
[score: 0.0000]
X-Cloudmark-Analysis: v=1.1
cv=Nww7yNiXF4C1XGF+VcigPkOcTpD8wJaI1KQuZlH5eEk= c=1 sm=0
a=aofHTkXiRO8A:10 a=IkcTkHD0fZMA:10 a=ybZZDoGAAAAA:8 a=W9UtoakOAAAA:8
a=5-KrP8fCEEKGw1YiS0UA:9 a=QEXdDO2ut3YA:10 a=qIVjreYYsbEA:10
a=HpAAvcLHHh0Zw7uRqdWCyQ==:117
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
Precedence: bulk
Lines: 20
List-Id: ruby-talk.ruby-lang.org
List-Software: fml [fml 4.0.3 release (20011202/4.0.3)]
List-Post: mailto:[email protected]
List-Owner: mailto:[email protected]
List-Help: mailto:[email protected]?body=help
List-Unsubscribe: mailto:[email protected]?body=unsubscribe
Received-SPF: none (Address does not pass the Sender Policy Framework)
SPF=FROM;
[email protected];
remoteip=::ffff:221.186.184.68;
remotehost=carbon.ruby-lang.org;
helo=carbon.ruby-lang.org;
receiver=eq4.andreas-s.net;

On 19.04.2011 18:40, mouser wrote:

On 19-Apr-2011, Brian C. [email protected] wrote:

Of course, if the question is really “why does Microsoft hang with a
‘More?’ prompt when dir is issued a second time”, then this isn’t really
the right solution.

But I found that his code does work in 1.8.7 but not in 1.9.2, so it’s not
just Microsoft’s fault. It looked to me to be a difference in character
encodings between the two versions of Ruby causing some issues with regex
matching in the preprocess instance method.

Is it maybe a similar issue I faced with Sinatra recently [1]? In 1.9
strings coming over network are in ASCII-8BIT usually and you’ve to
convert them to char charset to work with them.

HTH,

  • Markus

[1] SQLite3/Sinatra not returning results - Ruby - Ruby-Forum

solved. the reason is ruby net/telnet library use error newline
seperator. Must be EOL(CR+LF) but CR+NULL . But I don’t know who make
the bug,windows or ruby? I write a monkey patch as below:

class Net::Telnet
  def print(string)
      string = string.gsub(/#{IAC}/no, IAC + IAC) if

@options[“Telnetmode”]

      if @options["Binmode"]
        self.write(string)
      else
        if @telnet_option["BINARY"] and @telnet_option["SGA"]
          self.write(string.gsub(/\n/n, CR))
        elsif @telnet_option["SGA"]
          self.write(string.gsub(/\n/n, EOL)) ### fix here. reaplce

CR+NULL bY EOL
else
self.write(string.gsub(/\n/n, EOL))
end
end
end
end

Eric T. wrote in post #993412:

7stud – wrote in post #993403:

Yes, that would be pointless, but where does such a function appear in
your code?

That would be (I thought) the ‘out’ lambda,

Ahh, I see.

but as Christopher
explained, print is actually a method (not obvious if you don’t know
Ruby),

Ok.

so it makes more sense that a closure is required.

In Lua, for instance, print is a global function,

print() acts like a global function in ruby. Kernel is “mixed into” the
Object class (which means the methods act like they are defined in the
Object class itself), and all objects inherit from Object, which means
any object can call the methods defined in Kernel. And because the
methods defined in Kernel are private, you cannot specify a receiver
when calling the methods, and therefore calling a Kernel method looks
like calling a global method in any other language.

or if it is static that you can’t just pass it as-is
to anything that requires a callable.

The problem is that, in ruby, the name of a method is not a reference to
the method. Rather, the name of the method serves as a method call with
no arguments.

Jon L. wrote in post #1108363:

       elsif @telnet_option["SGA"]
         self.write(string.gsub(/\n/n, EOL)) ### fix here. reaplce

CR+NULL bY EOL
else
self.write(string.gsub(/\n/n, EOL))
end

That’s not a bug. CR+NUL is correct.

I captured the network packages of the telnet process of python and
ruby.And found the only difference is the newline separator. I didn’t
read the telnet protocol,so I can’t sure which side make the bug.

I know it is not a real solution.Could you kindly tell me the real
reason and solution?

       elsif @telnet_option["SGA"]
         self.write(string.gsub(/\n/n, EOL)) ### fix here. reaplce

CR+NULL bY EOL
else
self.write(string.gsub(/\n/n, EOL))
end

That’s not a bug. CR+NUL is correct.