Telnet "More?"

E

Eric T.

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 <DIR> Searches
04/13/2011 04:21 PM <DIR> 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):
http://tetzfiles.com/temp/output_log
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
(http://stackoverflow.com/questions/3450942/ruby-telnet-lib-weird-response).
You guys could help both of us out. :)

------------------------------------------------------------------

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.
 
C

Christopher Dicely

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:

=C2=A0 require 'net/telnet'
=C2=A0 t =3D Net::Telnet::new(
=C2=A0 =C2=A0 =C2=A0'Host' =C2=A0 =C2=A0 =C2=A0 =3D> 'somehost.com',
=C2=A0 =C2=A0 =C2=A0'Prompt' =C2=A0 =C2=A0 =3D> /:.*>/,
=C2=A0 )
=C2=A0 out =3D lambda do |c| print c end
=C2=A0 t.login('someusername', 'somepassword', &out)
=C2=A0 t.cmd('dir', &out)
=C2=A0 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:

=C2=A0 ...
=C2=A0 04/13/2011 =C2=A004:21 PM =C2=A0 =C2=A0<DIR> =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0Searches
=C2=A0 04/13/2011 =C2=A004:21 PM =C2=A0 =C2=A0<DIR> =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0Videos
=C2=A0 04/16/2011 =C2=A012:54 AM =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 6,558 _viminfo
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A01 File(s) =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A06,558 bytes
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 13 Dir(s) =C2=A02= 79,022,981,120 bytes free

=C2=A0 C:\Users\foo>dir
=C2=A0 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?
In a slightly unrelated question, I don't understand why I have to do
this:

=C2=A0 out =3D lambda do |c| print c end
=C2=A0 t.login('someusername', 'somepassword', &out)
=C2=A0 t.cmd('dir', &out)
=C2=A0 t.cmd('dir', &out)

Rather than simply this:

=C2=A0 t.login('someusername', 'somepassword', &print)
=C2=A0 t.cmd('dir', &print)
=C2=A0 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.
 
7

7stud --

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 Proc object as a block.
 
E

Eric T.

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.
 
E

Eric T.

Christopher Dicely 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.
 
C

Christopher Dicely

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.)
 
B

Brian Candler

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.
 
M

Markus Fischer

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] http://www.ruby-forum.com/topic/476119#989522
 
7

7stud --

Eric T. wrote in post #993412:
7stud -- wrote in post #993403:

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),

print() is a method in python3 as well.
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, from which all objects inherit, 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.

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top