Anterior Siguiente Indice

9. Compartiendo Una Impresora Windows Con Máquinas Linux

Para compartir una impresora en una máquina Windows, debes hacer lo siguiente:

a) Debes tener las entradas adecuadas en /etc/printcap y deben corresponderse a la estructura de directorios local (el directorio de spool, etc)

b) Debes tener el script /usr/bin/smbprint. Viene con las fuentes de Samba, pero no con la distribución de ejecutables del Samba. Más abajo comentamos una copia ligeramente modificada.

c) Si quieres convertir ficheros ASCII a PostScript, debes tener el 'nenscript' o su equivalente. nenscript es un conversor de PostScript y habitualmente está instalado en /usr/bin.

d) Puedes desear que las impresiones de Samba sean más sencillas teniendo un front end fácil de usar. Más abajo tienes un sencillo script en perl para manejar ASCII, PostScript o PostScript generado.

La entrada para /etc/printcap que tenemos debajo es para una impresora HP 5MP en un host Windows NT. Las entradas son las siguientes:



        cm - comentario
        lp - nombre del dispositivo a abrir para salida
        sd - el directorio de spool de la impresora (en la máquina local)
        af - el fichero de cuentas
        mx - el tamano maximo del fichero (cero es ilimitado)
        if - nombre del fichero de entrada (script)


Para más información, lee el COMO Imprimir (Printing HOWTO) o la página del man de printcap.



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


Asegúrate de que los directorios de spool y cuentas existe y se puede escribir en ellos. Asegura también que la línea 'if' tiene el path adecuado para el script smbprint (que damos debajo) y que apunta al dispositivo adecuado. (el fichero /dev especial).

Lo siguiente es el propio script smbprint. Normalmente está en /usr/bin y es atribuible a Andrew Tridgell, la persona que creó el Samba (que yo sepa). Viene con la distribución de las fuentes del Samba, pero está ausente de algunas distribuciones de ejecutables, por lo que lo he recreado aquí.

Te podría interesar mirarlo con cuidado. Hay algunas pequeñas alteraciones que han demostrado ser útiles.



#!/bin/sh -x

# Este script es un filtro de entrada para la impresion de printcap en
# una maquina unix. Usa el programa smbclient para imprimir un fichero
# en el servidor y servicio basados en smb especificados.
# Por ejemplo, puedes tener una entrada en printcap como esta
#
# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
#
# que creara una impresora unix llamada "smb" que imprimira a traves de
# este script. Necesitarras crear el directorio de spool /usr/spool/smb
# con los permisos y pertenencias apropiados para tu sistema.

# Ahora preparalos con el servidor y servicio en que quieras imprimir
# En este ejemplo tengo un PC WfWg llamado "lapland" que tiene una
# impresora exportada llamada "printer" sin password.

#
# Script alterado por hamilton@ecnz.co.nz (Michael Hamilton)
# para que servicio, servidor y clave puedan ser leidos desde un
# fichero /usr/var/spool/lpd/PRINTNAME/.config
#
# Para que esto funcione la entrada en /etc/printcap debe incluir un
# fichero de cuentas (af=...):
#
#   cdcolour:\
#       :cm=CD IBM Colorjet on 6th:\
#       :sd=/var/spool/lpd/cdcolour:\
#       :af=/var/spool/lpd/cdcolour/acct:\
#       :if=/usr/local/etc/smbprint:\
#       :mx=0:\
#       :lp=/dev/null:
#
# El fichero /usr/var/spool/lpd/PRINTNAME/.config deberia contener:
#   servidor=SERVIDOR_PC
#   servicio=NOMBRE_IMP
#   clave="clave"
#
# Ej.
#   servidor=PAULS_PC
#   servicio=CJET_371
#   clave=""

#
# Fichero de registro para correcciones, cambiar a /dev/null si se quiere
#
fichreg=/tmp/smb-print.log
# fichreg=/dev/null


#
# El ultimo parametro para el filtro es el nombre del fichero de
# cuentas
#
dir_spool=/var/spool/lpd/lp
fich_config=$dir_spool/.config

# Deberia leer las siguientes variables activadas en el fichero de
# configuracion:
#   servidor
#   servicio
#   clave
#   usuario
eval `cat $fich_config`

#
# Algo de ayuda en la correccion de errores. Cambia el >> por > si
# quieres salvar algo de espacio.
#
echo "servidor $servidor, servicio $servicio" >> $fichreg

(
# NOTA: Puede que quieras anadir la linea `echo translate' si quieres CR/LF
# automatico cuando imprimes.
        echo translate
        echo "print -"
        cat
) | /usr/bin/smbclient "\\\\$servidor\\$servicio" $clave -U $usuario -N -P >> $fichreg


La mayoría de las distribuciones de Linux vienen con el nenscript para convertir los documentos ASCII a Postscript. El siguiente script perl hace la vida más fácil dando un interfaz sencillo para que linux imprima a través de smbprint.



Forma de uso: print [-a|c|p] <nombre_fichero>
              -a imprime <nombre_fichero> como ASCII
              -c imprime <nombre_fichero> formateado como codigo fuente
              -p imprime <nombre_fichero> como Postscript
      Si no se pasa ningun parametro, print intenta
      averiguar el tipo de fichero e imprimirlo
      adecuadamente.


smbprint tiende a truncar las líneas demasiado largas cuando imprime ficheros ASCII. Este rompe las líneas largas donde haya un espacio en blanco (en lugar de en mitad de una palabra), si es posible.

El formateado de código fuente se hace con nenscript. Coge un fichero ASCII y lo formatea en 2 columnas con una cabecera mu' mona (fecha, nombre de fichero , etc). Además enumera las líneas. Usándolo como ejemplo, se pueden lograr otros tipos de formateado.

Los documentos Postscript también se imprimen correctamente, por lo que pasan directamente.



#!/usr/bin/perl

# Script:   print
# Autores:  Brad Marshall, David Wood
#           Plugged In Communications
# Fecha:    960808
# Cambios:  Ricardo Javier Cardenes Medina
# Razon:        Traduccion de comentarios y codigo a espanol para
#               mayor comprension.
# Fecha:    961109 (Sab 9 de Noviembre de 1996)
#
# Script para imprimir a Oreilly que esta actualmente en zimmerman.
# Proposito: Toma ficheros de varios tipos como parametros y
# los procesa apropiadamente para mandarlos al script de impresion de Samba.
#
# Tipos soportados actualmente:
# 
# ASCII      - Asegura que las lineas con mas de $largo_linea caracteres seran
#              divididas aprovechando los espacios en blanco.
# PostScript - No hace nada.
# Codigo     - Lo formatea en PostScript (usando nenscript) para una mejor
#              presentacion (fuente, etc...).
#

# Maxima longitud permitida para cada linea de texto ASCII.
$largo_linea = 76;

# Path y nombre del script 'print' de Samba.
$prog_print = "/usr/bin/smbprint";

# Path y nombre del nenscript (el convertidor ASCII-->PostScript)
$nenscript = "/usr/bin/nenscript";

unless ( -f $prog_print ) {
        die "íNo encuentro $prog_print!";
}
unless ( -f $nenscript ) {
        die "íNo encuentro $nenscript!";
}

&InterpLinCom(@ARGV);

# DBG
print "El tipo de fichero es $tipofich\n";

if ($tipofich eq "ASCII") {
        &Rompe($largo_linea);
} elsif ($tipofich eq "codigo") {
        &FormateaCodigo;
} elsif ($tipofich eq "postscript") {
        &CreaTabla;
} else {
        print "Lo siento..tipo de fichero desconocido.\n";
        exit 0;
}
# Enviar el array a smbprint
open(IMPRESORA, "|$prog_print") || die "íNo puedo abrir $prog_print: $!\n";
foreach $linea (@newlines) {
        print IMPRESORA $linea;
}
# Enviar un avance de linea extra en caso de que el fichero tenga una
# ultima linea incompleta.
print IMPRESORA "\n";
close(IMPRESORA);
print "Terminado\n";
exit 0;

# --------------------------------------------------- #
#         Todo lo de debajo es una subrutina          #
# --------------------------------------------------- #

sub InterpLinCom {
        # Interpreta la linea de comando, averiguando el tipo de fichero

        # Toma $par y $fich como parametro (si existe) y nombre del
        # fichero.
        if ($#_ < 0) {
                &FormaUso;
        }
        # DBG
        #       foreach $elemento (@_) {
        #               print "*$elemento* \n";
        #       }

        $par = shift(@_);
        if ($par =~ /\-./) {
                $com = $par;
        # DBG
        #       print "\Encontrado $com.\n";

                $fich = shift(@_);
        } else {
                $fich = $par;
        }
        
        # Defining the file type
        unless ($com) {
                # No tenemos parámetro

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

                # Procesa $fich buscando el tipo y devuelve $tipofich
        } else {
                # Tenemos el tipo en $par
                if ($com =~ /^-p$/) {
                        $tipofich = "postscript";
                } elsif ($com =~ /^-c$/) {
                        $tipofich = "codigo";
                } elsif ($com =~ /^-a$/) {
                        $tipofich = "ASCII"
                }
        }
}

sub FormaUso {
        print "
Forma de uso: print [-a|c|p] <nombre_fichero>
              -a imprime <nombre_fichero> como ASCII
              -c imprime <nombre_fichero> formateado como codigo fuente
              -p imprime <nombre_fichero> como Postscript
      Si no se pasa ningun parametro, print intenta
      averiguar el tipo de fichero e imprimirlo
      adecuadamente.\n
";
        exit(0);
}

sub Rompe {
        # Crea una tabla con las lineas del fichero, donde cada linea es
        # menor que el numero de caracteres especificado, y las rompe
        # solo en los espacios en blanco

        # Toma el numero de caracteres a los que limitar la linea.
        $limite = pop(@_);

        # DBG
        #print "Entrando en la subrutina Rompe\n";
        #print "El limite de caracteres es $limit\n";

        # Lee en el fichero, lo interpreta y pone en la tabla.
        open(FICHERO, "<$fich") || die "íNo puedo abrir $fich: $!\n";
        while(<FICHERO>) {
                $linea = $_;
                
                # DBG
                #print "La linea es:\n$linea\n";

                # Rompe la linea si se pasa del limite.
                while ( length($linea) > $limite ) {
                        
                        # DBG
                        #print "Rompiendo...";

                        # Toma los primeros $limite +1 caracteres.
                        $cacho = substr($linea,0,$limite +1);

                        # DBG
                        #print "La linea parcial es:\n$cacho\n";

                        # Mira a ver si el ultimo caracter es un espacio.
                        $ultimo_car = substr($cacho,-1, 1);
                        if ( " " eq $ultimo_car ) {
                            # Si lo es, imprime el resto.

                            # DBG
                            #print "El ultimo caracter era un espacio\n";

                            substr($linea,0,$limite + 1) = "";
                            substr($cacho,-1,1) = "";
                            push(@newlines,"$cacho\n");
                        } else {
                             # Si no lo es, busca el ultimo espacio en la
                             # sub-linea e imprime hasta alli.

                            # DBG
                            #print "El ultimo caracter no era un espacio\n";

                             # Borra el ultimo caracter que pasa de $limite
                             substr($cacho,-1,1) = "";
                             # Da la vuelta a la linea para hacer mas
                             # sencillo buscar el espacio.
                             $cachoreves = reverse($cacho);
                             $indice = index($revpart," ");
                             if ( $indice > 0 ) {
                               substr($linea,0,$limite-$indice) = "";
                               push(@newlines,substr($cacho,0,$limite-$indice) 
                                   . "\n");
                             } else {
                                 # No hay espacios en la linea, por lo que
                                 # se imprime hasta $limite.
                               substr($linea,0,$limite) = "";
                               push(@newlines,substr($cacho,0,$limite) 
                                   . "\n");
                             }
                        }
                }
                push(@newlines,$linea);
        }
        close(FICHERO);
}

sub FormateaCodigo {
        # Llama a la subrutina Rompe cuando filtra a traves de nenscript
        &Rompe($largo_linea);
        
        # Manda los resultados a traves de nenscript para crear un
        # fichero Postscript que de una forma decente a nuestro codigo
        # fuente para imprimirlo (fuente Courier, numero de lineas, ...).
        # E imprime todo esto a un fichero temporal.
        $fichtmp = "/tmp/nenscript$$";
        open(FICHERO, "|$nenscript -2G -i$fich -N -p$fichtmpfich -r") || 
                die "íNo pude abrir nenscript: $!\n";
        foreach $linea (@newlines) {
                print FICHERO $linea;
        }
        close(FICHERO);
        
        # Vuelca el fichero temporal en una tabla para que pueda
        # ser pasado al script de impresion de Samba.
        @newlines = ("");
        open(FICHERO, "<$fichtmp") || die "íNo puedo abrir $fichtmp: $!\n";
        while(<FICHERO>) {
                push(@newlines,$_);
        }
        close(FICHERO);
        system("rm $fichtmp");
}

sub CreaTabla {
        # Crear la tabla para postscript
        open(FICHERO, "<$fich") || die "íNo puedo abrir $fich: $!\n";
        while(<FICHERO>) {
                push(@newlines,$_);
        }
        close(FICHERO);
}



Anterior Siguiente Indice