9. Partager une imprimante Windows pour des clients Linux

Contenu de cette section

Pour partager une imprimante sur une machine Windows, vous devez suivre les points suivants~:

  1. Vous devez avoir les entrées correspondantes à l'imprimante dans /etc/printcap et elles doivent correspondre à la structure locale des répertoires (pour le repertoire de spool, etc...).
  2. Vous devez avoir le script /usr/bin/smbprint. Il est fournit avec les sources de Samba, mais pas avec toutes les distributions binaires. Une version légèrement modifiée de ce script est présentée plus loin.
  3. Si vous voulez convertir des fichiers ASCII en Postscript, vous devez avoir nenscript, ou équivalent. nenscript est un convertisseur Postscript et se trouve généralement dans /usr/bin.
  4. Vous voudrez peut-être simplifier l'impression à l'aide de Samba en utilisant une interface simple d'emploi. Un script simple, écrit en perl, pour gérer l'ASCII ou le PostScript est présenté ci-dessous.

L'entrée dans /etc/printcap est pour une imprimante HP 5 MP sur une machine utilisant Windows NT. Les entrées sont comme suit~:

cm - commentaire
lp - nom du peripherique a ouvrir en ecriture
sd - le repertoire de spool de l'imprimante (sur la machine locale)
af - le fichier d'accounting
mx - la taille maximum de fichier (zero pour aucune limite)
if - le nom du filtre en entree (un script)

Pour plus ample information, lisez le Printing HOWTO ou la page de manuel de printcap.

# /etc/printcap
#
# //zimmerman/oreilly avec smbprint
#
lp:\
       _:cm=HP 5MP Postscript OReilly sur zimmerman:\
       _:lp=/dev/lp1:\
       _:sd=/var/spool/lpd/lp:\
       _:af=/var/spool/lpd/lp/acct:\
       _:mx#0:\
       _:if=/usr/bin/smbprint:

Assurez que le répertoire de spool et celui d'accounting existent et son accessibles en écriture, que le chemin correct vers le script smbprint (donné ci-dessous) est indiqué par la ligne "~if~" et que vous avez séléctionné le bon device (le fichier spécial dans /dev).

Vient ensuite le script smbprint. Il est généralement mis dans le répertoire /usr/bin et a été créé par Andre Tridgell, le créateur de Samba pour autant que je sache. Il est fourni avec la distribution sous forme de code source de Samba, mais est absent de certaines distribution binaires. Je l'ai donc recopié ici.

Examinez le avec attention. Certains changement fait à ce script se sont avérées être utiles.

#!/bin/sh -x

# Ce script est un filtre d'entree sur l'impression avec printcap sur
# une machine Linux. Il utilise le programme smbclient pour imprimer
# le fichier au serveur et service specifie.
# Par exemple, vous pouvez avoir une entree printcap comme celle-ci_:
#
# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
#
# qui creerai une imprimante unix appelee "smb" qui imprimerait par
# l'intermediaire de ce script. Vous devrez creer le repertoire de
# spool, /usr/spool/smb avec les permissions qui conviennent et le bon
# proprietaire, pour votre systeme.

# Mettez les valeurs pour le serveur et le service sur lequel vous
# voulez imprimer.
# Dans cet exemple, j'utilise un PC sous Windows pour Workgroups nomme
# "laplan" ayant une imprimante appelee "printer" sans mot de passe.

#
# Script modifie par hamiltom@ecnz.co.nz (Michael Hamilton)
# afin que le serveur, le service et le mot de passe puissent etre lus
# depuis un fichier /usr/var/spool/lpd/PRINTNAME/.config
#
# Pour que ceci puisse fonctionner, l'entree du /etc/printcap doit
# inclure un fichier d'accounting (af=...)_:
#
#   cdcolour:\
#       :cm=CD IBM Colorjet au 6eme etage:\
#       :sd=/var/spool/lpd/cdcolour:\
#       :af=/var/spool/lpd/cdcolour/acct:\
#       :if=/usr/local/etc/smbprint:\
#       :mx=0:\
#       :lp=/dev/null:
#
# Le fichier /usr/var/spool/lpd/PRINTNAME/.config devrait contenir_:
#   server=SERVEUR_PC
#   service=NOM_IMPRIMANTE
#   password="mot_de_passe"
#
# Pas exemple_:
#   server=MON_BO_PC
#   service=CJET_371
#   password=""

#
# Fichier de log pour debuggage, changez le a /dev/null si vous le
# voulez
#
logfile=/tmp/smb-print.log
# logfile=/dev/null


#
# Le dernier parametre du filtre est le nom du fichier d'accounting
#
spool_dir=/var/spool/lpd/lp
config_file=$spool_dir/.config

# Les variables suivantes devraient etre lues depuis le fichier de
# configuration_:
#   server
#   service
#   password
#   user
eval `cat $config_file`

#
# Des informations de debuggage, changez le >> en > si vous voulez
# economiser de la place.
#
echo "server $server, service $service" >> $logfile

(
# NOTE Vous voudrez peut etre ajouter la ligne "echo translate" si
# vous voulez une conversion automatiques des CR/LF lors de l'impression
        echo translate
        echo "print -"
        cat
) | /usr/bin/smbclient "\\\\$server\\$service" $password -U $user -N -P >> $logfile

La plupart des distributions Linux sont fournies avec nenscript pour convertir des documents ASCII en Postscript. Le script perl qui suit simplifie la vie en fournissant une interface simple à smbprint pour l'impression sous Linux.

Usage: print [-a|c|p] <fichier>
       -a imprime <fichier> comme un fichier ASCII
       -c imprime <fichier> formatte en code source
       -p imprime <fichier> en tant que fichier Postscript
       Si aucun parametre n'est donne, print tente de
       deviner le type de fichier et imprime en consequence.

smbprint a tendance à tronquer les longues lignes lors de l'impression de fichiers ASCII. Ce script coupe les longues lignes sur les espaces (plutôt qu'au milieu d'un mot), si possible.

Le formatage en code source est réalisé par nenscript.Il prend en entrée un fichier ASCII et le formatte sur deux colonnes avec une entête (date, nom du fichier, etc...). Il numérote également les lignes. En prenant ce script comme exemple, on peut faire d'autres types de formatage.

Les documents sont déjà correctement formatés, donc ils passent directement à travers le filtre.

#!/usr/bin/perl

# Script:   print
# Auteurs:  Brad Marshall, David Wood
#           Plugged In Communications
# Date:     960808
#
# Script pour imprimer sur oreilly qui est pour l'instant connectee sur
# zimmerman.
# But:      Prendre differentes sortes de fichier en argument et les
#  traiter pour les injecter dans le script d'impression de Samba.
#
# Types de fichier supportes pour l'instant_:
# 
# ASCII      - verifie que les lignes plus longues que $line_length
#              caracteres sont coupes sur un espace.
# Postscript - Aucune action.
# Code       - Formatte en Postscript (a l'aide de nenscript) pour un
#              affichage correct (orientation, fonte, etc...).
#

# Fixe la longueur maximale d'une ligne de texte ASCII
$line_length = 76;

# Le chemin d'acces vers le script d'impression de Samba
$print_prog = "/usr/bin/smbprint";

# Le chemin vers le programme nenscript (le convertisseur
# ASCII->Postscript)
$nenscript = "/usr/bin/nenscript";

unless ( -f $print_prog ) {
        die "Je ne peux pas trouver $print_prog!";
}
unless ( -f $nenscript ) {
        die "Je ne peux pas trouver $nenscript!";
}

&amp;ParseCmdLine(@ARGV);

# Debug
print "filetype is $filetype\n";

if ($filetype eq "ASCII") {
        &amp;wrap($line_length);
} elsif ($filetype eq "code") {
        &amp;codeformat;
} elsif ($filetype eq "ps") {
        &amp;createarray;
} else {
        print "Desole, ce n'est pas un type de fichier que je connais";
        exit 0;
}
# Envoie le tableau a smbprint
open(PRINTER, "|$print_prog")
         || die "Je ne peux pas ouvrir $print_prog: $!\n";

foreach $line (@newlines) {
        print PRINTER $line;
}
# Envoie un retour a la ligne supplementaire si jamais le fichier a sa
# derniere ligne incomplete
print PRINTER "\n";
close(PRINTER);
print "Acheve\n";
exit 0;

# --------------------------------------------------- #
#       Tout ce qui suit est un sous programme        #
# --------------------------------------------------- #

sub ParseCmdLine {
        # Traite la ligne de commande, determine le type de fichier

        # $arg et $file sont respectivement les arguments (s'ils
        # existent) et le nom de fichier
        if ($#_ < 0) {
                &amp;usage;
        }
        # Debug
#       foreach $element (@_) {
#               print "*$element* \n";
#       }

        $arg = shift(@_);
        if ($arg =~ /\-./) {
                $cmd = $arg;
        # Debug
#       print "\$cmd trouve.\n";

                $file = shift(@_);
        } else {
                $file = $arg;
        }
        
        # Definition du type de fichier
        unless ($cmd) {
                # Aucun argument

                if ($file =~ /\.ps$/) {
                        $filetype = "ps";
                } elsif ($file =~ /\.java$|\.c$|\.h$|\.pl$|\.sh$|\.csh$|\.m4$|\.inc$|\.html$|\.htm$/) {
                        $filetype = "code";
                } else {
                        $filetype = "ASCII";
                }

                # Traite $file selon le type de fichier et retourne
                # le type de fichier ($filetype)
        } else {
                # Nous utilisons ltype de fichier decrit dans $arg
                if ($cmd =~ /^-p$/) {
                        $filetype = "ps";
                } elsif ($cmd =~ /^-c$/) {
                        $filetype = "code";
                } elsif ($cmd =~ /^-a$/) {
                        $filetype = "ASCII"
                }
        }
}

sub usage {
        print "
Usage: print [-a|c|p] <fichier>
       -a imprime <fichier> comme un fichier ASCII
       -c imprime <fichier> formatte en code source
       -p imprime <fichier> en tant que fichier Postscript
       Si aucun parametre n'est donne, print tente de
       deviner le type de fichier et imprime en consequence.\n
";
        exit(0);
}

sub wrap {
        # Cree un table contenant les lignes du fichier, avec chaque
        # ligne ayant une longueur < au nombre de caracteres
        # specifies, et coupee uniquement sur un espace.

        # Recupere la longueur maximum d'une ligne
        $limit = pop(@_);

        # Debug
        #print "Entree dans la procedure wrap\n";
        #print "La longueur maximum d'une ligne est $limit\n";

        # Lit le fichier, le traite et le stocke dans le tableau
        open(FILE, "<$file") || die "Impossible d'ouvrir $file: $!\n";
        while(<FILE>) {
                $line = $_;
                
                # Debug
                #print "La ligne est_:\n$line\n";

                # Coupe la ligne si celle-ci depasse la limite
                while ( length($line) > $limit ) {
                        
                        # Debug
                        #print "Je coupe...";

                        # Prend les premiers $limit +1 caracteres.
                        $part = substr($line,0,$limit +1);

                        # Debug
                        #print "La ligne partielle est_:\n$part\n";

                        # Verifie si le dernier caractere est un
                        # espace
                        $last_char = substr($part,-1, 1);
                        if ( " " eq $last_char ) {
                            # Oui, on imprime le reste

                            # Debug
                            #print "Le dernier caractere etait un espace\n";

                            substr($line,0,$limit + 1) = "";
                            substr($part,-1,1) = "";
                            push(@newlines,"$part\n");
                        } else {
                            # Non, on cherche le dernier espace de la
                            # ligne et on imprime jusqu'a lui

                            # Debug
                            #print "Le dernier caractere n'etait pas un espace\n";

                            # Supprime le caractere apres $limit
                            substr($part,-1,1) = "";
                            # Inverse la ligne pour trouver plus
                            # facilement l'espace
                            $revpart = reverse($part);
                            $index = index($revpart," ");
                            if ( $index > 0 ) {
                              substr($line,0,$limit-$index) = "";
                              push(@newlines,substr($part,0,$limit-$index) 
                                  . "\n");
                            } else {
                               # Aucun espace dans la ligne
                               # Imprime jusqu'a $limit
                               substr($line,0,$limit) = "";
                               push(@newlines,substr($part,0,$limit) 
                                   . "\n");
                             }
                        }
                }
                push(@newlines,$line);
        }
        close(FILE);
}

sub codeformat {
        # Appelle la procedure wrap et filtre par nenscript
        &amp;wrap($line_length);
        
        # Envoie le resultat a nenscript pour creer un fichier
        # Postscript qui respecte un format decent d'impression pour
        # du code source (orientation paysage, font Courier,
        # numerotation des lignes).
        # Imprime d'abord dans un fichier temporaire.
        $tmpfile = "/tmp/nenscript$$";
        open(FILE, "|$nenscript -2G -i$file -N -p$tmpfile -r") || 
                die "Je ne peux pas ouvrir nenscript_: $!\n";
        foreach $line (@newlines) {
                print FILE $line;
        }
        close(FILE);
        
        # Relis le fichier temporaire dans un tableau pour pouvoir
        # etre passe au script smbprint de Samba.
        @newlines = ("");
        open(FILE, "<$tmpfile") || die "Je ne peux pas ouvrir $file_: $!\n";
        while(<FILE>) {
                push(@newlines,$_);
        }
        close(FILE);
        system("rm $tmpfile");
}

sub createarray {
        # Cree le tableau pour un fichier postscript
        open(FILE, "<$file") || die "Can't open $file: $!\n";
        while(<FILE>) {
                push(@newlines,$_);
        }
        close(FILE);
}


Chapitre suivant, Chapitre Précédent

Table des matières de ce chapitre, Table des matières générale

Début du document, Début de ce chapitre