Re: Help Sought with Samba pseudo printer for PDF...

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

 



On 05-Nov-2003/10:11 -0500, Timothy Stone <citylists@xxxxxxxxxxxxxx> wrote:
>List,
>
>I'm trying to find my way thru the maze of supporting software to get 
>something that appears to be "cookbook" by some standards to work:
>Anonymously Produce PDF documents via a PDF Pseudo Printer in Samba.


#!/usr/bin/perl
#
# print2pdf v1.2
#
# ------------
#   Purpose
# ------------
# This script allows Windows users to create PDF files by printing to a
# "network printer". This "network printer" is actually a Samba share that
# takes the printjob, converts it to PDF, then sends the PDF back to the
# user via email. To a Windows user, the process looks like this:
#
#  1. Print a document to a shared printer named PDF-Maker (or whatever
#  you name it).
#
#  2. Wait for a popup message saying that the conversion is done.
#
#  3. Check email for delivery of the PDF.
#
#
# ------------
#    Legal
# ------------
# Copyright (c) 2002, Anthony E. Greene <mailto:agreene@xxxxxxxxx>
# License: GNU GPL, v2 or later <http://www.fsf.org/licenses/gpl.txt>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to:
#
#    Free Software Foundation, Inc.
#    59 Temple Place - Suite 330
#    Boston, MA  02111-1307, USA.
#
# ------------
# Requirements
# ------------
# 1. The ps2pdf utility included with Ghostscript.
#
# 2. A Postscript printer driver that creates Postscript code that 
#    includes the document name in the "Title:" header. I recommend
#    the "HP Color LaserJet PS" driver that ships with Windows. This
#    driver must be installed on each client machine.
#
# 3. The mimencode utility included with metamail.
#
# 4. A sendmail-like program that accepts mail data from a pipe and
#    delivers it via SMTP.
#
# 5. The login name provided on the command line (by Samba) must be
#     resolvable to a valid email address or alias.
#
# ------------
# How It Works
# ------------
#
# The Windows user prints to this print share using a Postscript printer
# driver (HP Color LaserJet PS). Samba spools the Postscript into a temp
# file, then calls this script to process the file.
#
# The script parses the header of the Postscript document specified by
# Samba on the command line and extracts the contents of the Title field.
# The title is used to construct the filename of the resulting PDF
# document.  The Samba-provided username is used to generate the email
# address used to deliver the PDF.
#
# In my environment, the username is not a valid email alias. So I use it
# to query our LDAP server to get the user's SMTP email address and full
# name. An alternative would be to use the system alias file
# (/etc/aliases) to map usernames to email addresses.
#
# If your users all have local accounts or aliases on the Samba server or
# the usernames map to mailboxes in your domain, then you can disable the
# LDAP lookup by setting "$useldap = 0;" in this script. In this case you
# will also need to specify the domain name that should be appended to
# create the email address: "$maildomain = 'yourdomain';".
#
# If the username is not provided on the command line, or the LDAP query
# fails to match the username to an email address, then the PDF will be
# sent to the the sysadmin/default recipient (root).
#
# The machine name specified on the command line (see Samba Setup below)
# is the NETBIOS name of the machine that submitted the printjob to Samba.
# The script uses it to send a WinPopup/Messenger Service message to the
# user's machine when the job is complete. If this command line argument
# is set to 'localhost' then the script will not attempt to send a popup.
#
# -----------
# Samba Setup
# -----------
# For a complete explanation of the Samba setup for this, see John
# Bright's Linux Gazette article "PDF Service with Samba" at:
#
#      <http://www.linuxgazette.com/issue72/bright.html>
#
# Remember to add %m (the machine name) and %U (requested username) to
# the end of the command line of the print command setting in smb.conf:
#
#      print command = /usr/local/bin/print2pdf %s %m %U
#
# John Bright's article also includes instructions for making the printer
# driver available to Windows clients from the Samba server. The driver 
# must be installed on each client machine.
#
#
# ---------
# ChangeLog
# ---------
#
# v1.3 12-Dec-2002
# ----------------
# - Allow the sysadmin to specify a domain to be used along with the
#   username to construct the recipient email address when LDAP is not
#   used to resolve the address. Allows delivery to username@yourdomain.
#
# - If the machine name of the client is given as 'localhost' on the
#   command line, then the script will not attempt to send a popup. This
#   makes it easier to use the script separately from Samba.
#
# - Use 'To: username@domain' as the email address format instead of
#   'To: "Full Name" <username@domain>'. This script is intended for use
#   by Windows clients, who will most likely receive mail via Exchange
#   Server and Outlook clients. This software combination will always
#   display the user's Display Name on incoming messages, so specifying
#   a name in this script is unneccessary.
#
# - Rewrote the Purpose and How It Works sections.
#
# v1.2 20-May-2002
# ----------------
# - Allow sysadmin to specify whether or not LDAP should be used to
#   resolve username to email address. If LDAP is not used, PDF will be
#   mailed to username@localhost. This assumes that the user is either
#   local or has an alias entry in /etc/aliases.
#
# - Expanded some of the comments.
#
# v1.1 10-May-2002
# ----------------
# - Use the %U Samba variable to specify the user instead of parsing
#   the Postscript for a "For:" header. This allows different print
#   drivers to be used, as long as there is a Title header. Every
#   driver I've tested includes a Title header. The %U variable still
#   needs to be resolvable to a valid email alias/address.
#
# - Tell the default recipient that they are receiving the file because
#   it was not deliverable to the actual owner.
#


#############################
##  User-defined settings  ##
#############################

# Set this to any non-zero value to see diagnostics when running
# the script in a console.
$debug = 0;

# Specify if LDAP should be used to do username -> email address mapping.
# 1 == True;  0 == False
$useldap = 0;

# Use this domain to construct the recipient email address if LDAP is not
# used to find the address. You only need to set this if the username is
# part of a valid email address in your organization's domain, but users
# do not have an account on this machine (ie; username@yourdomain is a
# valid email address, but username@localhost is not).
# Default: localhost
$maildomain = 'localhost';

# Large documents will generate multi-megabyte Postscript files. You'll
# need a lot of space for temp file. My /home partition has the most
# available space, so that's where I'll put the temp files. The path in
# the Samba share that calls this script should match this path.
$tmpdir = '/tmp';

# Specify the Postscript-to-PDF conversion command.
$ps2pdf = '/usr/bin/ps2pdf';

# Specify the LDAP attribute that contains the login name.
$keyattr = 'rdn';

# This user gets notified about errors and receives PDF documents when
# the email address of the actual document owner cannot be determined.
$sysadminaddr = 'root';

# Specify the location of a sendmail-like MTA.
# Default:  '| /usr/sbin/sendmail -oi -U -t'
$sendmail = '| /usr/sbin/sendmail -oi -U -t';


#########################################################################
#########################################################################
##                                                                     ##
##       You should not have to change anything below this line        ##
##                                                                     ##
#########################################################################
#########################################################################

##############################
##  Program initialization  ##
##############################
# Get the Process ID for use in generating unique filenames.
$pid = $$;

# Get the start time for metrics.
$starttime = time;

# Get the name of this script for generating filenames.
$scriptname = `basename $0`;
chomp $scriptname;

# Get the name and size of the Postscript file for logging.
$psfile = @ARGV[0];
$pssize = (stat($psfile))[7];

# The name of the machine that sent the printjob. This is where the popup
# notification message will be sent. If this is 'localhost', then
# the script will not attempt to send a popup message.
$winbox = @ARGV[1];
if ($winbox eq 'localhost') {
  $usepopup = 0;
} else {
  $usepopup = 1;
}

# Get the username of the Samba user. This will be used for email and
# logging.
$sambauser = @ARGV[2];

# Find out who's running this script and on what machine. This is for
# debugging.
$sender = $ENV{'LOGNAME'};
$host = $ENV{'HOSTNAME'};



###################################
##  Parse the Postscript header  ##
###################################
# Get the document title from the header of the Postscript doc.
$doctitle = '';
open(PS,"$psfile");
while (($line = <PS>) && ($line !~ /^\%\%EndComments/)) {
  if ($line =~ /^\%\%Title: /) {
    # Remove the CR and LF, then get the doc title.
    $line =~ s/\r//;
    $line =~ s/\n//;
    $doctitle = substr($line,9);
  }
}
close(PS);

# If there was no Title field in the header,
# then we need to set a document title.
if ($doctitle eq '') {
  $timestamp = time;
  $doctitle = "$winbox_$timestamp";
}


#############################################
##  Figure out where to send the document  ##
#############################################
# If Samba provided a username, use it to find the email
# address via LDAP. If there's no username or if the LDAP 
# lookup fails, then send the doc to the sysadmin. 
$recipientaddr = '';
if ($sambauser eq '') {
  # Samba did not provide a username. Send doc to Sysadmin.
  $nosambauser = 1;
  $recipientaddr = $sysadminaddr;
} else {
  # Samba provided a username. See if we can use it or if it needs to be
  # looked up via LDAP.
  if ($useldap) {
    # Lookup the name and email address via LDAP. This search should
    # return the dn and mail attributes, one per line. The ldaphost,
    # searchbase, and other settings are in the system LDAP client config
    # file:  /etc/openldap.ldap.conf.
    $ldapfailed = 0;
    @rcpt_attributes = `ldapsearch -LLL -x "$keyattr=$sambauser" mail`;
    foreach $attr (@rcpt_attributes) {
      chomp $attr;
      # Keep track of the number of records returned by the query. Any
      # number other than 1 will indicate an unsuccessful search.
      if ($attr =~ /^dn: /) {
        $resultcount++;
      }
      # Parse out the email address.
      if ($attr =~ /^mail: /) {
        $recipientaddr = substr($attr,6);
      }
    }
    # If the LDAP search didn't find any records, or if it found more
    # than one record, then it failed and we need to set the
    # recipient address.
    if (($recipientaddr eq '') || ($resultcount != 1)) {
      # The LDAP lookup failed. Send the doc to the sysadmin.
      $ldapfailed = 1;
      $recipientaddr = $sysadminaddr;
    }
  } else {
    # The username does not need to be looked up via LDAP. The username
    # is a valid email alias.
    $recipientaddr = $sambauser . '@' . $maildomain;
  }
}


## See what it's going to do.
if ($debug) {
  print "PrintJob by: $sambauser at $winbox\n";
  print "   Document: $doctitle ($pssize bytes)\n";
  print "  Recipient: $recipientaddr\n";
}


##########################
##  Run the conversion  ##
##########################
# Specify the temp files for PDF and Base64 (MIME) versions of the doc.
$temppdf  = "$tmpdir/$scriptname.$pid.pdf";
$tempmime = "$tmpdir/$scriptname.$pid.mime";

# Convert Postscript to PDF and detect a non-zero (failed) return code.
$conversionfailed = system("$ps2pdf $psfile $temppdf");

# Encode PDF using Base64 for email.
$mimefailed = system("mimencode $temppdf -o $tempmime");

# Get the file sizes of the PDF and MIME files for
# metrics and diagnostics.
$pdfsize = (stat($temppdf))[7];
$mimesize = (stat($tempmime))[7];

# Calculate the elapsed time.
$stoptime = time;
$elapsed = $stoptime - $starttime;



####################################################
##  Deliver the document or send an error notice  ##
####################################################
# Check for failure of either the ps2pdf conversion or 
# the MIME encoding process.
if (($conversionfailed) || ($mimefailed)) {
  # Log the failure and notify the sysadmin.
  $logmsg  = "Failed.  PS2PDF: $conversionfailed,  MIME: $mimefailed  ";
  $logmsg .= "User: $sambauser at $winbox  ";
  $logmsg .= "Document: $doctitle ($pssize -> $pdfsize bytes)  ";
  $logmsg .= "Time: $elapsed  seconds";
  system("logger -i -t $scriptname '$logmsg'");

  # Send error message to user and Sysadmin via email.
  open(MAIL,"$sendmail");
  &stdheaders();
  print MAIL "Cc: $sysadminaddr\n";
  print MAIL "Subject: Error creating PDF: $doctitle.pdf\n\n";
  print MAIL "The document titled $doctitle \n";
  print MAIL "that you submitted for conversion to PDF ";
  print MAIL "was not converted.\n";
  print MAIL "The System Administrator has been notified.\n\n";
  print MAIL "Please try again later.\n";
  close(MAIL);

  # Send user a "conversion failed" popup message.
  if (($sambauser) && ($winbox) && ($usepopup)) {
    $popupmsg  = "From: PDF Convertor at $host\n";
    $popupmsg .= "    To: $sambauser on $winbox\n";
    $popupmsg .= " Subj: $doctitle\n\n";
    $popupmsg .= "*******************************\n";
    $popupmsg .= "**   PDF CONVERSION FAILED   **\n";
    $popupmsg .= "*******************************\n";
    system("echo '$popupmsg' | smbclient -M $winbox &");
  }
  &cleanup;
  exit 1;
} else {
  # The conversion succeeded. Log the success.
  $logmsg  = "Conversion succeeded.  ";
  $logmsg .= "User: $sambauser on $winbox  ";
  $logmsg .= "Document: $doctitle ($pssize -> $pdfsize bytes)  ";
  $logmsg .= "$elapsed sec";
  system("logger -i -t $scriptname \"$logmsg\"");

  # Send PDF doc to user.
  open(MAIL,"$sendmail");
  &stdheaders();
  print MAIL "MIME-Version: 1.0\n";
  print MAIL "Content-Type: multipart/mixed; ";
  print MAIL "boundary=\"$scriptname-$pid-mime-boundary\"\n";
  print MAIL "Subject: $doctitle.pdf\n\n";
  print MAIL "--$scriptname-$pid-mime-boundary\n";
  print MAIL "Content-Type: text/plain; charset=\"us-ascii\"\n\n";
  if ($recipientaddr eq $sysadminaddr) {
    print MAIL "This PDF conversion is being delivered to you because\n";
    print MAIL "the system was unable to determine the email address\n";
    print MAIL "of the actual owner of the document. See the headers\n";
    print MAIL "of this message for detailed diagnostics.\n";
  } else {
    print MAIL "This is the result of your PDF conversion print job. ";
    print MAIL "If you cannot open the attached PDF document, please ";
    print MAIL "notify the System Administrator.\n\n";
  }
  print MAIL "--$scriptname-$pid-mime-boundary\n";
  print MAIL "Content-Type: application/pdf\n";
  print MAIL "Content-Transfer-Encoding: base64\n";
  print MAIL "Content-Description: $doctitle\n";
  print MAIL "Content-Disposition: attachment; ";
  print MAIL "filename=\"$doctitle.pdf\"\n\n";
  open(MIME,"$tempmime");
  while ($line = <MIME>) {
    print MAIL "$line";
  }
  close(MIME);
  print MAIL "\n\n--$scriptname-$pid-mime-boundary--\n";
  close(MAIL);
  # Send the user a "conversion succeeded" popup message. 
  if (($sambauser) && ($winbox) && ($usepopup)) {
    $popupmsg  = "From: PDF Convertor on $host\n";
    $popupmsg .= "    To: $sambauser on $winbox\n";
    $popupmsg .= " Subj: $doctitle\n\n";
    $popupmsg .= "Your document was converted to PDF ";
    $popupmsg .= "and sent via email to\n";
    $popupmsg .= "$recipientaddr";
    system("echo '$popupmsg' | smbclient -M $winbox &");
  }
  &cleanup;
  exit 0;
}




#####################
##   Subroutines   ##
#####################

# Generate standard email headers.
sub stdheaders {
  print MAIL "From: \"PDF Convertor at $host\" <$sender>\n";
  print MAIL "To: $recipientaddr\n";
  print MAIL "X-Scriptname: $scriptname\n";
  print MAIL "X-SambaUser: $sambauser on $winbox\n";
  print MAIL "X-PS-File: $psfile ($pssize bytes)\n";
  print MAIL "X-PDF-File: $temppdf ($pdfsize bytes)\n";
  print MAIL "X-MIME-File: $tempmime ($mimesize bytes)\n";
  print MAIL "X-LDAP-Failed: $ldapfailed\n";
  print MAIL "X-Conversion-Failed: $conversionfailed\n";
  print MAIL "X-MIME-Failed: $mimefailed\n";
  print MAIL "X-Elapsed: $elapsed seconds\n";
}

# Delete temp files.
sub cleanup {
  unlink $psfile;
  unlink $temppdf;
  unlink $tempmime;
}




-- 
Anthony E. Greene <mailto:Anthony%20E.%20Greene%20%3Cagreene@xxxxxxxxx%3E>
OpenPGP Key: 0x6C94239D/7B3D BD7D 7D91 1B44 BA26  C484 A42A 60DD 6C94 239D
AOL/Yahoo Messenger: TonyG05    HomePage: <http://www.pobox.com/~agreene/>
Linux. The choice of a GNU generation <http://www.linux.org/>


-- 
redhat-list mailing list
unsubscribe mailto:redhat-list-request@xxxxxxxxxx?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/redhat-list

[Index of Archives]     [CentOS]     [Kernel Development]     [PAM]     [Fedora Users]     [Red Hat Development]     [Big List of Linux Books]     [Linux Admin]     [Gimp]     [Asterisk PBX]     [Yosemite News]     [Red Hat Crash Utility]


  Powered by Linux