OpenScheme : Un (petit) client FTP
Par :
Guilhem de Wailly (gdw@erian-concept.com)

et :
Fernand Boéri (boeri@unice.fr)

Résumé
Notre connaissance du langage Scheme nous permet maintenant d'entrevoir toute la puissance de ce langage en concevant des applications plus complexes. Cela est rendu possible en exploitant les possibilités d'OpenScheme couvrant un large spectre de fonctionnalités.
Ce mois-ci, nous examinerons très sommairement le protocole FTP, puis nous programmerons en Scheme un (petit) client FTP ressemblant à la commande ftp de votre système favori. Ce client s'appuie sur la bibliothèque NET d'OpenScheme qui facilite grandement l'accès FTP depuis un programme Scheme.
L'environnement OpenScheme est disponible sur le CDROM de Linux Magazine. Il est aussi disponible sur www.open-scheme.com. Cet environnement existe en version libre ou commerciale.
Protocole FTP
Le protocole FTP (File Transfert Protocol) permet d'échanger des fichiers entre un serveur et un client. C'est un protocole relativement ancien mais toujours très utilisé car efficace et simple.
Dans un premier temps, nous proposons ce mois-ci d'examiner les principales commandes FTP en utilisant l'outil telnet. Puis nous programmerons un client FTP en Scheme. Pour cela, nous ferons appel à la bibliothèque NET d'OpenScheme.
Pour effectuer les exemples de cet article, il est nécessaire de disposer d'un serveur FTP. Votre système Linux dispose sûrement du serveur wu-ftpd, mais vous pouvez utiliser tout serveur FTP de l'Internet.
Le protocole FTP dépasse de beaucoup le simple transfert de fichier entre un serveur et un client. Il permet un accès interactif, de spécifier le format des données transférées et l'authentification lors de la connexion.
Le protocole FTP se distingue de la plupart des autres protocoles d'échange d'informations par le fait qu'au moins deux connexions sont utilisées, l'une pour la supervision du transfert et l'autre pour les données échangées. Plusieurs connexions peuvent être créées pour une seule connexion de supervision.
Nous allons explorer le protocole FTP en utilisant telnet. C'est presque le plus bas niveau d'interface possible qui montre bien les mécanismes mis en jeux. Le port standard pour la connexion FTP est le port 21. Nous pouvons ouvrir une session FTP avec telnet :
$ telnet localhost 21
220 machine.erian.com FTP server ready.
Nous supposons que votre machine possède un serveur FTP. Si ce n'est pas le cas, utilisez l'un de vos serveurs favoris. Le code 220 indique que la dernière opération s'est effectuée sans erreur. La connexion FTP est maintenant ouverte. Nous allons nous identifier :
USER gdw
331 Password required for gdw.
PASS motdepasse
230 User gdw logged in.
Certains serveurs FTP acceptent les connexions anonymes ; pour cela, le nom d'utilisateur est anonymous et le mot de passe est l'adresse email. Certains serveurs FTP anonymes requièrent une adresse email valides, d'autres acceptent des adresses email non valides ; cela se règle dans la configuration du serveur FTP. 
Nous sommes maintenant identifiés. Tapons par exemple :
SYST
215 UNIX Type: L8
PWD
257 "/home/gdw" is current directory.
CWD tmp
250 CWD command successful.
PWD
257 "/home/gdw/tmp" is current directory.
CDUP
250 CWD command successful.
Ces commandes demandent respectivement la nature du système hôte (SYST), le répertoire courant sur le serveur (PWD), la modification du répertoire courant (CWD) sur tmp, l'affichage du répertoire courant, et le déplacement sur le répertoire parent (CDUP).
Ces commandes sont assez simples car elles n'utilisent qu'un seul canal de communication. Nous allons maintenant mettre en oeuvre une communication sur deux canaux. Pour cela, nous allons tout d'abord passer en mode passif :
PASV
227 Entering Passive Mode (127,0,0,1,167,245)
Dans ce mode, le client ne va pas se comporter comme un serveur FTP pour récupérer les informations ; cela est plus simple à mettre en oeuvre et surtout, certaines configurations réseau refusent le mode actif.
Le résultat de la commande indique que, maintenant, nous sommes en mode passif ; les nombres entre parenthèses sont importants car ils indiquent quel serveur et quel port ouvrir pour récupérer le résultat de la prochaine commande. Là, un petit calcul est nécessaire : il faut ouvrir une autre session telnet sur l'adresse IP 127.0.0.1, avec le port 167*256+245. 
La commande shell suivante effectue ce calcul. Vous la taperez sur un autre terminal :
$ telnet 127.0.0.1 $(echo "167*256+245" | bc)
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Cette commande shell est exécutée depuis un autre terminal ; elle remplace le contenu de $(...) par le résultat de la commande à l'intérieur des parenthèses ; ici, on envoie au calculateur bc la demande de calcul entre guillemets. 
La nouvelle session telnet est ouvert. Maintenant, si on revient sur la session telnet initiale et que l'on tape :
LIST
150 Opening ASCII mode data connection
    for /bin/ls. Trying 127.0.0.1...
226 Transfer complete.
Nous obtenons alors sur l'autre terminal l'affichage suivant :
total 466
drwxr-xr-x 17 gdw  gdw   3072 Aug  9 14:47 .
drwxr-xr-x  6 root root  1024 Apr  4 15:37 ..
-rw-------  1 gdw  gdw    373 Aug  9 14:47 .Xauthority
-rwxr-xr-x  1 gdw  gdw    172 Nov 23  1999 .Xclients
-rw-r--r--  1 gdw  gdw   4114 Mar  1 15:14 .Xdefaults
-rw-r--r--  1 gdw  gdw   2455 Oct 24  1998 .Xmodmap
-rw-r--r--  1 gdw  gdw  14054 Oct 24  1998 .Xresources
drwx------  2 gdw  gdw   1024 Jun  2 12:40 .cedit
-rwx------  1 gdw  gdw    757 Oct 24  1998 .clean
drwx------  3 gdw  gdw   1024 Aug  4 12:05 .ddd
drwxr-xr-x 15 gdw  gdw   1024 Aug  4 18:53 .dt
-rwxr-xr-x  1 gdw  gdw   5111 Nov  4  1999 .dtprofile
drwxr-xr-x  2 gdw  gdw   1024 Aug  1 00:26 .hotjava
-rw-------  1 gdw  gdw     20 Oct 24  1998 .ispell_english
-rw-------  1 gdw  gdw   1959 Jun 22 21:43 .ispell_francais
-rw-------  1 gdw  gdw    341 Jul  3 09:57 .mailcap
-rw-rw-r--  1 gdw  gdw    561 Jun 19 22:25 .mtvrc
drwxr-xr-x  8 gdw  gdw   1024 Aug  9 14:58 .netscape
-rw-rw-r--  1 gdw  gdw    728 Feb 17 18:54 .pgaccessrc
-rw-r--r--  1 gdw  gdw    268 Nov 23  1999 .profile
-rw-r--r--  1 gdw  gdw   3336 Oct 24  1998 .screenrc
-rw-r--r--  1 gdw  gdw    102 Aug 24  1999 .signature
drwx------  2 gdw  gdw   1024 Aug  4 18:19 .solregis
-rw-r--r--  1 gdw  gdw   3932 Apr  2 21:02 .twmrc
drwx------  3 gdw  gdw   1024 Jan 15  2000 .xauth
drwxr-xr-x  5 gdw  gdw   1024 May  8 18:59 Desktop
drwxrwxr-x  3 gdw  gdw   1024 Jan 31  2000 MachinaSapiens
drwxr-xr-x  5 gdw  gdw   1024 Aug  4 14:55 axhome
drwxr--r--  4 gdw  gdw   1024 Jul 28 14:37 cv
drwxr-xr-x  8 gdw  gdw   1024 Feb 24 21:00 erian
drwxr-xr-x  2 gdw  gdw   2048 Aug  2 11:13 tmp
Connection closed by foreign host.
$ 
Après l'affichage du résultat, la connexion est automatique terminée. Ce mode de fonctionnement est aussi utilisé pour le transfert de fichiers en entrée et en sortie. Le lecteur pourra expérimenter ces transferts.
Terminons maintenant la session FTP :
QUIT
221-You have transferred 0 bytes in 0 files.
221-Total traffic for this session was 383 bytes in 0 transfers.
221-Thank you for using the FTP service on localhost.
221 Goodbye.
Connection closed by foreign host.
$ 
D'autres commandes FTP existent comme MKD (création de répertoire), RMD (suppression de répertoire vide), TYPE (positionnement du type de fichier en réception), RETR (récupération de fichier), DELE (suppression de fichiers), RNFR/RNTO (rennommage de fichier), STOR (envoi de fichier), etc.
L'utilisation de telnet pour faire du FTP n'est pas très aisée. Les clients FTP, comme la commande ftp, masquent ces difficultés pour offrir une interface utilisateur plus confortable. C'est justement aussi le rôle de la bibliothèque NET d'OpenScheme, avec les fonctions de la famille net:ftp exposées ci-dessous.
Bibliothèque NET:FTP
La bibliothèque NET d'OpenScheme définit un certain nombre de fonctions relatives au réseau. Parmi celles-ci, on trouve les fonctions FTP suivantes. Elles seront utilisées en partie pour réaliser un petit client FTP en Scheme.
·	(net:ftp? objet) : Retourne #t si objet est une connexion FTP et #f sinon.
·	(net:ftp:open hôte . port) : Ouvre une connexion FTP sur le serveur hôte. Par défaut, le port 21 est utilisé, mais cela peut être modifié en spécifiant l'argument port.
·	(net:ftp:ident ftp) : Retourne la chaîne de caractère d'identification du serveur FTP.
·	(net:ftp:result ftp) : Retourne l'erreur produite par la dernière commande, s'il elle existe, ou #f sinon.
·	(net:ftp:close ftp) : Ferme la connexion FTP donnée en argument.
·	(net:ftp:login ftp user password) : Ouvre une session utilisateur.
·	(net:ftp:logout ftp) : Termine la session utilisateur en cours.
·	(net:ftp:reset ftp) : Remise à zéro de l'état de la connexion. Toutes les actions en suspends sont avortées.
·	(net:ftp:pwd ftp) : Retourne la chaîne de caractères du chemin courant sur le serveur FTP.
·	(net:ftp:dir? ftp chemin) : Retourne #t si chemin est un répertoire sur le serveur FTP et #f sinon.
·	(net:ftp:chdir ftp chemin) : Change de répertoire de travail pour chemin sur le serveur FTP.
·	(net:ftp:mkdir ftp chemin) : Créer un répertoire chemin sur le serveur.
·	(net:ftp:rmdir ftp chemin) : Supprime le répertoire vide chemin du serveur.
·	(net:ftp:first ftp chemin) : Retourne le premier nom de fichier du répertoire chemin sur le serveur et positionne un pointeur sur le client. S'il n'y a pas de fichier, retourne #f.
·	(net:ftp:long ftp chemin) : Agit comme net:ftp:first, mais la chaîne de caractères retournée contient le nom du fichier est les informations affichée normalement par la commandes Unix ls -l.
·	(net:ftp:next ftp) : Retourne l'entrée suivante de celle initiée par net:ftp:first ou net:ftp:long ou #f.
·	(net:ftp:passive ftp) : Place le client en mode passif.
·	(net:ftp:active ftp) : Place le client en mode actif.
·	(net:ftp:get ftp chemin . output) : Ouvre le fichier chemin sur le serveur et affiche son contenu dans le port output, s'il est spécifié, ou le port de sortie standard, sinon.
·	(net:ftp:put ftp chemin . input) : Ouvre le fichier chemin sur le serveur et y écrit les information en provenance du port input, s'il est spécifié, ou du port d'entrée standard, sinon.
·	(net:ftp:size ftp chemin) : Retourne la taille du fichier chemin sur le serveur.
·	(net:ftp:date ftp chemin) : retourne la date de dernière modification du fichier chemin. Cette date est un réel manipulable avec les fonction date->string ou date->vector.
·	(net:ftp:delete ftp chemin) : Surprime le fichier chemin du serveur.
·	(net:ftp:rename ftp origine destination) : Renomme le fichier origine en destination sur le serveur.
Client en Scheme
Le programme commence par déclarer les bibliothèques qui seront nécessaires : la bibliothèque réseau contenant les fonctionnalités FTP et la bibliothèque pour manipuler les chaînes de caractères sont utilisées :
; déclaration des bibliothèques utilisées
(use 'net)
(use 'str)
Nous définissons ensuite une fonction permettant d'afficher l'invite du programme ; le numéro de la commande sera aussi affiché entre crochets :
; affichage de l'invite
(define prompt (let ([n 0])
                (lambda ()
                  (format #t "OsmFtp[~a]> " n)
                  (port-flush)
                  (set! n (+ n 1)))))
La fonction suivante lit une commande entrée à partir du prompt. On utilise la commande read-line qui lit une chaîne de caractère terminée par un saut à la ligne ou la fin de fichier. La fonction str:separate va séparer la chaîne en une liste de mots :
; lecture d'une commande de l'utilisateur
(define (get)
 (let ([v (read-line)])
   (str:separate
    (if (eof-object? v)
        "quit"
        v))))
La fonction suivante permet de vérifier que la connexion est établie avant de transmettre toute commande au serveur FTP :
; Vérification de la connexion
(define (check-ftp ftp)
 (if ftp
     #t
     (begin
       (format #t "Erreur: Connexion non ouverte\n")
       #f)))
La fonction suivante exécutera la commande open hôte. En cas de succès, une nouvelle connexion est retournée. La valeur #f est retournée en cas d'échec. Les fonctions Scheme réalisant les commandes FTP reçoivent en argument une liste de mots et elles retournent une connexion FTP. En général, la connexion FTP qu'elles retournent est identique à celle qu'elles ont reçue, à part pour les fonctions associées à la commande open (ci-dessous), à la commande quit et à la commande close. La commande open enchaîne automatiquement avec la commande user pour l'identification de l'utilisateur :
; ouvre une connexion FTP. Exécute aussi la commande user
(define (command.open ftp args)
 (if (pair? args)
      ; ouverture d'une connexion
     (let ([ftp (net:ftp:open (car args))])
       (if ftp
           (begin
              ; affichage de l'identification 
              ; du serveur FTP
             (format #t
                     "Connexion etablie:\n~a\n"
                     (net:ftp:ident ftp))
              ; identification de l'utilisateur
             (command.user ftp (cdr args)))
           (format #t
                   "Erreur: impossible d'ouvrir la connexion\n"))
       ftp)
       #f))
La fonction suivante permet à l'utilisateur de s'identifier auprès d'un serveur FTP :
; Identification de l'utilisateur
(define (command.user ftp args)
 (if (check-ftp ftp)
    ; lecture du nom du clavier ou des arguments
   (let ([name (if (null? args)
                    (begin
                     (display "Nom : ")
                    (port-flush)
                    (read-line))
                  (car args))])
     (if (and (string? name)
              (> (string-length name) 0))
        ; lecture du mot de passe
       (let ([pass (if (or (null? args)
                           (null? (cdr args)))
                     (begin
                       (display "Mot de passe : ")
                      (port-flush)
                       (read-line))
                     (cadr args))])
         (if (net:ftp:login ftp name
                            (if (string? pass)
                              pass
                              ""))
          (display "Login: ok\n")
          (display "Login: échec\n"))))))
  ftp)
La commande suivante affiche la liste des fichiers contenus dans le répertoire courant ou dans le répertoire donné en argument du serveur FTP. La fonction est une itération sur le résultat de net:ftp:first qui retourne un nom de fichier et positionne un pointeur dans la connexion FTP. La fonction net:ftp:next déplacera ce pointeur et retournera le nom suivant, ou #f s'il n'y a plus de noms de fichiers :
; affiche la liste des noms de fichiers du répertoire
; donnée en argument ou du répertoire courant de la
; connexion FTP
(define (command.ls ftp args)
 (if (check-ftp ftp)
   (let loop ([s (net:ftp:first ftp 
                                (if (null? args)
                                   "."
                                   (car args)))])
    (if s
        (begin
          (format #t "~a " s)
          (loop (net:ftp:next ftp)))
         (display #\newline))))
  ftp)
Cette fonction est identique à la précédente, mais elle affiche la liste des noms de fichiers avec des informations supplémentaires :
; affiche la liste longue des noms de fichiers du répertoire
; donnée en argument ou du répertoire courant de la
; connexion FTP
(define (command.ll ftp args)
 (if (check-ftp ftp)
   (let loop ([s (net:ftp:long ftp 
                               (if (null? args)
                                   "."
                                   (car args)))])
     (if s
         (begin
           (format #t "~a\n" s)
           (loop (net:ftp:next ftp)))
         (display #\newline))))
  ftp)
La fonction suivante permet de changer de répertoire courant sur le serveur FTP :
; changement du répertoire courant
(define (command.cd ftp args)
 (if (check-ftp ftp)
    (if (pair? args)
      (net:ftp:chdir ftp (car args))))
  ftp)
La fonction suivante permet de récupérer une liste de fichiers à partir du serveur FTP :
; récupération de fichiers à partir du serveur
(define (command.get ftp args)
 (if (check-ftp ftp)
   (for-each (lambda (file)
              (call-with-output-file
               file
               (lambda (port)
                (net:ftp:get ftp file port))))
             args))
  ftp)
Cette fonction permet d'envoyer une liste de fichiers locaux sur le serveur FTP, dans son répertoire courant :
; envoie de fichiers sur le serveur
(define (command.put ftp args)
 (if (check-ftp ftp)
     (for-each (lambda (file)
                 (call-with-input-file
                  file
                  (lambda (port)
                    (net:ftp:put ftp file portb))))
               args))
  ftp)
La commande suivante ferme une connexion FTP :
; fermeture de la connexion
(define (command.close ftp args)
 (if (check-ftp ftp)
     (begin
       (net:ftp:close ftp)
       (display "Connexion fermée\n")))
  #f)
Cette fonction permet de quitter le client FTP. Si la connexion n'est pas fermée, elle la termine aussi. Par convention, le client se termine lorsqu'une commande retourne le symbole 'quit :
; quitte le client en retournant le symbole 'quit
(define (command.quit ftp args)
 (if ftp (net:ftp:close ftp))
 (display "quit\n")
 'quit)
La fonction suivante est le programme principal qui démarre le client FTP. On commence par construire une liste de listes qui permettra d'associer nom de commande FTP, commande Scheme et aide en ligne dans la variable commandes. La seule commande qui ne soit pas associée à une fonction Scheme est help qui est associée au symbole help ; ceci sera traité dans l'analyse des commandes :
; programme principal
(define (ftp-client)
  ; petit message
  (display "Osm ftp client\n")
  
  ; commandes reconnues par le client
  ; Très facilement extensible
  (define commandes
   (list [list "open"
                command.open
                " [hôte]       : connexion à hôte"]
         [list "user"
                command.user
                " [nom [pass]] : identification"]
         [list "ls"
                command.ls
                " [chemin]     : listing court"]
         [list "ll"
                command.ll
                " [chemin]     : listing long"]
         [list "cd"
                command.cd
                " chemin       : changement de répertoire"]
         [list "get"
                command.get
                " fich fich ...: obtenir des fichiers"]
         [list "put"
                command.put
                " fich fich ...: envoyer des fichiers"]
         [list "close"
                command.close
                "              : fermer une connexion"]
         [list "quit"
                command.quit
                "              : quitter the client"]
         [list "help"
                'help
                "              : cette aide"]))
La fonction suivante fait partie du programme principal. Elle affiche l'aide en ligne du client FTP en affichant toutes les commandes disponibles ainsi que leur syntaxe :
  ; affiche l'aide du client
  (define (help ftp)
   (for-each (lambda (c)
               (format #t
                        "~a~a\n"
                        (car c)
                        (caddr c)))
             commandes)
    ftp)
Enfin, le programme principal entre dans une boucle alternant affichage de l'invite (prompt), lecture de la commande (get), recherche dans la table (assoc), et exécution. La recherche dans la table est faite en utilisant la fonction assoc qui recherche une association dans une liste. Si la recherche échoue ou retourne l'association concernant l'aide (symbole help), la fonction help est exécutée. Sinon, la fonction associée à la commande est invoquée avec la connexion ftp et la liste des arguments ; son résultat est utilisé pour définir la valeur du paramètre ftp de l'itération suivante :
  ; traitement des commandes de l'utilisateur
  (let loop ([ftp #f])
   (if (not (eq? ftp 'quit))
    (begin
     ; affichage de l'invite
     (prompt)

     ; lecture de la commande
     (let* ([cmd (get)]
            [op  (assoc (car cmd) commandes)])

      ; exécution de la commande et rebouclage
      (loop (if (or (not op)
                    (eq? (cadr op) 'help))
            (help ftp)
            ((cadr op) ftp (cdr cmd)))))))))

; démarrage du client FTP
(ftp-client)
Le client FTP est maintenant terminé. Il offre les principales fonctionnalités que l'on peut en attendre. Cependant, il est très facilement extensible : on pourra ajouter des fonctions issues directement de la bibliothèque NET:FTP. On pourra le doter d'une interface semi-graphique en utilisant la bibliothèque OC ou OOC (console) permettant notamment d'obtenir une ligne de commande avec édition et/ou historique ou graphique en utilisant OK ou OOK (graphique).
Exemple d'utilisation
Voici maintenant un exemple d'utilisation du client FTP en OpenScheme :
$ _osm_c --exec osmftp.osm
Osm ftp client

OsmFtp[0]> help
open hôte        : connexion à hôte
user [nom [pass]]: identification
ls [chemin]      : listing court
ll [chemin]      : listing long
cd chemin        : changement de répertoire
get fich fich ...: obtenir des fichiers
put fich fich ...: envoyer des fichiers
close            : fermer une connexion
quit             : quitter the client
help             : cette aide

OsmFtp[1]> open localhost
Connexion établie:
Nom: gdw
Mot de passe: motdepasse
Login: ok

OsmFtp[2]> ls
Desktop MachinaSapiens axhome cv erian tmp

OsmFtp[3]> ll
drwxr-xr-x 17 gdw  gdw   3072 Aug  9 14:47 .
drwxr-xr-x  6 root root  1024 Apr  4 15:37 ..
-rw-------  1 gdw  gdw    373 Aug  9 14:47 .Xauthority
-rwxr-xr-x  1 gdw  gdw    172 Nov 23  1999 .Xclients
-rw-r--r--  1 gdw  gdw   4114 Mar  1 15:14 .Xdefaults
-rw-r--r--  1 gdw  gdw   2455 Oct 24  1998 .Xmodmap
-rw-r--r--  1 gdw  gdw  14054 Oct 24  1998 .Xresources
drwx------  2 gdw  gdw   1024 Jun  2 12:40 .cedit
-rwx------  1 gdw  gdw    757 Oct 24  1998 .clean
drwx------  3 gdw  gdw   1024 Aug  4 12:05 .ddd
drwxr-xr-x 15 gdw  gdw   1024 Aug  4 18:53 .dt
-rwxr-xr-x  1 gdw  gdw   5111 Nov  4  1999 .dtprofile
drwxr-xr-x  2 gdw  gdw   1024 Aug  1 00:26 .hotjava
-rw-------  1 gdw  gdw     20 Oct 24  1998 .ispell_english
-rw-------  1 gdw  gdw   1959 Jun 22 21:43 .ispell_francais
-rw-------  1 gdw  gdw    341 Jul  3 09:57 .mailcap
-rw-rw-r--  1 gdw  gdw    561 Jun 19 22:25 .mtvrc
drwxr-xr-x  8 gdw  gdw   1024 Aug  9 14:58 .netscape
-rw-rw-r--  1 gdw  gdw    728 Feb 17 18:54 .pgaccessrc
-rw-r--r--  1 gdw  gdw    268 Nov 23  1999 .profile
-rw-r--r--  1 gdw  gdw   3336 Oct 24  1998 .screenrc
-rw-r--r--  1 gdw  gdw    102 Aug 24  1999 .signature
drwx------  2 gdw  gdw   1024 Aug  4 18:19 .solregis
-rw-r--r--  1 gdw  gdw   3932 Apr  2 21:02 .twmrc
drwx------  3 gdw  gdw   1024 Jan 15  2000 .xauth
drwxr-xr-x  5 gdw  gdw   1024 May  8 18:59 Desktop
drwxrwxr-x  3 gdw  gdw   1024 Jan 31  2000 MachinaSapiens
drwxr-xr-x  5 gdw  gdw   1024 Aug  4 14:55 axhome
drwxr--r--  4 gdw  gdw   1024 Jul 28 14:37 cv
drwxr-xr-x  8 gdw  gdw   1024 Feb 24 21:00 erian
drwxr-xr-x  2 gdw  gdw   2048 Aug  2 11:13 tmp

OsmFtp[4]> cd tmp

OsmFtp[5]> put fichier_local

OsmFtp[6]> get fichier_distant

OsmFtp[7]> close
Connexion terminée

OsmFtp[8]> quit

OpenScheme 1.3.4
La nouvelle version d'OpenScheme 1.3.4 est maintenant disponible sur le CDROM de LinuxMagazine et sur le site www.open-scheme.com. Parmi les nouvelles caractéristiques, nous trouvons :
·	Amélioration de la vitesse,
·	Correction de bug dans les threads sous Windows,
·	Client HTTP,
·	Son,
·	Port pour les logs,
·	Plugin pour Netscape & Internet Explorer sous Windows et Linux,
·	Police de sécurité,
·	IMG: PostScript en écriture, Windows Bitmaps BMP en lecture, fonctions de dessin,
·	Traditionnelles corrections de bugs.
OpenScheme est maintenant librement utilisable et distribuable dans sa version Free. Le numéro de licence n'est plus nécessaire sauf pour obtenir un support gratuit. La version commerciale peut toujours être commandée sur le site.
Les auteurs

Guilhem de Wailly, directeur de la société Erian Concept : support, formations, configurations, administration, développements Linux. Environnement OpenScheme.
http://www.erian-concept.com

Pr Fernand Boéri, Professeur à l'Université de Nice - Sophia-Antipolis, membre de l'unité SPORTS du laboratoire I3S, spécialiste en modélisation, évaluation de performances et architectures parallèles.
http://www.i3s.unice.fr
Références
FTP
¨	TCP/IP, Architecture, protocoles, applications
Douglas Comer
InterEdition
Scheme
¨	Structure et Interprétation des programmes informatiques
H. Abelson, GJ. Sussman
InterEdition
¨	The Scheme Programming Languages - Ansi Scheme 
R. Kent Dybvig
Prentice Hall
¨	Les langages Lisps - Christian Queinnec
InterEdition
¨	Programmer avec Scheme - J. Chazarin
Thomson Publishing
¨	Revised4 Report on the Algorithmic Language Scheme
W. Clinger, J. Rees
ftp://ftp.nj.nec.com/pub/kelsey
Environnements Scheme Free
¨	Bigloo - Manuel Serrano
http://kaolin.unice.fr
Environnement de programmation Scheme.
¨	DrScheme - Rice University
http://www.cs.rice.edu/CS/PLT/
Environnement Scheme libre très avancé.
¨	PCScheme - Texas Instrument
ftp://cui.unige.ch/public/pcs/pcscheme.exe
Un très bon environnement de programmation Scheme pour DOS, avec éditeur intégré.
¨	Scm - A. Jaffer
http://www-swiss.ai.mit.edu/~jaffer
La référence des interprètes Scheme. Très petit, rapide, pour beaucoup de plates-formes, extensible.
¨	Stk - Erik Gallesio
http://kaolin.unice.fr
Interprète Scheme avec la bibliothèque TK.
D'autres liens sont visibles sur le site www.schemers.org.
Environnements Scheme commerciaux
¨	ChezScheme - Cadence, Inc
http://www.scheme.com/
Environnement Scheme très performant.
¨	EdScheme, 3Dscheme - Scheme, Inc
http://www.schemers.com/
Environnement de programmation Scheme pour Windows.
¨	Inlab Scheme - Inlab Software GmbH
http://www.munich.net/inlab/scheme/
Environnement commercial
¨	OpenScheme - Erian Concept
http://www.open-scheme.com
Environnement professionnel de programmation Scheme comprenant un interprète, un compilateur et un débogueur symbolique. 
Existe en version libre et commerciale, pour Linux, FreeBSD, Solaris, Windows et BeOS, sur systèmes Intel.