[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

[MacPerl] LPD-submit.pl



Hello,

I submitted a Perl script that behaves as an LPD client, some time ago.
This is a new version, implementing a number of suggestions from you, folks.
I am submitting this now, because I will soon leave this situation (of sitting
at a Mac with TCP/IP and with access to an LPD server).
Things I have not done yet, and that I dream of:
- multiple input files, and drag-and-drop for the Mac;
- PostScript sensing, and automatic choice between a PostScript queue and a
'plain' queue.
Remember that my host-address and queue-nqme of MY LPD-server are hardcoded in
this script.


Regards,
Peter Van Avermaet

# LPD-submit.pl
# This Perl script is a small client of the LPD protocol.
# It is intended to demonstrate the protocol,
#  not to be a product-quality LPD client.
# It can run on Mac and on Unix.
# For the LPD protocol itself:
#  refer to RFC1179
# Textbook: UNIX Network Programming, W. Richard Stevens, 
#  Prentice Hall, ISBN 0-13-949876-1
# (Chapter 13 in the 1990 edition)
# Interesting hints from GUSI.ph in the MacPerl distribution.
#
# Written by Peter Van Avermaet
# Version 16 January 1996
# Changes:
#  Finds own hostname
#  Finds username
#  Smarter about job-name (last 30 chars)
#  Re-shuffled some code

# get own hostname (or address)
# in case of Mac: this works if you have a recent version of MacPerl
#  (4.1.8 or better)
$thishost = `hostname` || die "get hostname: $!";
chop($thishost);
print "hostname is ",$thishost,"\n";

if ($thishost =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/){
  $cltadr = pack('C4',$1,$2,$3,$4);
} else {
  local(@x) = gethostbyname($thishost);
  $cltadr = $x[4];
};

# get own username
# in case of Mac: must have XFCN ChooserName in resource-fork
if($MacPerl'Version){
  $file = $0;
  &MacPerl'DebugExternals(2);
  &MacPerl'LoadExternals($file);
  $user = &ChooserName;
}else{
  $user = $ENV{'USER'};
};
print "user is ",$user,"\n";

# get hostname (or address) of LPD server
# in case of Mac: hard-coded
# in case of Unix: 1st argument
if($MacPerl'Version){
  $svr = '162.1.3.204';# uchsd01
}else{
  $svr = @ARGV[0];
  shift;
};
print "LPD server host is ", $svr, "\n";

if ($svr =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/){
  $svradr = pack('C4',$1,$2,$3,$4);
} else {
  local(@x) = gethostbyname($svr);
  $svradr = $x[4];
};

# get name of print queue (as defined on LPD server)
# in case of Mac: hard-coded
# in case of Unix: 2nd argument
if($MacPerl'Version){
  $queue = 'lp0';
}else{
  $queue = @ARGV[0];
  shift;
};
print "queue is ", $queue, "\n";

# get name of file
# in case of Mac: file-select dialog (we could add drag-and-drop)
# in case of Unix: 3rd argument
if($MacPerl'Version){
  $templ = pack("s",1) . "TEXT";
  $file = choose (4, 0, "", $templ);
}else{
  $file = @ARGV[0];
  shift;
};
print "file is ", $file, "\n";

$size = -s $file;
print "size is ", $size, "\n";

# some arithmetic with starting date & time
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);

# build a sequence-number - this algorithm is a hack -
#  we ought to have a sequence-number that is unique among all
#  pending requests from this client
$seqno = $min * 60;
$seqno = $seqno + $sec +100; # must have at least 3 digits
$seqno = $seqno - int($seqno/1000) * 1000;
print "sequence number is ",$seqno,"\n";

socket (SOC, 2, 1, 6) || die "socket: $!";

# bind a socket on the client side
# we assume that this is not possible on a Unix machine
# (you need privilege)
# if you do not bind a socket on the client side,
#  some servers may refuse you
# (they expect a connect from a privileged socket)
if($MacPerl'Version){
  $here = pack('S n a4 x8',2,515,$cltadr);
  bind (SOC,$here) || die "bind: $!";
};

$dest = pack('S n a4 x8',2,515,$svradr);

connect (SOC, $dest) || die "connect: $!";

$cmd = "\002" . $queue . "\012";
send(SOC,$cmd,0) || die "send request $!";
recv(SOC,$status,1,0);
if ($status ne "\000"){die "server refuses after: send request $!";};

$cmd = "\003" . $size . " dfA" . $seqno . "" . $thishost . "\012"; # RDF
send(SOC,$cmd,0) || die "send data header $!";
recv(SOC,$status,1,0);
if ($status ne "\000"){die "server refuses after: send data header $!";};

open(FH,$file) || die "open file $!";
$toread = $size;
while($toread > 0){
  $chunk = $toread;
  if ($chunk > 512) {$chunk = 512;};
  read(FH,$buf,$chunk) || die "read from file $!";
  send(SOC,$buf,0) || die "send data record $!";
  $toread = $toread - $chunk;
}  
close(FH);

send(SOC,"\000",0) || die "send end of data $!";

recv(SOC,$status,1,0);
if ($status ne "\000"){die "server refuses after: send end of data $!";};

# job-name: RFC says max 31 characters,
#  but HP LJ printers seem to truncate to 30
if (length($file) > 30){
  $jobname = substr($file,-30);
}else{
  $jobname = $file;
};

$cmd1 = "H" . $thishost . "\012"
 . "C" . $thishost . "\012"
 . "L" . $user . "\012"
 . "P" . $user . "\012"
 . "M" . $user . "\012"
 . "J" . $jobname . "\012"
 . "N" . $jobname . "\012"
 . "fdfA" . $seqno . "" . $thishost . "\012"
 . "UdfA" . $seqno . "" . $thishost . "\012";
$cmd = "\002" . length($cmd1) . " cfA" . $seqno . "" . $thishost . "\012";

send(SOC,$cmd,0) || die "send control header $!"; # RCF
recv(SOC,$status,1,0);
if ($status ne "\000"){die "server refuses after: send control header $!";};

$cmd1 = $cmd1 . "\000";
send(SOC, $cmd1,0) || die "send control $!";
recv(SOC,$status,1,0);
if ($status ne "\000"){die "server refuses after: send control $!";};

close SOC || die "close: $!";

print "finished\n";
exit;