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);
}