Página seguinte Página anterior Índice

649. Compartilhando uma impressora do Windows com máquinas Linux

Para compartilhar uma impressora de uma máquina com Windows, deve-se observar os seguintes passos:

a) Deve-se ter as entradas adequadas em /etc/printcap e elas devem corresponder à estrutura de diretórios local (para o diretório de tarefas temporárias, etc.).

b) Deve-se ter à disposição o programa /usr/bin/smbprint. Ele é disponibilizado com os fontes do Samba, mas não necessariamente em todas as distribuições binárias. Uma cópia ligeiramente modificada é apresentada a seguir.

c) Caso se deseje converter arquivos ASCII em Postscript, deve-se ter à disposição o nenscript, ou o seu equivalente. O Nenscript é um conversor Postscrip, geralmente instalado em /usr/bin.

d) Pode ser desejável tornar a impressão via Samba mais simples disponibilizando uma interface composta por um simples programa perl (código-fonte mais abaixo) para lidar com arquivos ASCII, Postscript ou Postscript criados.

A entrada no arquivo /etc/printcap a seguir é destinada à uma impressora HP 5MP em uma máquina com Windows NT. As entradas podem ter o seguinte formato:


        cm - comentário
        lp - nome do dispositivo a ser acionado na saída 
        sd - nome do diretório de tarefas temporárias na máquina local
        af - arquivo de contabilidade 
        mx - tamanho máximo de arquivo (zero significa ilimitado) 
        if - nome do filtro de entrada (um programa) 

Para maiores informações veja o COMO FAZER Impressão ou as páginas de impressão do printcap.


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

Esteja seguro de que o diretório temporário e os diretórios de contabilidade existem e, é permitida a gravação nesses diretórios. Verifique se a linha 'if' contém a rota apropriada para o programa smbprint (fornecido a seguir) e esteja seguro que o dispositivo apropriado está apontado (para o arquivo especial /dev).

A seguir verificaremos o programa smbprint. Ele normalmente está localizado em /usr/bin e é de autoria de Andrew Tridgell, a pessoa que criou o Samba até onde eu sei. Ele vem com os fontes da distribuição Samba, mas está ausente em algumas distribuições binárias, razão pela qual eu o recriei aqui.

Pode-se desejar verificar o seu conteúdo atentamente. Há algumas pequenas alterações que mostraram-se muito úteis.


#!/bin/sh -x

# Este programa  é  um  filtro  de entrada na impressão printcap  em uma máquina 
# Unix. Ele é usado pelo programa smbclient para imprimir um arquivo no servidor 
# baseado em SMB.
# Pode-se, por exemplo, criar uma entrada no printcap com a seguinte linha:  
#
# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
#
# a qual pode criar uma impressora Unix chamada "smb" que irá imprimir através 
# deste programa. Deve-se criar o diretório de tarefas temporárias denominado   
# /usr/spool/smb com as permissões e proprietários apropriados ao sistema local. 

# Configure este para o servidor e o serviço no qual se deseje imprimir.
# Neste exemplo eu tenho um PC com Windows For Workgroups chamado "terrasanta" que 
# tem uma impressora exportada como "impressora" e não possui senhas.

#
# Este programa foi alterado por hamiltom@ecnz.co.nz (Michael Hamilton)
# permitindo que o servidor, o serviço e a senha possam ser lidas a partir
# do arquivo /usr/var/spool/lpd/PRINTNAME/.config.
#
# Para que este programa possa funcionar, a entrada no /etc/printcap deve incluir
# um arquivo de contabilidade (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:
#
# O arquivo /usr/var/spool/lpd/PRINTNAME/.config deve conter:
#   server=SERVIDOR
#   service=PR_NOME_COPARTILHAMENTO
#   password="senha"
#
# Exemplo:
#   server=SERVIDOR_2
#   service=CJET_371
#   password=""

#
# Para depurar o arquivo de mensagens deve-se alterar o parâmetro /dev/null para  
# o arquivo desejado
#
logfile=/tmp/smb-impressora.log
# logfile=/dev/null


#
# O último parâmetro para o filtro é o nome do arquivo de contabilidade. 
#
spool_dir=/var/spool/lpd/lp
config_file=$spool_dir/.config

# Devem ser lidas as seguintes variáveis no arquivo de configuração: 
#   servidor
#   serviço
#   senha
#   usuário
eval `cat $config_file`

#
# Dicas na depuração: mude >> para > se você quiser o mesmo espaço.
#
echo "server $server, service $service" >> $logfile

(
# NOTA: é possível anexar a linha `echo translate' caso se deseje 
# conversões automáticas de CR/LF durante a impressão
        echo translate
        echo "print -"
        cat
) | /usr/bin/smbclient "\\\\$server\\$service" $password -U $user -N -P >> $logfile

Muitas distribuições Linux contém o nenscript para a conversão de documentos ASCII para Postscript. O seguinte programa em Perl torna a vida mais simples ao prover uma interface simples a impressão Linux via smbprint.


Uso: print [-a|c|p] <nome_do_arquivo>
       -a imprime <nome_do_arquivo> como ASCII
       -c imprime <nome_do_arquivo> formatado como código fonte
       -p imprime <nome_do_arquivo> como Postscript
        caso nenhum parâmetro seja informado, o comando de impressão tenta 
        descobrir o tipo de arquivo e imprimi-lo corretamente. 

O uso do smbprint para a impressão de longas filas ASCII tende a truncar linhas longas. Este programa quebra estas linhas, se possível, nos espaços em branco (ao invés de fazê-lo no meio de uma palavra).

A formatação do fonte é feita com nenscript. Ele recebe uma arquivo ASCII e o formata em duas colunas com um cabeçalho interessante (data, nome do arquivo, etc.), além de numerar as linhas. Usando isso como um exemplo, outros tipos de formatação podem ser realizados.

Documentos Postscript são formatados de forma adequada, não sendo então tratados pelo programa.


#!/usr/bin/perl

# Programa:   print
# Autores:    Brad Marshall, David Wood
#                 Conectados em Comunicações
# Data:       08/08/96 
#
# Programa para impressão para Oreilly, que está com zimmerman
# Propósito:  Recebe  arquivos  de vários  tipos  como argumentos e
#             os  processa adequadamente, conectando-os ao programa
#             de impressão Samba. - Atualmente suporta os seguintes
#             tipos de arquivos: 
# 
# ASCII      - garante que linhas com um número de caracteres maior que o valor 
#              da variável $line_length sejam divididas quando é encontrado um
#              espaço em branco. 
# Postscript - Não executa nenhuma ação.
# Code       - Formata em Postscript (usando nenscript) para listá-los 
#              adequadamente (formato, fonte, etc.).
#
# Configuração do tamanho máximo de cada linha de texto ASCII  
$line_length = 76;

# Configura o caminho e o nome do programa de impressão Samba 
$print_prog = "/usr/bin/smbprint";

# Configura o caminho e o nome para nenscript (o conversor ASCII-->Postscript) 
$nenscript = "/usr/bin/nenscript";

unless ( -f $print_prog ) {
        die "Não foi possível encontrar $print_prog!";
}
unless ( -f $nenscript ) {
        die "Não foi possível encontrar $nenscript!";
}

&ParseCmdLine(@ARGV);

# DBG
print "arquivo é do tipo $filetype\n";

if ($filetype eq "ASCII") {
        &wrap($line_length);
} elsif ($filetype eq "code") {
        &codeformat;
} elsif ($filetype eq "ps") {
        &createarray;
} else {
        print "Desculpe..tipo de arquivo desconhecido.\n";
        exit 0;
}
# Conecta a tabela com smbprint 
open(PRINTER, "|$print_prog") || die "Não foi possível abrir $print_prog: $!\n";
foreach $line (@newlines) {
        print PRINTER $line;
}
# Envia uma nova linha extra no caso do arquivo ter uma última linha incompleta. 
print PRINTER "\n";
close(PRINTER);
print "Finalizado\n";
exit 0;

# --------------------------------------------------- #
#        O conteúdo abaixo é uma subrotina            #
# --------------------------------------------------- #

sub ParseCmdLine {
        # Recebe a linha de comando, descobrindo qual o tipo de arquivo 
      # Recebe $arq e $file como argumentos (se existirem)
        # e o nome do arquivo 
        if ($#_ < 0) {
                &usage;
        }
        # DBG
#       foreach $element (@_) {
#               print "*$element* \n";
#       }

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

                $file = shift(@_);
        } else {
                $file = $arg;
        }
        
        # Definindo o tipo de arquivo 
        unless ($cmd) {
                # Temos alguns argumentos 

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

                # Processa $file para o tipo de arquivo indicado e retorna $filetype 
        } else {
                # O parâmetro informado está em $arg
                if ($cmd =~ /^-p$/) {
                        $filetype = "ps";
                } elsif ($cmd =~ /^-c$/) {
                        $filetype = "code";
                } elsif ($cmd =~ /^-a$/) {
                        $filetype = "ASCII"
                }
        }
}

sub usage {
        print "
Uso: print [-a|c|p] <nome_do_arquivo>
       -a imprime <nome_do_arquivo> como ASCII
       -c imprime <nome_do_arquivo> formatado como código fonte
       -p imprime <nome_do_arquivo> como Postscript
        caso nenhum parâmetro seja informado, o comando de impressão tenta 
        descobrir o tipo de arquivo e imprimi-lo corretamente.\n
";
        exit(0);
}

sub wrap {
        # Cria um vetor com as linhas do arquivo, onde cada linha é menor
      # que o número de caracteres especificado, e quebrada somente onde
      # houver espaços em branco 

        # Obtém o limite do número de caracteres por linha.
        $limit = pop(@_);

        # DBG
        #print "Entrando na subrotina de quebra de linhas\n";
        #print "O tamanho máximo de caracteres por linha é igual a $limit\n";

        # Lê o arquivo e o coloca em um vetor 
        open(FILE, "<$file") || die "Não foi possível abrir $file: $!\n";
        while(<FILE>) {
                $line = $_;
                
                # DBG
                # print "Linha:\n$line\n";

                # Quebra a linha que estiver além do limite.
                while ( length($line) > $limit ) {
                        
                        # DBG
                        #print "Quebrando...";

                        # Obtém o limite + 1 caractere
                        $part = substr($line,0,$limit +1);

                        # DBG
                        #print "A linha parcial é:\n$part\n";

                        # verifica se o último caractere é um espaço.
                        $last_char = substr($part,-1, 1);
                        if ( " " eq $last_char ) {
                            # Em caso positivo imprime o restante.

                            # DBG
                            #print "O último caractere foi um espaço\n";

                            substr($line,0,$limit + 1) = "";
                            substr($part,-1,1) = "";
                            push(@newlines,"$part\n");
                        } else {
                             # caso contrário, encontra o último espaço na 
                             # sublinha e o imprime. 

                            # DBG
                            #print "O último caractere não era um espaço\n";

                             # Remove o caractere que ultrapassar o limite 
                             substr($part,-1,1) = "";
                             # inverte a linha para facilitar a busca pelo último 
                       # espaço
                           $revpart = reverse($part);
                             $index = index($revpart," ");
                             if ( $index > 0 ) {
                               substr($line,0,$limit-$index) = "";
                               push(@newlines,substr($part,0,$limit-$index) 
                                   . "\n");
                             } else {
                               # Não há espaço na linha, então 
                               # será impresssa até $limit.
                               substr($line,0,$limit) = "";
                               push(@newlines,substr($part,0,$limit) 
                                   . "\n");
                             }
                        }
                }
                push(@newlines,$line);
        }
        close(FILE);
}

sub codeformat {
        # Chama a subrotina wrap e executa um filtro através de nenscript 
        &wrap($line_length);
        
        # Conecta o resultado através de nenscript para criar um  arquivo 
      # Postscript que esteja de acordo com algum formato de impressão
      # código fonte (paisagem, fonte Courier, numeração de linhas)
      # Inicialmente imprime em um arquivo temporário
        $tmpfile = "/tmp/nenscript$$";
        open(FILE, "|$nenscript -2G -i$file -N -p$tmpfile -r") || 
                die "Não foi possível abrir nenscript: $!\n";
        foreach $line (@newlines) {
                print FILE $line;
        }
        close(FILE);
        
        # Lê o arquivo temporário de volta em um vetor viabilizando 
        # a sua passagem para um programa de impressão Samba
        @newlines = ("");
        open(FILE, "<$tmpfile") || die "Não foi possível abrir $file: $!\n";
        while(<FILE>) {
                push(@newlines,$_);
        }
        close(FILE);
        system("rm $tmpfile");
}

sub createarray {
        # Cria um vetor para o arquivo Postscript
        open(FILE, "<$file") || die "Não foi possível abrir $file: $!\n";
        while(<FILE>) {
                push(@newlines,$_);
        }
        close(FILE);
}


Página seguinte Página anterior Índice