#!@GUILE@ \ --debug -e main # aside from this initial boilerplate, this is actually -*- scheme -*- code !# ;;; client.scm -- Echo client example. ;; Copyright (C) 2014, 2015 Artyom V. Poptsov ;; ;; This program is free software: you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation, either version 3 of the ;; License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see ;; . ;;; Commentary: ;; Echo client example. ;; ;; Usage: client.scm [ options ] ;; ;; Options: ;; --user=, -u User name ;; --port=, -p Port number ;; --identity-file=, -i Path to private key ;; ;; Examples: ;; $ ./client.scm -i ~/.ssh/id_rsa -p 12345 127.0.0.1 "`date`" ;;; Code: (use-modules (ice-9 getopt-long) (ice-9 rdelim) (ssh channel) (ssh session) (ssh auth) (ssh key)) (define *program-name* "client.scm") (define *default-identity-file* (format #f "~a/.ssh/id_rsa" (getenv "HOME"))) (define *default-user* (getenv "USER")) (define *default-port* "22") ;; Command line options (define *option-spec* '((user (single-char #\u) (value #t)) (port (single-char #\p) (value #t)) (identity-file (single-char #\i) (value #t)) (help (single-char #\h) (value #f)))) (define (print-help-and-exit) "Print information about program usage." (display (string-append "\ " *program-name* " -- Echo client example. Copyright (C) Artyom V. Poptsov Licensed under GNU GPLv3+ Usage: " *program-name* " [ options ] Options: --user=, -u User name --port=, -p Port number --identity-file=, -i Path to private key ")) (exit 0)) (define (handle-error session) "Handle a SSH error." (display (get-error session)) (newline) (exit 1)) (define (get-prvkey session identity-file) "Get a private SSH key. Handle possible errors." (let ((prvkey (private-key-from-file identity-file))) (or prvkey (handle-error session)) prvkey)) (define (read-all port) "Read all lines from the PORT." (let r ((res (read-line port 'concat)) (str "")) (if (not (eof-object? str)) (r (string-append res str) (read-line port 'concat)) res))) (define (main args) "Entry point of the program." (let* ((options (getopt-long args *option-spec*)) (user (option-ref options 'user *default-user*)) (port (option-ref options 'port *default-port*)) (identity-file (option-ref options 'identity-file *default-identity-file*)) (help-needed? (option-ref options 'help #f)) (args (option-ref options '() #f))) (and (or (null? args) help-needed?) (print-help-and-exit)) (let* ((host (car args)) (str (cadr args)) (session (make-session #:user user #:host host #:port (string->number port) #:log-verbosity 'nolog))) ;Be quiet (connect! session) (case (authenticate-server session) ((not-known) (let* ((pubkey (get-server-public-key session)) (hash (get-public-key-hash pubkey 'md5))) (display "The server is unknown. Please check MD5 sum:\n") (format #t " ~a~%" (bytevector->hex-string hash))))) (let ((private-key (get-prvkey session identity-file))) (and (eqv? (userauth-public-key! session private-key) 'error) (handle-error session)) (let ((channel (make-channel session))) (or channel (handle-error session)) (channel-open-session channel) (write-line str channel) (let poll ((ready? #f)) (if ready? (format #t "Response from server: ~a~%" (read-all channel)) (poll (char-ready? channel)))) (close channel)))))) ;;; echo.scm ends here.