LINUX GAZETTE
[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]

"Linux Gazette...making Linux just a little more fun!"


A Linux Client for the Brother Internet Print Protocol

By Graham Jenkins


The Brother Internet Print Protocol

A recent article Internet Printing--Another Way described a printing protocol which can be used with some Brother printers. It enables users of Windows machines to send a multi-part base-64 encoded print file via email directly to a Brother print server.

The article went on to show how the functionality of the Brother print server can be implemented in simple Perl program which periodically polls a POP3 server to check for jobs whose parts have all arrived. When such a job is detected, its parts are downloaded in sequence and decoded for printing.

A Linux Client

The Perl program mentioned above has been in use at my place for a few months, and has made it a lot easier for me to print Word and other Microsoft-format documents to a remote printer. But it hasn't made life any easier for those at my place who use Linux workstations.

A brief search on the Brother website failed to reveal a Linux client, so it was decided that I should develop one. The result is described hereunder.

Implementation

Conventional wisdom probably dictates that a program which breaks a binary input stream into chunks for feeding into a decoder in sequence - should be implemented in Perl, or perhaps in C. In fact, the common Bourne shell and its derivatives have all the necessary capabilities when used with a couple of general Unix/Linux tools like 'split' and 'wc'.

Program Walk-Through

As shown in the listing (text version), the program starts by checking that it has been called with two arguments; a usage message is printed if this is not the case. It then defines a function which will be called later to print a header on each part as it is sent. In particular, this function will include an address for notification, a part number, a part count, and a job identifier.

The program body begins by generating an email address for the originator, together with a timestamp. These are concatenated and used to generate a name for a scratch directory. A trap is set to remove any directory having that name in the event of error, and an attempt is made to create the scratch directory.

The Unix/Linux 'split' utility is then used to split the program input into parts whose size is given by the first program argument. Each of these is fed into a base-64 encoder and mailer (with appropriate pre-amble) to the address given by the second program argument.

The program ends by removing the scratch directory and returning an exit status.

#!/bin/sh
# BIPclient.sh  Brother Internet Print client program. Breaks incoming stream
#               into parts of designated size, then does base-64 encoding of
#               each part and emails it with appropriate preamble etc. to
#               designated email address.  Graham Jenkins, IBM GSA, June 2001.

[ $# -ne 2 ] && echo "Usage: `basename $0` kb-per-part destination">&2 &&
  echo " e.g.: man a2ps | a2ps -o - | `basename $0` 16 [email protected]">&2&& exit 2

do_header () {                                  # Function to print header
cat <<EOF
START-BROBROBRO-START
BRO-SERVICE=ZYXWVUTSRQ980
BRO-NOTIFY=Always
BRO-REPLY=$Me
BRO-PARTIAL=$Part/$Total
BRO-UID=$Me$Now
STOP-BROBROBRO-STOP

Content-Type: application/octet-stream; name="PrintJob.PRN"
Content-Transfer-Encoding: base64

EOF
}

Me=`whoami`@`hostname`
[ -n "`domainname`" ] && [ "`domainname`" != "(none)" ] && Me=$Me.`domainname`
Now=`date '+%Y%m%d%H%M%S'`                      # Generate email address,
Dir=/tmp/`basename $0`.$Me$Now                  # timestamp and directory name
trap 'rm -rf $Dir;echo Oops>&2;exit 1' 1 2 3 15 # Set cleanup trap

mkdir $Dir                      || exit 1       # Create directory
split -b ${1}k - $Dir/          || exit 1       # Generate parts
Total=`ls $Dir|wc -w |tr -d ' '`|| exit 1       # Count parts

Part=0
for File in `ls $Dir/*` ; do                    # Encode and send parts
  Part=`expr 1 + $Part`
  [ -t 2 ] && echo "Sending part: $Part/"$Total"  to: $2 .. $Now" >&2
  ( do_header
    base64 $File                                # Use mmencode or base64
    echo ) | Mail -s "Brother Internet Print Job" $2 
done

rm -rf $Dir                                     # Cleanup and exit
exit 0

Limitations

In the interests of simplicity, the 'do_header' function shown in the listing leaves out some of the header lines which are generated by the Windows client programs, and uses a dummy value for 'BRO-SERVICE'. In consequence, it may not work satisfactorily with a genuine Brother print server. If any readers have such a device, I would be interested in their feedback.

The 'unique' message identifier can actually be duplicated if a user submits two jobs within the same one-second period; this is a limitation of the Brother identifier format. An alternative identifier format which inserts a process number before the user's email address could be used if required.

And finally, the creation of a scratch directory to hold what is effectively a duplicate of the raw print file - may be seen as a problem if the client machine has a limited amount of temporary file-space. The issue here is that we really have to take a copy of the raw print file as it arrives so that we can generate a "total-parts" figure for inclusion in the header of each mailed component.

It is possible (using Perl or 'dd') to generate and mail parts on the fly, without using any temporary files - provided that the server program is modified slightly so as not to require a "total-parts" figure in the header of each part. I will be happy to send details to anyone who would like to do it this way.

Graham Jenkins

Graham is a Unix Specialist at IBM Global Services, Australia. He lives in Melbourne and has built and managed many flavors of proprietary and open systems on several hardware platforms.


Copyright © 2001, Graham Jenkins.
Copying license http://www.linuxgazette.net/copying.html
Published in Issue 68 of Linux Gazette, July 2001

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]