telnetlib
telnetlib is a networking library for doing Telnet. It is ported from Python's telnetlib library and quite useful for writing automatical scripts.

ASDF-install package (obsolete) http://telnetlib-for-common-lisp.googlecode.com/files/telnetlib-for-common-lisp-20080103.zip

<!-- body { color: #000000; background-color: #cce8cf; } .builtin { /* font-lock-builtin-face */ color: #da70d6; } .comment { /* font-lock-comment-face */ color: #b22222; } .comment-delimiter { /* font-lock-comment-delimiter-face */ color: #b22222; } .function-name { /* font-lock-function-name-face */ color: #0000ff; } .keyword { /* font-lock-keyword-face */ color: #a020f0; } .string { /* font-lock-string-face */ color: #bc8f8f; } .type { /* font-lock-type-face */ color: #228b22; }

a { color: inherit; background-color: inherit; font: inherit; text-decoration: inherit; } a:hover { text-decoration: underline; } -->

<span class="comment-delimiter">;; </span><span class="comment">-*- MODE: LISP -*-
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">Brian Jiang (brianjcj AT gmail.com)
</span><span class="comment-delimiter">;; </span><span class="comment">2007-11
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">TelnetLib
</span><span class="comment-delimiter">;; </span><span class="comment">=========
</span><span class="comment-delimiter">;; </span><span class="comment">In our ordinary work, we often write some automatically scripts
</span><span class="comment-delimiter">;; </span><span class="comment">which login in the server to run some commands and performce some
</span><span class="comment-delimiter">;; </span><span class="comment">actions based on the result of the commands. In this case, a telnet
</span><span class="comment-delimiter">;; </span><span class="comment">client library will be very helpful. Such a library is very handy
</span><span class="comment-delimiter">;; </span><span class="comment">in Perl, Python and Ruby. But I googled it a lot and failed to find
</span><span class="comment-delimiter">;; </span><span class="comment">one in Common Lisp. So I decided to port the Telnetlib from Python
</span><span class="comment-delimiter">;; </span><span class="comment">to Common Lisp. Why port from Python? Because I am more familiar
</span><span class="comment-delimiter">;; </span><span class="comment">with Python and have use its TelnetLib before :-) 
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">The functionality of this library is almost the same as Python's
</span><span class="comment-delimiter">;; </span><span class="comment">one.  But the interface is a little different.
</span>

<span class="comment-delimiter">;; </span><span class="comment">Supported Lisp implementations
</span><span class="comment-delimiter">;; </span><span class="comment">==============================
</span><span class="comment-delimiter">;; </span><span class="comment">- SBCL
</span><span class="comment-delimiter">;; </span><span class="comment">- LispWorks
</span><span class="comment-delimiter">;; </span><span class="comment">- Allegro CL
</span><span class="comment-delimiter">;; </span><span class="comment">- CLISP
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">TelnetLib also supports other Lisp implementations (require USOCKET
</span><span class="comment-delimiter">;; </span><span class="comment">and FLEXI-STREAMS) . But I have never done any testing for them.
</span>
<span class="comment-delimiter">;; </span><span class="comment">Testing:
</span><span class="comment-delimiter">;; </span><span class="comment">--------
</span><span class="comment-delimiter">;; </span><span class="comment">TelnetLib has been tested in following environment:
</span><span class="comment-delimiter">;;   </span><span class="comment">- sbcl-1.0.11-x86-linux
</span><span class="comment-delimiter">;;   </span><span class="comment">- LispWorks in Windows XP
</span><span class="comment-delimiter">;;   </span><span class="comment">- Allegro CL in Windows XP
</span><span class="comment-delimiter">;;   </span><span class="comment">- CLISP 2.43 in Linux
</span><span class="comment-delimiter">;;   </span><span class="comment">- CLISP 2.41 in Windows XP
</span><span class="comment-delimiter">;;</span><span class="comment">
</span><span class="comment-delimiter">;; </span><span class="comment">But it failed in sbcl-1.0.9 in Windows XP. Error occurs
</span><span class="comment-delimiter">;; </span><span class="comment">when writing the socket stream.
</span>

<span class="comment-delimiter">;; </span><span class="comment">Library Dependency
</span><span class="comment-delimiter">;; </span><span class="comment">==================
</span><span class="comment-delimiter">;; </span><span class="comment">For SBCL, LispWorks, Allegro CL and CLISP, it only depends on
</span><span class="comment-delimiter">;; </span><span class="comment">CL-PPCRE.
</span><span class="comment-delimiter">;; </span><span class="comment">For other Lisp implementations, USOCKET and FLEXI-STREAMS (to
</span><span class="comment-delimiter">;; </span><span class="comment">set the external-format) are also required.
</span>
<span class="comment-delimiter">;; </span><span class="comment">Known Problem
</span><span class="comment-delimiter">;; </span><span class="comment">=============
</span><span class="comment-delimiter">;; </span><span class="comment">Don't work well when telent localhost. It seems it is due to the process/thread
</span><span class="comment-delimiter">;; </span><span class="comment">schedule mechanism. Will try to fix it in the future.
</span>
<span class="comment-delimiter">;; </span><span class="comment">How to use it
</span><span class="comment-delimiter">;; </span><span class="comment">=============
</span>
<span class="comment-delimiter">;; </span><span class="comment">Export functions/macros:
</span><span class="comment-delimiter">;; </span><span class="comment">------------------------
</span>(<span class="keyword">defun</span> <span class="function-name">open-telnet-session</span> (host <span class="type">&optional</span> port)...)
(<span class="keyword">defun</span> <span class="function-name">close-telnet-session</span> (tn)....)
(<span class="keyword">defmacro</span> <span class="function-name">with-telnet-session</span> ((tn host <span class="type">&optional</span> port) <span class="type">&body</span> body)....)
(<span class="keyword">defun</span> <span class="function-name">set-telnet-session-option</span> (tn
                                  <span class="type">&key</span> (remove-return-char nil r-r-c-p)
                                  (debug-on nil debug-on-p)
                                  (char-callback nil char-callback-p)
                                  (option-callback nil option-callback-p)
                                  (sb-option-callback nil sb-option-callback-p))...)
(<span class="keyword">defun</span> <span class="function-name">peek-available-data</span> (tn <span class="type">&optional</span> block-read)....)
(<span class="keyword">defun</span> <span class="function-name">read-available-data</span> (tn <span class="type">&optional</span> block-read)....
(<span class="keyword">defun</span> <span class="function-name">read-until</span> (tn str <span class="type">&key</span> (timeout 600) case-insensitive-mode)....)
(<span class="keyword">defun</span> <span class="function-name">read-until-2</span> (tn strings <span class="type">&key</span> (timeout 600) case-insensitive-mode)....)
(<span class="keyword">defun</span> <span class="function-name">read-until-2-ind</span> (tn strings <span class="type">&key</span> (timeout 600) case-insensitive-mode)....)
(<span class="keyword">defun</span> <span class="function-name">expect</span> (tn regexp <span class="type">&optional</span> (timeout 600))....)
(<span class="keyword">defun</span> <span class="function-name">format-tn</span> (tn control-string <span class="type">&rest</span> format-arguments)....)
(<span class="keyword">defun</span> <span class="function-name">write-ln</span> (tn str)....)
(<span class="keyword">defun</span> <span class="function-name">write-ln-crlr</span> (tn str)....)


<span class="comment-delimiter">;; </span><span class="comment">Example:
</span><span class="comment-delimiter">;; </span><span class="comment">--------
</span>(<span class="keyword">defun</span> <span class="function-name">example-1</span> ()
  (with-telnet-session (tn <span class="string">"202.38.33.94"</span>)

    (set-telnet-session-option tn <span class="builtin">:remove-return-char</span> t)
    
    (read-until tn <span class="string">"ogin:"</span>)
    (write-ln tn <span class="string">"brianjcj"</span>)

    (read-until tn <span class="string">"assword:"</span>)
    (write-ln tn <span class="string">"abcdefg12"</span>)
    (read-until tn <span class="string">">"</span>)

    (format-tn tn <span class="string">"~A~%"</span> <span class="string">"pwd"</span>) <span class="comment-delimiter">;; </span><span class="comment">stupid demo :-)
</span>    (read-until tn <span class="string">">"</span>)

    (write-ln tn <span class="string">"cmd1"</span>)
    (read-until-2 tn (list <span class="string">"Done."</span> <span class="string">"Error"</span> <span class="string">"Pending."</span>)
                  <span class="builtin">:case-insensitive-mode</span> t)
    (read-until tn <span class="string">">"</span>)

    
    (write-ln tn <span class="string">"cmd2"</span>)
    (expect tn
            (cl-ppcre:create-scanner
             <span class="string">"OK\|NO"</span>
             <span class="builtin">:case-insensitive-mode</span> t))
    (read-until tn <span class="string">">"</span>)

    
    (write-ln tn <span class="string">"cmd3"</span>)
    (expect tn <span class="string">"Done\|Try later."</span>)
    (read-until tn <span class="string">">"</span>)

    (write-ln tn-vmap <span class="string">"unload testci"</span>)
    (<span class="keyword">case</span> (read-until-2-ind tn (list <span class="string">"Please confirm ("</span> <span class="string">"has not been loaded yet"</span>))
      ((0)
       (read-until tn *prompt*)
       (sleep *rest-time*)
       (write-ln tn <span class="string">"Y"</span>)
       (read-until tn *prompt*))
      ((1)
       (read-until tn-vmap *prompt*)))
    
    (write-ln tn <span class="string">"exit"</span>)
    
    (<span class="keyword">loop</span> until (eof tn) do
         (read-available-data tn t))

    ))

(<span class="keyword">defun</span> <span class="function-name">example-2</span> ()

  (with-telnet-session (tn <span class="string">"202.38.33.94"</span>)

    (set-telnet-session-option tn <span class="builtin">:char-callback</span> nil)

    
    (princ (read-until tn <span class="string">"ogin:"</span>))
    (write-ln tn <span class="string">"brianjcj"</span>)

    (princ (read-until tn <span class="string">"PassWord:"</span>
                       <span class="builtin">:case-insensitive-mode</span> t))
    (write-ln tn <span class="string">"zaq12WSX"</span>)
    (princ (read-until tn <span class="string">">"</span>))

    
    (write-ln tn <span class="string">"ls"</span>)
    (princ (read-until tn <span class="string">">"</span>))

    (write-ln tn <span class="string">"cmd1"</span>)
    (princ (expect tn <span class="string">"Done\|Error"</span>))
    (princ (read-until tn <span class="string">">"</span>))

    (write-ln tn <span class="string">"cmd2"</span>)
    (princ (read-until-2
            tn
            (list <span class="string">"OK."</span> <span class="string">"Try again"</span> <span class="string">"Later."</span>)
            <span class="builtin">:timeout</span> 10))
    (princ (read-until tn <span class="string">">"</span>))


    (write-ln tn <span class="string">"cmd3"</span>)
    (princ (read-until-2
            tn (list <span class="string">"Right"</span> <span class="string">"Wrong"</span>)
            <span class="builtin">:timeout</span> 10 <span class="builtin">:case-insensitive-mode</span> t))
    (princ (read-until tn <span class="string">">"</span>))

    (write-ln tn <span class="string">"cmd4"</span>)
    (princ (expect
            tn
            (cl-ppcre:create-scanner
             <span class="string">"Right\|Wrong"</span>
             <span class="builtin">:case-insensitive-mode</span> t)))
    (princ (read-until tn <span class="string">">"</span>))
    
    (write-ln tn <span class="string">"exit"</span>)
    
    (<span class="keyword">loop</span> until (eof tn) do
         (princ (read-available-data tn t)))

    ))