#!/bin/sh
# hacked by JHS 2006.12.16 based on david/scanjet5-2005.11.04/sjrun.sh 
##  
##  Copyright (c) 2003, David S. Madole
##  All rights reserved.
##  
##  For latest sources and information on this software, please
##  go to http://www.madole.net/scanjet
##  
##  Questions, comments or suggestions should be directed to
##  David S. Madole <david@madole.net>.
## 
##  Redistribution and use in source and binary forms, with or without
##  modification, are permitted provided that the following conditions
##  are met:
##
##  1. Redistributions of source code must retain the above copyright
##     notice unmodified, this list of conditions, and the following
##     disclaimer.
##
##  2. Redistributions in binary form must reproduce the above copyright
##     notice, this list of conditions and the following disclaimer in the
##     documentation and/or other materials provided with the distribution.
## 
##  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
##  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
##  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
##  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
##  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
##  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
##  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
##  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
##  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
##  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
##  SUCH DAMAGE.
##  
##  End of copyright

##  ---------------------------------------------------------------------------

##
##  Revision History:
##
##  2005-10-30	An enhancement to paper jam detection:
##
##		o Allow the scanner to detect a paper jam during a scan job
##		  and resume from the jammed page after the jam is cleared.
##		  previously, the jam would end the current job and would
##		  detect and recover from the jam during the next job. This
##		  is a little tricky because there is no direct way to detect
##		  a jam; after a jam occurs, the next scan job crashes.
##
##  2005-10-15	Apparently greyscale TIFFs never worked right:
##
##		o Added a new option, "compress_gray" which specifies a
##		  compression method for grayscale TIFF files. Previously,
##		  there was only one setting for TIFF compression,
##		  "compress_tiff" and if you set it to a method that only
##		  supports black and white, like the default of "g4", then
##		  grayscale scans did not work. Now that setting only controls
##		  black and white TIFF scans.
##
##  2005-03-10	Some minor updates related to the document feeder:
##
##		o Centering of the image on the page was inconsistent between
##		  scans on the flat-bed and scans through the document feeder.
##		  This is because the document feeder centers the page, where
##		  the flatbed aligns it on the left. This release attempts to
##		  normalize the image location when the feeder is used. The
##		  problem would have been most noticable with paper smaller
##		  than US letter, but it affected letter a little bit, too.
##
##		o Previous releases auto-selected between the document feeder
##		  and the flatbed at the start of a scan job, but on multi-
##		  part scan jobs, all subsequent scans were taken from the
##		  same source. That restriction has been removed. It is now
##		  possible, for example, to create a single PDF file including
##		  pages from both the document feeder and flatbed.
##
##  2004-08-16  A few long-delayed minor enhancements:
##
##		o Added a new setting that changes the overall scan range
##		  lighter or darker by chaning the "Normal" setting and
##		  everything else relative to that.
##
##		o Added the ability to define an origin offset for each
##		  printer so that the position of the image on the copy can
##		  be adjusted to match the original, to compensate for margins.
##
##  2003-07-31	Major reworking, almost a rewrite. Major features added:
##
##		o Virtually all parameters are tunable and configurable through
##		  a separate configuration file. Many new settings, plus
##		  ability to set default settings for almost everything.
##
##		o All display text is customizable through separate language
##		  configuration files, making it easy to translate and 
##		  distribute translations separately from code updates.
##
##		o Post-scan document processing is now serialized so that many
##		  consecutive scans do not bury the CPU with background jobs.
##
##		o Multi-part document scanning is now supported. This allows
##		  multiple scan runs to be combined to form one document. This
##		  allows for scanning long documents a chunk at a time, as well
##		  as creating multi-page documents from flatbed scans. It also
##		  allows for recovery from document feeder jams.
##
##		o Multiple paper sizes are supported and can be selected from
##		  the front panel. Also, for emailed and saved scans, documents
##		  can be rotated to landscape and reverse orientations.
##
##		o Multiple printers are supported for copy mode and can be
##		  selected from the front panel.
##
##		o Multiple fax gateways can be supported. Support is included
##		  for the free fax service provided at http://www.tpc.int.
##
##		o Flexible rules can be defined for normalizing entered phone
##		  numbers as well as controlling what numbers can be entered.
##
##  2003-07-17  Rework SIGCHLD handling to work with "bash" shell. Add a few
##		other Linux support details. Add hidden command to display IP
##		address of scanner. Make panel LED stop flashing when stop
##		button is pressed during scan. (DSM)
##
##  2003-07-10  Fix PDF/TIFF mode selection in "Save" mode. Fix handling of
##		fax fine mode: always scan at 200 dpi, just set "{fine}" flag
##		when fine mode is requested. (DSM)
##
##  2003-03-01  Minor bug fixes. (DSM)
##
##  2003-02-27  Initial release. (DSM)
##

##  ---------------------------------------------------------------------------

##  This is used to display the version on the front panel and is updated
##  automatically when the distribution is built.

#version=2005.11.04
version=2006.12.16.jhs

##  ---------------------------------------------------------------------------

##  All of the following are default settings that can be overridden in
##  /etc/local/etc/sjrun.conf. It is preferable to change them there, rather
##  than here, so that local settings aren't lost when upgrading software.

##  Start of configuration items

##  ---------------------------------------------------------------------------

##  General notes on configuration:
##
##  Configuration items are shell script variables. Local configuration
##  settings can be placed in %ETCDIR%/sjrun.conf to override default
##  settings. The configuration file is sourced by the shell, so arbitrary
##  shell commands may be included as well to calculate configuration settings.
##
##  Because the configuration file is a shell script, characters that are
##  special to the shell need to be quoted. In general, it is recommended that
##  values be enclosed in double-quotes and quotes be otherwise avoided.
##
##  Many of the configuration settings accept lists of items. These lists are
##  formed by separating items with the "|" character. Where lists are used,
##  generally the order of list items determines the order of presentation in
##  menus on-screen. The first item is normally the default.
##
##  None of the values of these settings change the actual text visible to the
##  user -- they change functionality and options presented. To change the
##  text, see the language settings.
##
##  If you distribute a configuration file publicly that is produced by
##  editing the standard file, please retain the original copyright text,
##  which covers the comments and overall structure. You may, of course, add
##  your own terms and restrictions for the work you have added.
##
##  Descriptions and default values for all possible configuration settings
##  follow.

##  ---------------------------------------------------------------------------

##  The domain name of the machine, used to build email addresses in the
##  default configuration.

domain_name=`hostname | sed 's/[^.]*[.]//'`

##  The following determines where user information for email and save comes
##  from. There are four possible types of value, examples of which are:
##
##  "passwd|500|9999" -- gets users from the /etc/passwd system password file
##  whose user IDs are between 500 and 9999.
##
##  "group|scanjet" -- gets users who are a member of the group "scanjet". Any
##  number of group names separated by "|" may be specified.
##
##  "file|/usr/local/etc/sjrun.user" -- gets user information from the named
##  file. The file format is one line per user with three items per line
##  separated by "|". The three items are user name to display, email address,
##  and home directory path. 
##
##  "exec" -- this allows for custom command lines for some other backend.

user_source="passwd|500|9999"

##  When the preceeding is set to "exec", the following contain the command
##  lines to be run to look up users.
##
##  list_users --  When the list of all users is needed, this command is run
##  with "$1" containing a filter to match user names against. The command
##  should output one user name per line.
## 
##  fetch_user -- After a specific user is selected, this command will be run
##  with "$1" containing the specific user name. The command should output a
##  three-item list containing the user name, the email address, and the home
##  directory of the user, separated by "|".
##
##  This is a highly advanced feature. Good luck with it.

list_users=""
fetch_user=""

##  The following settings determine scan resolutions for different modes.
##  The resolution_1bit setting is used for lineart scans for the email and
##  save functions, where resolution_8bit is used for grayscale scans for
##  these. The resolution of copies is determined by resolution_copy, and the
##  resolution of faxes is determined by resolution_fax. This last one should
##  almost never be changed, unless you really know what you are doing.

resolution_1bit="300"
resolution_8bit="100"
resolution_fax="200"
resolution_copy="300"

##  SANE's brightness setting range is -127 to 127, but the extremes are much
##  too dark or much too light to be useful. The following sets reasonable
##  limits that the front panel setting is scaled to.

brightness_range="50"

##  This provides a way to permanently skew the brightness setting of scans.
##  This changes what the "Normal" setting is, and everything else relative to
##  that. Use a negative number for darker, positive for lighter.

brightness_offset="0"

##  The modes_ settings affect the choices of scan modes for each function,
##  as well as the default mode (as the default is the first item). You can
##  also add additional modes, but keep in mind that fax mode and copies to
##  PCL printers won't work with grayscale.

modes_copy="lineart|halftone"
modes_fax="lineart|halftone"
modes_email="lineart|grayscale"
modes_save="lineart|grayscale"

##  The following settings determine the type of compression appied to TIFF
##  documents. The compress_tiff setting affects the email and save functions
##  for black & white scans. Grayscale scans use compress_gray instead.
##  The compress_fax setting determines the compression type for TIFF files
##  sent through fax services. See "tiffcp -?" for possible choices.

compress_tiff="g4"
compress_gray="lzw"
compress_fax="g3"

##  If zipped or gzipped PDF or TIFF formats are permitted, this selects the
##  level of compression (1 is fastest compression and 9 is smallest output).

compress_gzip="6"
compress_zip="6"

##  The pdf_gs_level setting determines whether level 1 or level 2 Postscript
##  encoding is fed into Ghostscript to produce PDFs. Level 1 seems to give
##  better compression, resulting in smaller document sizes.

pdf_ps_level="1"

##  When generating PDFs, these options determine how the Postscript page
##  output should be rotated. The page width and height (in points) are pushed
##  on the stack before these Postscript fragments are executed. It's extremely
##  unlikely that anyone would ever want to change these.

pdf_rotate_none="pop pop"
pdf_rotate_left="90 rotate neg 0 exch translate pop"
pdf_rotate_right="-90 rotate neg 0 translate pop"
pdf_rotate_flip="180 rotate neg exch neg exch translate"

##  The following as a Postscript fragment that is executed to set arbitrary
##  page sizes when generating PDF files. The page width and height (in points)
##  are pushed on the stack before this fragment is executed. The only reason
##  you would change this is if you were using an odd version of Ghostscript.

pdf_set_page="//systemdict /statusdict get begin .setpagesize end"

##  The rotate_list setting determines what page orientations can be selected
##  from the front panel. The first item in the list will be the default.

rotate_list="none|left|right|flip"

##  The output_list setting determines what document formats are available for
##  the email and save functions. The first format listed will be the default.
##  Possible settings are pdf, tiff, pdf_gz, tiff_gz, pdf_zip, and tiff_zip.
##  The options ending with _gz and _zip are further compressed (besides any
##  compression inherent to the format) with gzip and zip, respectively.

output_list="pdf|tiff"

##  The detail_list setting determines what fax resolution modes are available.
##  Whatever mode is listed first will be the default.

detail_list="normal|fine"

##  The sender email address to be used when sending faxes out.

fax_sender="fax@$domain_name"

##  The email address of the HylaFAX email gateway, if one is used. The "<>"
##  token gets replaced with the post-processed fax number.

hylafax_email="<>.FAX@hylafaxserver.mycompany.com"

##  The sender email address to be used when emailing scans to users.

email_sender="scanner@$domain_name"

##  The service_list setting determines what fax services are available. The
##  option listed first will be the default. Current settings include "tpc"
##  for The Phone Company's free service (http://www.tpc.int), "maxemail"
##  for the pay service provided by MaxEmail (http://www.maxemail.com), and
##  "hylafax" for a HylaFAX email-to-fax gateway (http://www.ifax.com).

service_list="tpc"

##  The following options determine what paper sizes are offered for each
##  function. The size listed first will be the default. Make sure your
##  fax services and printers support any sizes listed for the first two.

sizes_copy="letter|legal"
sizes_fax="letter|legal"
sizes_save="letter|legal|a4|a5"
sizes_email="letter|legal|a4|a5"

##  The following settings affect the copy function. The maximum number of
##  copies of a document is determined by copy_limit.

copies_limit="100"

##  The following four sets of items are all lists used to adjust and validate
##  phone numbers used for faxes. Each item is a list of shell-style wildcards
##  (allowing '?', '*', and '[]') which are matched against the phone number.
##
##  The fax services tend to work with some sort of normalized phone numbers,
##  so these can be used to give the appearance of following local dialling
##  customs for the ease of users. There is now a separate set of settings for
##  each service, named for the service. Previously one set was used for all
##  fax numbers. The old parameters, named phone_xxx are officially deprecated
##  but will still be used for any services where the service-specific
##  parameters are not configured, for backwards compatibility.
##
##  The xxx_strip list is applied first. If any pattern in the list matches
##  the phone number, then the initial non-wildcard part of the pattern is
##  removed. Only the first matching pattern is used.

tpc_strip=""
phone_strip=""
hylafax_strip=""
maxemail_strip=""

##  Next the xxx_prefix list is applied. Each item in the list is split into
##  a prefix part consisting of any leading digits, and a wildcard pattern
##  part, which is whatever is left.  If the wildcard part of any item in this
##  list matches the phone number, then prefix part is prepended to the number,
##  with only the first matching entry used.

tpc_prefix=""
phone_prefix=""
hylafax_prefix=""
maxemail_prefix=""

##  After xxx_strip and xxx_prefix are used, the phone number is checked
##  for validity using xxx_allow and xxx_deny. These are both lists of
##  wildcard patterns that the number is checked against. If the phone number
##  matches a pattern in xxx_allow, the fax is permitted. If a phone number
##  does not match xxx_allow, but does match a pattern in xxx_deny, the
##  call is not allowed. Phone numbers that don't match either list are
##  always permitted.

tpc_allow="*"
phone_allow="*"
hylafax_allow="*"
maxemail_allow="*"

tpc_deny=""
phone_deny=""
hylafax_deny=""
maxemail_deny=""

##  List of printers for the copy function. This should be the names that
##  they are known to 'lpr' by, that is, what's in /etc/printcap.

printer_list="lp"

##  This allows a page origin offset to be defined for each printer so that
##  the margins can be adjusted to position the image on the page to match
##  the position of the image on the original. This works by manipulating the
##  scan area. The first number is how much the image should be moved to the
##  left, the second is how much the image should be moved up. These are both
##  positive numbers; it's not possible to move the image the other way, but
##  it's not likely you'd need to, either.

print_origin_lp="0|0"

##  SCSI device that the scanner is accessed through. If this is set to 
##  something valid, it will be used, otherwise a search is done for a 
##  reasonable device.

scan_device="default"

##  The following control how long before given panels timout and return to
##  the top menu as though if the stop key were pressed. All are in seconds,
##  with timeout_idle applying to any of the second-level function menus,
##  when the scanner is waiting to start a job. The second two are when
##  waiting during a job; timeout_flip is when two-sided originals need to be
##  turned over, and timeout_part is while waiting for additional pages when
##  multi_part scanning is enabled.

timeout_idle="30"
timeout_flip="300"
timeout_part="300"
timeout_jam="300"

##  The default number of sides for originals, that is, what the separate
##  "duplex" LED indicators are reset to at the topmost menu.

sides_default="1"

##  The default number of sides for copies. Setting this to "2" is only useful
##  if your printer is capable of printing duplex.

duplex_default="1"

##  Multiple sets of pages can be scanned and combined as one document if
##  multi_part is set to 'yes'. This will cause a prompt for additional pages
##  after each scan operation. Otherwise, after a scan is complete, the
##  document will be processed with just those pages. It is also possible to
##  set multi_part to either 'normal' or 'adf' and only jobs from that
##  paper source will be multi-part. Using 'normal' is most useful.

multi_part="no"

##  This is the subdirectory of the user's home directory to put documents
##  into in save mode.

save_directory="Scanner"

##  This is the filename to be used for mail attachments and saved files.
##  It can contain the date formatting codes described in 'man strftime'.

file_name="%y%m%d%H%M%S"

##  Following is a list of standard paper sizes. All sizes are in tenths of
##  millimeters, as a list with the width first, then the height. New sizes
##  can be added here as needed.

paper_size_a4="2099|2970"
paper_size_a5="1485|2099"
paper_size_a6="1047|1485"
paper_size_a7="740|1047"
paper_size_a8="522|740"
paper_size_a9="370|522"
paper_size_flsa="2159|3302"
paper_size_halfletter="1397|2159"
paper_size_note="1905|2540"
paper_size_legal="2159|3556"
paper_size_letter="2159|2794"

##  In PCL, pages can't be specified by size directly, but rather by code.
##  These are the codes for a few sizes. Additional sizes can be added if
##  you can find the codes for them.

pcl_paper_a4="26"
pcl_paper_a5="4"
pcl_paper_a6="24"
pcl_paper_flsa="8"
pcl_paper_legal="3"
pcl_paper_letter="2"

##  Following are definitions of the non-ACSII characters of the ISO 8859-1
##  (Latin 1) characters that the scanner is able to display. The names chosen
##  here are the HTML entity names for the characters, but these need to be
##  used as shell variables, for example "${ouml}" instead of "&ouml;". These
##  should not really be changed or added to, as it may break translations and
##  these are the only additional characters the scanner can display anyway.

AElig="\\306"   # AE ligature, decimal 198
aelig="\\346"   # ae ligature, decimal 230
Aring="\\305"   # A ring, decimal 197
Auml="\\304"    # A umlaut, decimal 196
acirc="\\342"   # a circumflex, decimal 226
agrave="\\340"  # a grave accent, decimal 224
aring="\\345"   # a ring, decimal 229
auml="\\344"    # a umlaut, decimal 228
Ccedil="\\307"  # C cedilla, decimal 199
ccedil="\\347"  # c cedilla, decimal 231
Eacute="\\311"  # E acute accent, decimal 201
eactute="\\351" # e acute accent, decimal 233
ecirc="\\352"   # e circumflex, decimal 234
egrave="\\350"  # e grave accent, decimal 232
euml="\\353"    # e umlaut, decimal 235
icirc="\\356"   # i circumflex, decimal 238
igrave="\\354"  # i grave accent, decimal 236
iuml="=\\239"   # i umlaut, decimal 239
ocirc="\\364"   # o circumflex, decimal 244
ograve="\\362"  # o grave accent, decimal 242
ouml="\\366"    # o umlaut, decimal 246
ucirc="\\373"   # u circumflex, decimal 251
ugrave="\\371"  # u grave accent, decimal 249
uuml="\\374"    # u umlaut, decimal 252
yuml="\\377"    # y umlaut, decimal 255

##  End of configuration items

##  ---------------------------------------------------------------------------

##  Following are language strings used on the display and for other external
##  communications. There can be overridden in %ETCDIR%/sjrun.lang, 
##  which is where translations to other languages should be done. If you just
##  want to modify a few settings from a "standard" translation, you should
##  probably put those in %ETCDIR%/sjrun.conf instead, so that upgrades
##  of the software and translation files won't overwrite your settings.

##  Start of translation items

##  ---------------------------------------------------------------------------

##  General information on translations:
##
##  Translation items are are shell script variables. Full translations of the
##  user interface may be make by placing new value assignments in the
##  %ETCDIR%/sjrun.lang file. The translation file is sourced by the
##  shell, so arbitrary shell commands may be included as well to calculate
##  configuration settings.
##
##  Because the translation file is a shell script, characters that are
##  special to the shell need to be quoted. In general, it is recommended that
##  values be enclosed in double-quotes and quotes be otherwise avoided.
##
##  Some of the translation settings accept lists of items. These lists are
##  formed by separating items with the "|" character. Where lists are used,
##  they contain two items for the two display lines for labelling the soft
##  keys under the display. Each item in the list should be ten characters
##  or less. If only one line is needed, use a null item for the first item.
##
##  Some other settings accept multiple line strings. Lines should be
##  separated by newline characters. Any leading tabs, but not spaces, are
##  removed from each line before the string is displayed, and each line is
##  centered on the display.
##
##  Many translation settings may contain a "<>" token, which gets substituted
##  with an appropriate value at the time the string is used. Where used, the
##  values are discussed below.
##
##  There are a number of accented characters that the scanner can display
##  that may be useful in some languages. These characters are translated by
##  the LCD driver from the ISO 8859-1 (Latin-1) character encoding, although
##  only a subset of Latin-1 can be displayed. To simplify use of these
##  characters, it is also possible to use symbolic names that have been
##  pre-defined as variables named after the appropriate HTML character
##  entities. See the configuration settings for the list of characters.
##
##  The translation file is loaded by the configuration file. This has two
##  useful consequences: Translation files can also be used for localization
##  by changing default settings for configuration items, like paper sizes.
##  Also, The configuration file may contain translation settings where it is
##  desired to locally override a few strings, but get the rest of the 
##  translation from an unaltered translation file.
##
##  If you distribute a translation file publicly that is produced by
##  editing the standard file, please retain the original copyright text,
##  which covers the comments and overall structure. You may, of course, add
##  your own terms and restrictions for the work you have added.
##
##  Descriptions and default values for all possible translation settings
##  follow.

##  ---------------------------------------------------------------------------

##  Following are labels for the softkeys underneath the display. These should
##  all be lists of too items, which are displayed first above the second
##  on the bottom two lines of the display. Each item should be ten characters
##  or less.

##  These are the names displayed above the softkey for page orientation.
##  Normal orientation as produced by the scanner is rotate_none; this turned
##  upside down is rotate_flip; normal orientation turned 90 degrees counter-
##  clockwise is left, 90 degrees clockwise is rotate_right.

rotate_none="Portrait|Normal"
rotate_flip="Portrait|Reverse"
rotate_left="Landscape|Normal"
rotate_right="Landscape|Reverse"

##  The following determine the number of sides of copies made with the
##  copy function. Double-sided only really works if your printer can print
##  duplex of course.

duplex_1sided="Single|-sided"
duplex_2sided="Double|-sided"

##  Labels for selection of lineart or grayscale/halftone scan mode.

modes_lineart="Black|& White"
modes_halftone="Grays|/ Color"
modes_grayscale="Grays|/ Color"

##  The label for the rightmost key, which selects pages of options.

more_options="More|Options"

##  The label for the key that changes scan brightness. Three separate strings
##  are chosen from, depending on whether the brightness is normal, darker
##  than normal, or lighter than normal. The "normal" string is displayed
##  as-is; in the others, a '<>' token is replaced with a digit from 0-9
##  indicating the degree lighter or darker than normal.

density_normal="Normal|Density"
density_lighter="<>0%|Lighter"
density_darker="<>0%|Darker"

##  Like the above, but these control scaling the size of scans. The '<>'
##  token here (except in "normal") is replaced with a number from 20-500.

resize_normal="Resize|<>%"
resize_smaller="Resize|<>%"
resize_larger="Resize|<>%"

##  Labels for the key used to select output document format.

output_pdf="PDF|Format"	
output_tiff="TIFF|Format"
output_pdf_gz="PDF/GZ|Format"
output_tiff_gz="TIFF/GZ|Format"
output_pdf_zip="PDF/ZIP|Format"
output_tiff_zip="TIFF/ZIP|Format"

detail_normal="Normal|Detail"
detail_fine="Fine|Detail"

##  Labels for the key used to select the fax service provider.

service_hylafax="HylaFAX|Gateway"
service_maxemail="MaxEmail|Service"
service_tpc="TPC|Service"


##  Following are the display names for different sizes of paper. If a new
##  size is added, a matching name should be added here as well.

paper_a4="A4|Paper"
paper_a5="A5|Paper"
paper_a6="A6|Paper"
paper_a7="A7|Paper"
paper_a8="A8|Paper"
paper_a9="A9|Paper"
paper_flsa="Folio|Paper"
paper_halfletter="Half-|Letter"
paper_note="Note|Paper"	
paper_legal="Legal|Paper"
paper_letter="Letter|Paper"

##  This is the displayed names for the printers configured by printer_list.

printer_lp="Default|Printer"

##  This determines the format for the date if it is displayed on the title.

date_format="%a %b %e %I:%M %p %Y"

##  These are the labels for the four functions as shown on the top-most menu.

title_keys="Copy|Email|Fax|Save"

##  The following are the settings prompts. There all have the actual setting
##  calue appended to them when displayed.

prompt_copies="Number of copies:"
prompt_from="Fax sender:"
prompt_fax="Fax number:"
prompt_email="Email to:"
prompt_save="Save to:"
prompt_resize="Percent of original:"
prompt_density="Percent of original:"

##  The following message is displayed when a phone number fails the checks
##  against the phone_allow and phone_deny settings.

phone_error="\
	The phone number entered is not
	valid or is not permitted."

##  The following message is displayed when a phone number is valid but is
##  not reachable through a given fax gateway. This is dynamic for TPC.

phone_unreach="\
	The phone number entered cannot
	be reached through this service."

##  The following messages are full-screen displays or prompts. Each line will
##  be centered on the display after leading whitespace is removed. Each line
##  should have 40 characters or less and lines should be separated by
##  newline characters.

##  The display for the title page. The '<>' token will be replaced by the
##  current date and/or time as formatted by date_format.

prompt_main="\

	Network ScanJet 5 Enhanced

	<>"

##  The prompt when double-sided originals need to be turned over.

prompt_flip="\

	Reload copies for second side.
	Load with first page down.

	Press start key to continue or
	stop key to cancel scan."

##  The message that is displayed while pages are being scanned. The '<>'
##  token will be replaced with the total number of scanned pages.

prompt_scan="\

	Scan in progress, please wait.
	
	Total pages scanned: <> 
	
	Press stop key to cancel scan."

##  The prompt for additional pages when multi_part mode is enabled.

prompt_part="\

	Load any additional pages for
	this document.

	Press start key to continue or
	stop key if no more pages."

##  The prompt for resuming the job when a paper jam occurs.

prompt_jam="\

	A paper jam has occurred. Clear
	and reload the feeder to continue.

	Press start key to continue or
	stop key if no more pages."

##  The message displayed with the scanner is halted from the front panel.

prompt_halt="\

	Halting scanner...

	Please wait at least one minute
	before powering scanner off."

##  The message displayed with the scanner is rebooted from the front panel.

prompt_boot="\

	Rebooting scanner...

	Scanner should be back online
	within two to three minutes."

##  The prompt used to display the IP address. The '<>' will be replaced
##  with the adanner's address.

prompt_addr="Address: <>"

##  The prompt used to display the software version. The '<>' will be
##  replaced with the adanner's address.

prompt_vers="Version: <>"

##  In the following two messages, the "<>" will be replaced with the filename
##  that is attached to the email. The email_body message may contain multiple
##  lines; each will have any leading whitespace removed.

email_subject="Scanned Document <>"

email_body="Attached is your scanned document <>."

##  Verification of fax numbers or loading the user list might take a second
##  of two, so the following is displayed.

please_wait="Please wait..."

##  End of translation items

##  ---------------------------------------------------------------------------

##  Pull in alternate language strings. The user interface can be translated
##  to other languages in this file. This is loaded before the configuration
##  settings so that default settings can be translated and users can override
##  specific translations locally that they don't like.

# if [ -r "%ETCDIR%/sjrun.lang" ]
# then . "%ETCDIR%/sjrun.lang"
# fi

# David's %ETCDIR% is not being set so force it.
LOCALETC=/usr/local/etc

if [ -r "$LOCALETC/sjrun.lang" ]
then . "$LOCALETC/sjrun.lang"
fi

##  Pull in local customizations for configuration settings.

# if [ -r "%ETCDIR%/sjrun.conf" ]
# then . "%ETCDIR%/sjrun.conf"
# fi

if [ -r "$LOCALETC/sjrun.conf" ]
then . "$LOCALETC/sjrun.conf"
fi

##  ---------------------------------------------------------------------------

##  We use a few things from /sbin like reboot, halt, and ifconfig, so add
##  /sbin to $PATH if it's not there already.

case ":$PATH:" in
  *:/sbin:*) ;;
  *) export PATH="$PATH:/sbin"
esac

# Add /usr/local/bin for xscanimage
#  ( /usr/local/bin is also inherited if called from
#	/usr/local/etc/rc.d/sjrun.sh start
#     but not if started in test mode as
#	sjlcd /dev/cuaa0 sjrun
#  )
case ":$PATH:" in
  *:/usr/local/bin:*) ;;
  *) export PATH="$PATH:/usr/local/bin"
esac

# Add /usr/X11R6/bin for gs
case ":$PATH:" in
  *:/usr/X11R6/bin:*) ;;
  *) export PATH="$PATH:/usr/X11R6/bin"
esac

##  ---------------------------------------------------------------------------

##  If the user set a scan device that exists, use it, otherwise look for a
##  device that would be reasonable. This should find the right device on
##  FreeBSD and most flavors of Linux.

if [ -c "$scan_device" ]
then :

elif [ -c /dev/pass0 ]
then scan_device=/dev/pass0

elif [ -c /dev/sg0 ]
then scan_device=/dev/sg0

elif [ -c /dev/sga ]
then scan_device=/dev/sga

else
  echo "don't know what device to use for scanner!" >&2
  exit 1
fi

##  ---------------------------------------------------------------------------

##  The phone_xxx settings have been deprecated, but so that old config files
##  work on new versions cleanly, copy them into any service-specific settings
##  where the service-specific settings have not been set.

if [ -z "$tpc_strip$tpc_prefix$tpc_deny" ]
then
  tpc_deny="$phone_deny"
  tpc_allow="$phone_allow"
  tpc_strip="$phone_strip"
  tpc_prefix="$phone_prefix"
fi

if [ -z "$hylafax_strip$hylafax_prefix$hylafax_deny" ]
then
  hylafax_deny="$phone_deny"
  hylafax_allow="$phone_allow"
  hylafax_strip="$phone_strip"
  hylafax_prefix="$phone_prefix"
fi

if [ -z "$maxemail_strip$maxemail_prefix$maxemail_deny" ]
then
  maxemail_deny="$phone_deny"
  maxemail_allow="$phone_allow"
  maxemail_strip="$phone_strip"
  maxemail_prefix="$phone_prefix"
fi

##  ---------------------------------------------------------------------------

##  Newlines are needed in strings here and there and they are ugly to embed
##  literally, so use this.

newline="
"

##  ---------------------------------------------------------------------------

##  Reimplement a simple case of 'tput' for the vt100 as an internal function
##  to avoid forking and other overhead in running the external command. Also
##  includes functions to light the LEDs, which a real VT100 supports, too,
##  but that I couldn't find a read termcap entry for.

tput ( ) {

  case "$1" in

    light) printf "\\033[H\\033[${2}q" ;;
    flash) printf "\\033[H\\033[?${2}t" ;;
    clear) printf "\\033[H\\033[J" ;;
     home) printf "\\033[H" ;;
      cup) printf "\\033[$(($3 + 1));$(($2 + 1))H" ;;
       cm) printf "\\033[$(($3 + 1));$(($2 + 1))H" ;;

    esac
}

##  ---------------------------------------------------------------------------

##  The labelkeys function outputs a line suitable for labelling the softkeys
##  at the bottom of the display. The first argument is which line on the
##  screen to display on (0-7) and the next four arguments are the text
##  strings, up to ten characters each.

labelkeys () {

  tput cm 0 $1
  shift

  for center in 3 4 5 6
  do
    left=$(( $center - ${#1} / 2 ))

    if [ $left -lt 0 ]
    then left=0
    fi

    right=$(( $left - 10 ))
    printf "%${left}s%${right}s" "" "$1"
    shift

  done
}

##  ---------------------------------------------------------------------------

##  The first argument to this function is a string that replaces the token
##  '<>' anywhere it occurs in the values of the variables named by the
##  additional arguments. The second and later arguments are the names of
##  variables, not values of variables.

substitute () {

  eval "temp1=\"$1\""

  while [ -n "$2" ]
  do
    eval "temp2=\"$2\""

    while [ -n "$temp2" -a -z "${temp2##*<>*}" ]
    do
      temp2="${temp2%<>*}$temp1${temp2#*<>}"
    done

    eval "${2#$}=\"$temp2\""
    shift
  done
}

##  ---------------------------------------------------------------------------

##  Function to display multi-line messages. The second argument is the
##  message to display with lines separated by newlines. Each line is centered
##  on the display. The first argument is a string that is substituted into
##  the message wherever the token "<>" appears.

multiline () {

  prompt="${2%$newline}"
  prompt="$prompt$newline"

  substitute "$1" '$prompt'

  while [ -n "$prompt" ]
  do
    line="${prompt%%$newline*}"
    left="$(( 20 + ${#line} / 2 ))"
    right="$(( 40 - $left ))"
    printf "%${left}s%${right}s\b\n" "$line" ""
    prompt="${prompt#*$newline}"
  done
}

##  ---------------------------------------------------------------------------

##  Gets the first item from a configuration list. This is simple, but it is
##  defined here by name to make the rest of the script more readable.
##
##  The first argument should be the contents of the list, the second argument
##  should be the name of the variable to get the value, including the leading
##  dollar-sign, so it should be single-quoted when called i.e. '$paper'.

getfirstitem () {

  eval "temp=\"$1\""

  eval "${2#\$}=\"\${temp%%|*}\""
}

##  ---------------------------------------------------------------------------

##  Gets the item from a list after the given item. The first argument is the
##  contents of the list, the second is the name of the variable containing
##  the current value, which will also receive the new value. Again, it needs
##  to be passed as the variable name with '$' not the value.

getnextitem () {

  eval "temp=\"$1\""

  temp="|$temp|${temp%%|*}|"
  eval "temp=\"\${temp#*|$2|}\""
  eval "${2#\$}=\"${temp%%|*}\""
}

##  ---------------------------------------------------------------------------

##  Splits the items of a list into individual variables. The first argument
##  is the list contents, the remaining are the variable names to put the
##  values into, same as with the prior list functions.

splititems () {

  eval "temp=\"$1|\""

  while [ -n "$2" ]
  do
    eval "${2#$}=\"${temp%%|*}\""
    temp="${temp#*|}"
    shift
  done
}

##  ---------------------------------------------------------------------------

##  Function to validate and adjust phone numbers for fax use. See the 
##  description of the configuration items phone_strip, phone_prefix,
##  phone_allow, and phone_deny for an explanation of what this does.

validatefax () {

  eval "temp=\"$1\""

  list="$phone_strip|"

  while [ -n "${list%|}" ]
  do
    entry="${list%%|*}"
    list="${list#*|}"

    case "$temp" in
      $entry)
        prefix="${entry%%[!0-9]*}"
        temp="${temp#$prefix}"
        break ;;
    esac
  done

  list="$phone_prefix|"

  while [ -n "${list%|}" ]
  do
    entry="${list%%|*}"
    list="${list#*|}"

    prefix="${entry%%[!0-9]*}"
    match="${entry#$prefix}"

    case "$temp" in
      $match)
        temp="$prefix$temp"
        break ;;
    esac
  done

  list="$phone_allow|"
  deny="$phone_deny|"

  while [ -n "${list%|}" ]
  do
    entry="${list%%|*}"
    list="${list#*|}"

    case "$temp" in
      $entry)
        deny=""
        break ;;
    esac
  done

  while [ -n "${deny%|}" ]
  do
    entry="${deny%%|*}"
    list="${deny#*|}"

    case "$temp" in
      $entry)
        temp=""
        break ;;
    esac
  done

  eval "${1#$}=\"$temp\""
}

##  ---------------------------------------------------------------------------

##  Select a predefined function for looking up users according to the setting
##  in user_source. If user_source is set to something other than one of these
##  then list_users and fetch_users will be used as-is. This allows for
##  completely custom functions.

case "$user_source" in

  file*)

    splititems "$user_source" '$dummy' '$file'

    list_users="awk -v 'FS=|' '/^[^#]/ && /^'\"\$1\"'/ \
		{ print \$1 }' '$file'"

    fetch_user="awk -v 'FS=|' '\$1 == \"'\"\$1\"'\" \
		{ print ; exit }' '$file'" ;;

  group*)

    groups="${user_source#*|}"

    list_users="awk -v FS=: '\$1 ~ \"^($groups)\$\" \
		{ gsub(\",\", \"\\n\", \$4); print \$4 }' /etc/group |
		grep \"^\$1\""

    fetch_user="awk -v FS=: '\$1 == \"'\"\$1\"'\" \
		{ print \$1 \"|\" \$1 \"@$domain_name|\" \$6 ; exit }' \
		/etc/passwd" ;;

  passwd*)

    splititems "$user_source" '$dummy' '$min' '$max'

    list_users="awk -v FS=: '\$3 >= $min && \$3 <= $max && /^'\"\$1\"'/ \
		{ print \$1 }' /etc/passwd"

    fetch_user="awk -v FS=: '\$1 == \"'\"\$1\"'\" \
		{ print \$1 \"|\" \$1 \"@$domain_name|\" \$6 ; exit }' \
		/etc/passwd" ;;
esac

##  Copy current stdout file descriptor so we can restore it after forking.

exec 3>&1

##  ---------------------------------------------------------------------------

(
  ##  Our stdout descriptor is now the pipe to the background process, so save
  ##  it on another descriptor for later use and restore stdout from saved
  ##  descriptor.

  exec 4>&1 1>&3

  ##  We run scanimage in the background so that we can monitor the keyboard in
  ##  the foreground. Trap SIGCHLD so that we will know when scanimage exits by
  ##  setting a variable that we can poll.

  trap sigchld=true CHLD

  ##  In the Bash shell, SIGCHLD does not get delivered unless job control is
  ##  enabled, which is only done by default in interactive shells. So, if we
  ##  are running under Bash, enable job control explicitly.

  if [ -n "$BASH_VERSION" ]
  then set -o monitor
  fi

  ##  The main scanner code starts here. It is a big endless loop so that we
  ##  can start over from the menu after a scan operation.

  while :
  do

    ## Reimport variables per job, (don't stick with boot defaults).
    ## (eg allow a load of European A4 to be  scanned in morning, then a
    ## remote edit & change of default for a load of USA letter in afternoon.

    if [ -r "$LOCALETC/sjrun.lang" ]
    then . "$LOCALETC/sjrun.lang"
    fi
    if [ -r "$LOCALETC/sjrun.conf" ]
    then . "$LOCALETC/sjrun.conf"
    fi

    ##  Set the default number of sides of originals and set LED accordingly.
    ##  The 'sides' variable is either 1 or 2 for single or double-sided. The
    ##  corresponding LEDs are set by, coincidentally, values of 1 and 2.

    scan_sides=$sides_default
    tput light 0
    tput light $scan_sides

    ##  Clear the screen and display the softkey labels for the main functions.

    tput clear
    tput cm 0 7

    splititems "$title_keys" '$soft1' '$soft2' '$soft3' '$soft4'
    labelkeys 7 "$soft1" "$soft2" "$soft3" "$soft4"

    ##  The next loop implements the topmost menu, which is the choice of
    ##  overall device function: copy, email, fax, or save to a directory.

    while :
    do

      ##  Display the title screen each time around to the date gets updated.

      tput cm 0 0
      multiline "`date \"+$date_format\"`" "$prompt_main"

      ##  The timeout on input here is so that we exit the read periodically
      ##  and loop around to update the date on the display. Elsewhere, the
      ##  timeouts are so that, if left alone, the scanner returns to the top
      ##  menu.

      read -t 30 key

      case "$key" in

        ##  Implement a couple of 'Easter Egg' sequences to help with device
        ##  maintenance. Store up keypad keystrokes, and if the keys matching
        ##  'BOOT' or 'HALT' are pressed, followed by enter, the reboot or
        ##  halt the box, accordingly.

        [0-9])

	  if [ ${#magic} -lt 10 ]
	  then magic=$magic$key
	  else magic=${magic#?}$key
	  fi ;;

        ENTER)

	  ##  If 'HALT' + ENTER is typed, halt the operating system.

	  if [ -z "${magic%%*4258}" ]
	  then
	    tput clear
	    multiline "" "$prompt_halt"

	    halt
	    exit

	  ##  If 'BOOT' + ENTER is typed, reboot the operating system.

	  elif [ -z "${magic%%*2668}" ]
	  then
	    tput clear
	    multiline "" "$prompt_boot"

	    reboot
	    exit

	  ##  If 'ADDR' + ENTER is typed, display the scanner's IP address

	  elif [ -z "${magic%%*2337}" ]
	  then
	    ifconfig | while read tag address rest
	    do
	      address="${address#*:}"

	      if [ "$tag" = "inet" -a "${address##127.*}" ]
	      then
	        tput cm 0 5
	        multiline "$address" "$prompt_addr"
	        break
	      fi
	    done

	  ##  If 'VERS' + ENTER is typed on keypad, display software version

	  elif [ -z "${magic%%*8377}" ]
	  then
            tput cm 0 5
	    multiline "$version" "$prompt_vers"

	  ##  If 'CONF' + ENTER is typed on keypad, run configuration program
	  ##  Note: the configuration program is not open source. Please
	  ##  contact the author to purchase a commercial upgrade package.

	  elif [ -z "${magic%%*2663}" ]
	  then
	    . sjcfg
	  fi ;;

        ##  Select the device function mode based on the SOFT1 - SOFT 4 keys,
        ##  setup defaults for that mode, and break out of this loop.

        SOFT1)

	  function="COPY"
	  scan_format="pnm"
	  resolution="$resolution_copy"
          duplex="$duplex_default"
          copies=1
	  getfirstitem "$printer_list" '$printer'
	  paper_list="$sizes_copy"
	  modes_list="$modes_copy"
	  break ;;

        SOFT2)

	  function="EMAIL"
	  scan_format="tiff"
	  resolution="$resolution_1bit"
	  saveifs="$IFS"
	  user=1
	  lastfilter=
	  getfirstitem "$output_list" '$output'
	  modes_list="$modes_email"
	  paper_list="$sizes_email"
	  break ;;

        SOFT3)

	  function="FAX"
	  scan_format="tiff"
	  resolution="$resolution_fax"
	  getfirstitem "$detail_list" '$detail'
	  getfirstitem "$service_list" '$service'
	  modes_list="$modes_fax"
	  paper_list="$sizes_fax"
          phone=_
	  break ;;

        SOFT4)

	  function="SAVE"
	  scan_format="tiff"
	  resolution="$resolution_1bit"
	  saveifs="$IFS"
	  user=1
	  lastfilter=
	  getfirstitem "$output_list" '$output'
	  modes_list="$modes_save"
	  paper_list="$sizes_save"
	  break ;;

        ##  Allow the user to change the number of sides of the originals at
        ##  pretty much any time. Use the LED indicators on the front panel to
        ##  indicate the number of sides selected.

        DUPLEX)

	  scan_sides=$(( 3 - $scan_sides ))
	  tput light 0
	  tput light $scan_sides
	  ;;

      esac
    done

    ##  Now get the settings for the function selected. This is done in a
    ##  common loop for all the functions, since many of the settings are
    ##  similar. First setup a few common defaults for all functions.

    scale=100
    density=0
    getfirstitem "$paper_list" '$paper'
    getfirstitem "$modes_list" '$scan_mode'
    getfirstitem "$rotate_list" '$rotate'

    ##  This loop wraps the whole settings menu and scan process. This way,
    ##  after a function is complete, we return to the settings menu in case
    ##  the user wants to do the same function again with the same or similar
    ##  settings.

    while :
    do

      ##  Always start clean at the topmost menu

      if [ $function = FAX -a "$fax_sender" = select ]
      then toppage=FROM
      else toppage=MAIN
      fi

      setting="$toppage"

      tput clear
      page=PAGE1

      filter="$lastfilter"
      lastfilter="x$lastfilter"

      ##  This loop implements the actual function setting menus.

      while :
      do

        ##  Internally, density is kept as in integer between -9 and 9.
        ##  Translate this to something more verbose for display.

        if [ $density -lt 0 ]
        then
          splititems "$density_darker" '$density1' '$density2'

        elif [ $density -gt 0 ]
        then
          splititems "$density_lighter" '$density1' '$density2'

        else
          splititems "$density_normal" '$density1' '$density2'
        fi

        substitute "${density#-}" '$density1' '$density2'

        ##  Compose display string for resize of document.

        if [ "${scale%_}" -lt 100 ]
        then
	  splititems "$resize_smaller" '$resize1' '$resize2'

        elif [ "${scale%_}" -gt 100 ]
        then
	  splititems "$resize_larger" '$resize1' '$resize2'

        else
	  splititems "$resize_normal" '$resize1' '$resize2'
        fi

        substitute "$scale" '$resize1' '$resize2'

        ##  Get display name of scan mode

        splititems "\$modes_$scan_mode" '$mode1' '$mode2'

        ##  The SOFT2 key function changes depending on what function was
        ##  selected. Make up appropriate display labels depending on function.

        case $function in

	  COPY)

	    splititems "\$printer_$printer" '$soft2a' '$soft2b'
	    splititems "\$duplex_${duplex}sided" '$soft3a' '$soft3b' ;;

	  FAX)

	    splititems "\$service_$service" '$soft2a' '$soft2b'
	    splititems "\$detail_$detail" '$soft3a' '$soft3b' ;;

	  EMAIL|SAVE)

	    splititems "\$rotate_$rotate" '$soft2a' '$soft2b'
	    splititems "\$output_$output" '$soft3a' '$soft3b' ;;

	esac

	##  Handle user name selection and filter for the appropriate modes.

        case $function-$setting in

	  EMAIL-*|SAVE-*|FAX-FROM)

	    if [ "${#filter}" -lt "${#lastfilter}" ]
	    then
	      saveifs="$IFS"
	      IFS="$newline"
	      set -- "$filter"
#	      set -- `eval $list_users | sort -f`
# I want my users left in the order they appear in /etc/group
	      set -- `eval $list_users          `
	      IFS="$saveifs"
	      user=1

	    elif [ "${#filter}" -gt "${#lastfilter}" ]
	    then
	      saveifs="$IFS"
	      IFS="$newline"
	      set -- `echo "$*" | grep -i "^$filter"`
	      IFS="$saveifs"
	      user=1
	    fi

	    if [ $# -eq 0 ]
	    then
	      set -- "(none)"
	      user=1
	    fi

	    lastfilter="$filter"
	    eval "name=\${$user}"

        esac

        ##  For the main setting for each function i.e. number of copies, fax
        ##  number, etc., and also for setting that have more than two or three
        ##  options, put up a prompt in the middle of the display.

        tput cm 0 1

        case $function-$setting in

	  COPY-MAIN)
	    prompt="$prompt_copies $copies"
	    length=$(( ${#prompt_copies} + 4 )) ;;

	  FAX-MAIN)
	    prompt="$prompt_fax $phone"
	    length=$(( ${#prompt_fax} + 15 )) ;;

	  FAX-FROM)
	    prompt="$prompt_from $name"
	    length=$(( ${#prompt_from} + 15 )) ;;

	  EMAIL-MAIN)
	    prompt="$prompt_email $name"
	    length=$(( ${#prompt_email} + 15 )) ;;

	  SAVE-MAIN)
	    prompt="$prompt_save $name"
	    length=$(( ${#prompt_save} + 15 )) ;;

	  *-RESIZE)
	    prompt="$prompt_resize $scale"
	    length=$(( ${#prompt_resize} + 3 )) ;;

	  *-DENSITY)
	    prompt="$prompt_density $density1 $density2"
	    length=$(( ${#prompt_density} + 15 )) ;;

        esac

        left=$(( 20 - $length / 2 ))
        length=$(( 40 - $left ))
        printf "%${left}s%-${length}s" "" "$prompt"

        splititems "\$paper_$paper" '$paper1' '$paper2'
        splititems "$more_options" '$soft4a' '$soft4b'

        ##  Use the bottom two lines of the display for the settings other than
        ##  the main setting for the function. Display them above the soft key
        ##  that is used to change the particular setting.

        case $page in

	  PAGE1)

	    labelkeys 6 "$paper1" "$soft2a" "$soft3a" "$soft4a"
	    labelkeys 7 "$paper2" "$soft2b" "$soft3b" "$soft4b" ;;

	  PAGE2)

	    labelkeys 6 "$resize1" "$density1" "$mode1" "$soft4a"
	    labelkeys 7 "$resize2" "$density2" "$mode2" "$soft4b" ;;

        esac

	case "$function-$key-$setting" in

	  FAX-START-MAIN|FAX-ENTER-MAIN)

	    fax_phone="${phone%_}"
	    validatefax '$fax_phone'

	    if [ -z "$fax_phone" ]
	    then
	      tput cm 0 3
	      multiline "" "$phone_error"
	      key="ENTER"
	      error=1
	    fi

	    if [ "$service" = "tpc" ]
	    then
	      tput cm 0 3
	      multiline "" "$please_wait"

	      temp=`host -t mx $fax_phone.iddd.tpc.int`

	      tput cm 0 3
	      printf "%40s" ""

	      if [ $? -ne 0 ] || 
	         [ -z "${temp%%*sinkhole.tpc.int}" ] ||
	         [ -n "${temp##*is handled*}" ]
	      then
	        tput cm 0 3
	        multiline "" "$phone_unreach"
	        key="ENTER"
	        error=1
	      fi
	    fi

	esac

	##  We detect the start keypress here, after coming back from the
        ##  end of the loop, so that the display can be updated by the code
	##  above first.

	if [ "$key" = START ]
	then break
	fi

        ##  If timeout occurs on the read, the value of the variable will be
        ##  unchanged, so set it first to STOP to define the action on timeout.

        key=STOP
        read -t $timeout_idle key

        if [ "$error" = 1 ]
        then
	  tput cm 0 3
	  printf "                                        \b\n"
	  printf "                                        \b\n"
          error=
        fi

        ##  Remember what setting we started off changing so that we can tell
        ##  at the end of the big case statement if we changed mode to a
        ##  setting so we can clean up the display variable appropriately.

        previous=$setting

        ##  Which action to perform out of this unified set is determined by
        ##  a combination of the key pressed, function we are in, and setting
        ##  we are currently changing. By using wildcards, we can make some
        ##  actions apply across multiple functions easily.

        case "$page-$key-$function-$setting" in

	  ##  The duplex key chenges the number of sides of the originals.

	  *-DUPLEX-*-*)

	    scan_sides=$(( 3 - $scan_sides ))
	    tput light 0
	    tput light $scan_sides ;;

	  ##  On page one, the soft1 key always selects paper size.

	  PAGE1-SOFT1-*-*)

	    getnextitem "$paper_list" '$paper' ;;

	  ##  On page one, the soft4 key always changes to setting page two.

	  PAGE1-SOFT4-*-*)

	    setting="$toppage"
	    page=PAGE2 ;;

	  ##  On page two, the soft1 key always selects resize mode.

	  PAGE2-SOFT1-*-*)

	    setting=RESIZE ;;

	  ##  On page two, the soft2 key changes the brightnes setting.

	  PAGE2-SOFT2-*-*)

	    setting=DENSITY ;;

	  ##  On page two, the soft3 key always changes the scan mode between
	  ##  lineart and continuous tone, with continuous tone meaning
	  ##  halftone for copy and fax modes and grayscale for email or save.

	  PAGE2-SOFT3-*-*)

	    getnextitem "$modes_list" '$scan_mode'

	    case "$scan_mode-$function" in

	      *-COPY)
	        resolution="$resolution_copy" ;;

	      *-FAX)
	        resolution="$resolution_fax" ;;

	      grayscale-*)
	        resolution=$resolution_8bit ;;

	      *)
	        resolution=$resolution_1bit ;;

	    esac ;;

	  ##  On page two, the soft4 key always changes to setting page one.

	  PAGE2-SOFT4-*-*)

	    setting="$toppage"
	    page=PAGE1 ;;

	  ##  Get number of copies to make, limit the maximum. Allow entry
	  ##  with either the up and down arrows, or the numeric keypad.

	  *-DOWN-COPY-MAIN)

	    if [ "${copies#*_}" -gt 1 ]
	    then
	      copies="$(( $copies - 1 ))"
	    fi ;;
	
	  *-UP-COPY-MAIN)

	    if [ -n "${copies#*_}" ]
	    then
	      if [ "$copies" -lt "$copies_limit" ]
	      then
	        copies="$(( $copies + 1 ))"
	      fi
	    fi ;;
 
	  *-[0-9]-COPY-MAIN)

	    if [ "${copies#*_}" ]
	    then
	      if [ "$key" != 0 ]
	      then
	        copies="${key}_"
	      fi

	    elif [ "${copies%_}$key" -le "$copies_limit" ]
	    then
	      if [ "${copies%_}$key" -ge 1 ]
	      then
	        copies="${copies%_}${key}_"
	      fi
	    fi ;;

	  *-BACK-COPY-MAIN)

            if [ -z "${copies#*?_}" ]
            then
	      copies="${copies%?_}_"
           fi ;;

	  ##  Enter a fax number. By overriding the default START key action,
	  ##  we can check the number and prefix 1 plus the area code if it is
	  ##  only seven digits, or refuse to send at all if it is less than 7.

	  *-[0-9]-FAX-MAIN)

	    if [ -n "${phone##*_}" ]
	    then
	      phone="${key}_"

	    elif [ "${#phone}" -le 15 ]
	    then
	      phone="${phone%_}${key}_"
	    fi ;;

	  *-BACK-FAX-MAIN)

	    phone="${phone%_}"
	    phone="${phone%?}_" ;;


	  ##  Choose a user ID to either mail to or save to home directory for.
	  ##  The id can be selected with the up and down arrow keys. The 
	  ##  numeric keys can be used to filter the list to narrow down
	  ##  choices to those matching the letters corresponding to the keys
	  ##  pressed. So most users should be able to enter their name or the
	  ##  first few letters of their name and get within a name or two of
	  ##  theirs.

	  *-[2-9]-SAVE-MAIN|*-[2-9]-EMAIL-MAIN|*-[2-9]-FAX-FROM)

	    temp="2AaBbCc3DdEeFf4GgHhIi5JjKkLl6MmNnOo7PpQqRrSs8TtUuVv9WwXxYyZz"
	    temp="${temp#*$key}"
	    filter="${filter}[${temp%%[0-9]*}]" ;;

	  *-BACK-SAVE-MAIN|*-BACK-EMAIL-MAIN|*-BACK-FAX-FROM)
	    filter="${filter%[[]*}" ;;
	
	  *-ENTER-SAVE-MAIN|*-ENTER-EMAIL-MAIN)
	    lastfilter=
	    filter= ;;

	  *-CHECK-SAVE-MAIN|*-CHECK-EMAIL-MAIN)
	    lastfilter=
	    filter= ;;

	  *-DOWN-SAVE-MAIN|*-DOWN-EMAIL-MAIN|*-DOWN-FAX-FROM)
	    if [ $user -lt $# ]
	    then
	      user=$(( $user + 1 ))
	    fi ;;

	  *-UP-SAVE-MAIN|*-UP-EMAIL-MAIN|*-UP-FAX-FROM)
	    if [ $user -gt 1 ]
	    then
	      user=$(( $user - 1 ))
	    fi ;;

	  ##  SOFT2 rotates through list of configured printers in copy mode.

	  PAGE1-SOFT2-COPY-*)

	    getnextitem "$printer_list" '$printer' ;;

	  ##  SOFT3 changes the number of sides of output copies in copy mode.

	  PAGE1-SOFT3-COPY-*)

	    duplex=$(( 3 - $duplex )) ;;

	  ##  In the fax function, SOFT2 changes between fine and normal mode.

	  PAGE1-SOFT3-FAX-*)

	    getnextitem "$detail_list" '$detail' ;;

	  ##  Select fax gateway or transport service

	  PAGE1-SOFT2-FAX-*)

	    getnextitem "$service_list" '$service'

	    eval "phone_deny=\"\$${service}_deny\""
	    eval "phone_allow=\"\$${service}_allow\""
	    eval "phone_strip=\"\$${service}_strip\""
	    eval "phone_prefix=\"\$${service}_prefix\"" ;;

	  ##  In the email or save function, SOFT2 selects the document format.

	  PAGE1-SOFT3-EMAIL-*|PAGE1-SOFT3-SAVE-*)

	    getnextitem "$output_list" '$output' ;;


	  PAGE1-SOFT2-EMAIL-*|PAGE1-SOFT2-SAVE-*)

	    getnextitem "$rotate_list" '$rotate' ;;
	    
	  ##  If we are in the density setting mode, allow either the up and
	  ##  down arrows, or the numeric keypad, with # and * selecting
	  ##  lighter and darker.

	  *-DOWN-*-DENSITY)
	    if [ $density -gt -9 ]
	    then
	      density=$(( $density - 1 ))
	    fi ;;

	  *-UP-*-DENSITY)
	    if [ $density -lt 9 ]
	    then
	      density=$(( $density + 1 ))
	    fi ;;

	  *-[0-9]-*-DENSITY)
	    density=${density%?}$key ;;

	  *-"#"-*-DENSITY)
	    density=${density#-} ;;

	  *-"*"-*-DENSITY)
	    density=-${density#-} ;;

	  ##  For the resize setting, allow either the up and down arrows, or
	  ##  the numeric keypad. Limit the setting to between 20% and 500%.

	  *-DOWN-*-RESIZE)
	    if [ -n "${scale#*_}" ]
	    then
	      if [ "$scale" -gt 20 ]
	      then
	        scale=$(( $scale - 1 ))
	      fi
	    fi ;;
	
	  *-UP-*-RESIZE)
	    if [ -n "${scale#*_}" ]
	    then
	      if [ "$scale" -lt 500 ]
	      then
	        scale=$(( $scale + 1 ))
	      fi
	    fi ;;
	
	  *-[0-9]-*-RESIZE)
	    if [ -z "${scale#*_}" ]
	    then
	      if [ "${scale%_}$key" -le 500 ]
	      then
	        scale="${scale%_}${key}_"
	      fi
	    elif [ "$key" != 0 ]
	    then
	      scale="${key}_"
	    fi ;;

	  *-BACK-*-RESIZE)
	    if [ -z "${scale#*?_}" ]
	    then
	      scale="${scale%?_}_"
	    fi ;;

	  ##  In the case of FAX-FROM mode, we want to suppress the START
	  ##  or ENTER keypress from initiating phone number checking.

	  *-START-FAX-FROM|*-ENTER-FAX-FROM)
	    toppage=MAIN
	    setting=MAIN
	    key=NONE ;;

	  ##  If the CHECK or ENTER key was pressed, exit any setting mode we
	  ##  were in and go back to the main setting for the current function,
	  ##  i.e. number of copies for copy mode, phone number for fax mode

	  *-CHECK-*-*|*-ENTER-*-*)
	    setting="$toppage" ;;

	  ##  If the STOP key was pressed, go back to the top-most-level menu.

	  *-STOP-*-*)
	    break 2 ;;

        esac

        ##  If a setting mode was exited, update the display variables as
        ##  needed i.e. remove the cursor from a numeric setting field.

        if [ $previous != $setting \
	     -o "$key" = START -o "$key" = ENTER -o "$key" = CHECK ]
        then

	  case $function-$previous in

	    COPY-MAIN)

	      copies="${copies%_}"

	      if [ -z "$copies" ]
	      then copies=1
	      fi ;;

	    FAX-MAIN)

	      phone="${phone%_}" ;;

	    *-RESIZE)

	      if [ -z "${scale%_}" ]
	      then scale=100

	      elif [ "${scale%_}" -lt 20 ]
	      then scale=20

	      else scale="${scale%_}"
	      fi ;;

	  esac
        fi

      done

      ##  All the settings have been changed as needed and the user has pressed
      ##  START, so begin the scanning. Make a directory to hold the scans.

      directory=`date "+/tmp/scan-%H%M%S"`
      mkdir $directory

      ##  Setup a few overall variables controlling the scanning.

      scan_pass=1
      scan_start=1001
      scan_step=$scan_sides

      ##  Scale the brightness setting to the configured range. Although the
      ##  range of SANE is -127 to 127, going much farther than +/- 50 or so
      ##  gives a way-too-dark or way-too-light scan.

      scan_bright=$(( $density * $brightness_range / 9 + $brightness_offset ))

      ##  Get the page size (in tenths of millimeters) from configured sizes.

      splititems "\$paper_size_$paper" '$page_width' '$page_height'

      ##  This loop is for scanning both sides of the originals and multiple
      ##  sets of input pages. We break out at the end when the job is done.

      while :
      do

        ##  Flash the LED next to the START key so the user knows something is
        ##  happening and display the scanning message.

        tput flash 3

        tput clear
        multiline "0" "$prompt_scan"

        ##  Try the document feeder first, if no scan file gets produced, then
        ##  there were no documents in the feeder, so try a regular flatbed
        ##  scan next.

        for scan_source in adf normal
        do

	  ##  Always scan in batch mode, but only scan one page if we are not
	  ##  using the document feeder.

	  if [ $scan_source = normal ]
	  then onepage="--batch-count=1"
	  else unset onepage
	  fi

	  ##  If we are making a copy, set the origin offset for the printer.

	  unset scan_left scan_top

	  if [ "$function" = "COPY" ]
	  then
	    splititems "\$print_origin_$printer" '$scan_left' '$scan_top'
	  fi

	  ##  If the origin was not set, assume values of zero.

	  if [ -z "$scan_left" -o -z "$scan_top" ]
	  then
	    scan_left=0
	    scan_top=0
	  fi

	  ##  If scanning from the ADF, compensate for the fact that the
	  ##  page is aligned differently, that is, in relation to the center
	  ##  of the width of the page, rather than the top left corner.

	  if [ $scan_source = adf ]
	  then
	    scan_left=$(( $scan_left + 1110 - $page_width / 2 ))
	  fi

	  ##  The resize setting works by changing the scan resolution, so
	  ##  calculate the correct resolution and area to yield a full page.

	  scan_resolution=$(( $resolution * $scale / 100 ))

	  scan_width=$(( $page_width * 100 / $scale - $scan_left ))
	  scan_height=$(( $page_height * 100 / $scale - $scan_top ))

	  ##  Save the settings that the background processing task will need
	  ##  to convert and ship out the scans.

	  ##  Limit to actual page area, these may be way off otherwise from
	  ##  page reduction or print offset.

	  if [ $scan_width -gt $page_width ]
	  then
	    scan_width=$page_width
	  fi

	  if [ $scan_height -gt $page_height ]
	  then
	    scan_height=$page_height
	  fi

	  ##  We're still in tenths of a millimeter, change to millimeters

	  scan_width=$(( $scan_width / 10 )).$(( $scan_width % 10 ))
	  scan_height=$(( $scan_height / 10 )).$(( $scan_height % 10 ))

	  scan_left=$(( $scan_left / 10 )).$(( $scan_left % 10 ))
	  scan_top=$(( $scan_top / 10 )).$(( $scan_top % 10 ))

	  ##  Temporarily divert stdout so that scanner error messages and
	  ##  shell child exit messages don't appear on the LCD, but save
	  ##  stdout on a different filedescriptor so we can restore it later.

          exec 1>&2

	  ##  Page count gets reset every time scanimage runs.

	  page_count=0
	  scan_watch=$scan_start

	  ##  Reset flag for receipt of SIGCHLD signal.

	  sigchld=false

	  ##  Now actually start the scan in the background.

	  echo "scanimage \
	    --device=hp:$scan_device \
	    --mode=$scan_mode \
	    --resolution=$scan_resolution \
	    --source=$scan_source \
	    --format=$scan_format \
	    --brightness=$scan_bright \
	    --batch=$directory/page%d.$scan_format \
	    --batch-start=$scan_start \
	    --batch-increment=$scan_step $onepage \
	     -x $scan_width \
	     -y $scan_height \
	     -l $scan_left \
	     -t $scan_top" >> /tmp/log.jhs
	  scanimage \
	    --device=hp:$scan_device \
	    --mode=$scan_mode \
	    --resolution=$scan_resolution \
	    --source=$scan_source \
	    --format=$scan_format \
	    --brightness=$scan_bright \
	    --batch=$directory/page%d.$scan_format \
	    --batch-start=$scan_start \
	    --batch-increment=$scan_step $onepage \
	     -x $scan_width \
	     -y $scan_height \
	     -l $scan_left \
	     -t $scan_top &

	  ##  Watch the keypad for the STOP key. If it is pressed, kill the
	  ##  background scan job and bail out completely. When the scan
	  ##  ends, $sigchld will be set to 'true' and the loop will exit.

	  while ! $sigchld
	  do

	    while [ -f "$directory/page$scan_watch.$scan_format" ]
	    do
	      tput cm 0 0 >&3
	      multiline $page_count "$prompt_scan" >&3

	      scan_watch=$(( $scan_watch + $scan_step ))
	      page_count=$(( $page_count + 1 ))
	    done

	    read -t 1 key

	    if [ "$key" = STOP ]
	    then

	      ##  Send the kill signal and wait for it to exit so that the
	      ##  shell's process done message appears while stdout is away.

  	      kill $!
  	      wait

	     ##  Remove the temporary directory

	      rm -rf "$directory"

	      ##  Restore stdout, stop the LED flashing, and go all the way
	      ##  back to the top menu.

	      exec 1>&3
	      tput flash 0
  	      break 4
	    fi
	  done

	  ##  There is no direct way to detect when a paper jam occurs during
	  ##  a job. However, scanimage coredumps on the scan following a
	  ##  paper jam, so if this was a scan from the adf, try another
	  ##  one now. If the previous scan really ended because the adf is
	  ##  empty, nothing will happen, but if it ended because of a paper
	  ##  jam, we will get a coredump which we can detect. Only do this
	  ##  if we actually got a page; a jam seems to generate a garbage
	  ##  scan and this saves time when we are only probing the adf.

	  paper_jam=no

          if [ -f "$directory/page$scan_start.$scan_format" \
	       -a "$scan_source" = adf ]
	  then
	    scanimage \
	      --device=hp:$scan_device \
	      --source=adf > /dev/null

	    if [ -f scanimage.core ]
	    then
	      paper_jam=yes

	      rm scanimage.core

	      if [ -c /dev/pass0 ]
	      then
	        camcontrol reset all

	      elif [ -f /proc/scsi/scsi ]
	      then
	        echo "scsi remove-single-device 0 0 1 0" >/proc/scsi/scsi
	        echo "scsi add-single-device 0 0 1 0" >/proc/scsi/scsi
	      fi
	    fi
	  fi

	  ##  It's safe to restore stdout now.

          exec 1>&3

	  ##  If a paper jam was detected, break the scan loop so that we can
	  ##  wait for the user to clear the jam and restart.

	  if [ $paper_jam = yes ]
	  then break
	  fi

	  ##  If we got a file, then exit. Otherwise, if this was the first
	  ##  loop, the ADF didn't have a document, loop back and scan flatbed.

          if [ -f "$directory/page$scan_start.$scan_format" ]
          then break
          fi

        done

	##  Make input timeouts look like the STOP key was pressed.

        key=STOP

	##  Stop the light from flashing.

	tput flash 0

	##  Finish counting pages scanned, as we might have gotten the
	##  signal before we saw all the files

	while [ -f "$directory/page$scan_watch.$scan_format" ]
	do
	  scan_watch=$(( $scan_watch + $scan_step ))
	  page_count=$(( $page_count + 1 ))
	done

	##  Check if the last file counted has disappeared and adjust page
	##  count if so. This happens after the last page because
	##  scanimage creates the next file before it knows if the ADF has
	##  a page available or not.

	scan_watch=$(( $scan_watch - $scan_step ))

	if [ ! -f "$directory/page$scan_watch.$scan_format" ]
	then
	  page_count=$(( $page_count - 1 ))
	fi

	##  If a paper jam occurred, ask the user to clear and continue.

	if [ $paper_jam = yes ]
	then
	  prompt="$prompt_jam"
	  timeout="$timeout_jam"

        ##  If we need to do the back of two-sided originals, prompt for flip.

        elif [ $scan_sides != $scan_pass ]
        then
	  prompt="$prompt_flip"
	  timeout="$timeout_flip"

        ##  If multi-part scanning enabled, prompt for next part to scan.

        elif [ $multi_part = yes -o $multi_part = $scan_source ]
        then
	  prompt="$prompt_part"
	  timeout="$timeout_part"

        ##  Otherwise, we are done, queue the document up for post-processing.

        else
	  break
        fi

	##  When a paper jam occurs, a bad scan page is generated. Back up
	##  the start scan by one page when we resume.

	if [ $paper_jam = yes ]
	then
	  scan_start=$(( $scan_start + $page_count - $scan_step ))

	##  If we just finished the first pass of a double-sided scan, then
	##  set starting page count for next scan to one past the last page
	##  scanned, and set up for page numbers to decrease.

        elif [ $scan_sides -gt $scan_pass ]
        then
	  scan_start=$(( $scan_start + $page_count * 2 - 1 ))
	  scan_pass=2
	  scan_step=-2

	##  Otherwise, if we finished the second pass of a double-sided scan,
	##  leave three empty page slots by starting four higher than last one.

	elif [ $scan_pass -eq 2 ]
	then
	  scan_start=$(( $scan_start + 4 ))
	  scan_pass=1
	  scan_step=$scan_sides

	##  If neither of the previous, then we just finished a single-sided
	##  scan, so set the start of the next scan three higher to leave
	##  three empty slots between parts.

        else
	  scan_start=$(( $scan_start + $page_count + 3 ))
	  scan_pass=1
	  scan_step=$scan_sides
        fi

        tput clear
        multiline "$page_count" "$prompt"

        while read -t $timeout key
        do
	  case "$key" in

	    START)
	      break ;;

	    STOP)
	      if [ $scan_pass = 1 ]
	      then
	        break 2

	      else
	        break 3
	      fi ;;

	    DUPLEX)
	      if [ $scan_pass = 1 ]
	      then
	        scan_sides=$(( 3 - $scan_sides ))
		scan_step=$scan_sides
	        tput light 0
	        tput light $scan_sides
	      fi ;;

          esac
        done

      done

      ##  Send document directory to background process

      ( echo "function=\"$function\""
        echo "output=\"$output\""
        echo "paper=\"$paper\""
        echo "duplex=\"$duplex\""
        echo "copies=\"$copies\""
        echo "printer=\"$printer\""
        echo "detail=\"$detail\""
        echo "rotate=\"$rotate\""
        echo "service=\"$service\""
        echo "name=\"$name\""
        echo "resolution=\"$resolution\""
        echo "fax_phone=\"$fax_phone\""
        echo "page_height=\"$page_height\""
        echo "page_width=\"$page_width\""
        echo "scan_resolution=\"$scan_resolution\""
        echo "scan_format=\"$scan_format\""
        echo "scan_mode=\"$scan_mode\""

      ) >"$directory/settings"

      echo "$directory" >&4

    done
  done

) | (

##  ---------------------------------------------------------------------------

##  After the scan is complete, the user interface / scanning part passes the
##  staging directory name to here, the post-processing part. This allows the
##  post-processing phase to be serialized.

  exec >&3 3>&- >&2

  while read directory
  do

    ##  Switch to the staging directory and pull in the settings passed from
    ##  the user interface process.

    cd "$directory"
    . settings

    case $function in

      EMAIL|SAVE)

	##  Lookup the user's email address and home directory.

	set -- "$name"
	splititems "`eval $fetch_user`" '$dummy' '$recipient' '$homedir'

	##  If a home subdirectory is configured, add it to what we looked up.

	if [ -n "$save_directory" ]
	then homedir="$homedir/$save_directory"
	fi

	##  Expand the subject line and message body to include the filename.

	subject="$email_subject"
	body="$email_body"
	sender="$email_sender" 

	##  Choose and appropriate compression format based on image type.

	if [ "$scan_mode" = "grayscale" ]
	then compress="$compress_gray"
	else compress="$compress_tiff"
	fi ;;


      FAX)

	##  Set text body of message and subject according to service used.

	case "$service-$detail" in
	  maxemail-fine) body="{fine}" subject="{nocoverpage}" ;;
	  maxemail-*) body="" subject="{nocoverpage}" ;;
	  *) body="" subject="Fax for $fax_phone attached" ;;
	esac

	##  Choose the sender if appropriate, otherwise use default.

	sender="$fax_sender"

	if [ "$sender" = select ]
	then
	  set -- "$name"
	  splititems "`eval $fetch_user`" '$name' '$sender' '$home'
	fi

	##  Setup the correct recipient format for the service selected.

	case "$service" in
	  hylafax) recipient="$hylafax_email" ;;
	  maxemail) recipient="<>@maxemailsend.com" ;;
	  tpc) recipient="remote-printer._@<>.iddd.tpc.int" ;;
	esac

	substitute "$fax_phone" '$recipient'

	##  Attachment formatting options

	output="tiff" compress="$compress_fax" ;;

    esac

    case $function in

      ##  For copies, convert to PCL and spool to the printer. Of course, this
      ##  be changed to convert to Postscript if that's the sort of printer
      ##  you have. If so, change the scan format and use tiff2ps rather than
      ##  pnmtops, as it's much faster and produces better Postscript.

      COPY)

	eval "pclsize=\"\${pcl_paper_$paper}\""

	if [ -z "$pclsize" ]
	then pclsize="$pcl_paper_letter"
	fi

	##  Send reset escape at start of job to clear any leftover cruft

	( printf "\\033E"
	  printf "\\033&l$(($duplex - 1))S"
	  printf "\\033&l${copies}X"
	  printf "\\033&l${pclsize}A"
 
	  for file in *.pnm
	  do
	    pbm2lj -packbits -noreset -resolution $resolution_copy "$file"
	    printf "\\033&a0G"
	  done

	  printf "\\033E" ) | lpr -P "$printer" ;;

      SAVE|EMAIL|FAX)

	##  If we scanned at a different resolution than the output should be,
	##  then force resolution to output resolution to effect scaling.

	if [ $resolution != $scan_resolution ]
	then tiffres $resolution *.tiff
	fi

	case $output in

	  pdf*)

	    ps_size="$page_width 72 mul 254 div $page_height 72 mul 254 div"

	    if [ $rotate = "left" -o $rotate = "right" ]
	    then ps_size="$ps_size exch"
	    fi

	    eval "ps_rotate=\"\$pdf_rotate_$rotate\""

	    ( echo "/getpagesize { $ps_size } bind def"
	      echo "/rotatepage { getpagesize $ps_rotate } bind def"
	      echo "/showpage { showpage rotatepage } bind def"
	      echo "getpagesize $pdf_set_page rotatepage"

	      tiff2ps -$pdf_ps_level *.tiff ) |

	    gs -q \
	      -sDEVICE=pdfwrite \
	      -sOutputFile=output \
	      -dBATCH \
	      -dNOPAUSE -

	    content_type="application/pdf"
	    filename="`date \"+$file_name.pdf\"`" ;;

	  tiff*)

	    ##  If the page orientation is not normal, rotate the files first.

	    if [ "$rotate" != "none" ]
	    then
	      for file in *.tiff
	      do
	        tiffrotate "$rotate" "$file" "rotate-$file"
	        rm -f "$file"
	      done
	    fi

	    ##  Combine the individual pages into one file and compress.

	    tiffcp -c "$compress" *.tiff output

	    content_type="image/tiff"
	    filename="`date \"+$file_name.tiff\"`" ;;

	esac ;;

    esac

    ##  If we created a file in the previous step, get it to the user now.

    case "$function" in

      SAVE)

	##  Create a "scanner" directory in user's home if one doesn't exist.

	if [ ! -d "$homedir" ]
	then
	  mkdir -p "$homedir"
	  chown $name "$homedir"
	fi

	##  If gzip compression requested, use gzip to compress while copying
	##  to user's directoy, otherwise just plain copy. Make sure user ends
	##  up owning the file themselves.

	if [ -z "${output##*_gz}" ]
	then
	  gzip -c -$compress_gzip output >"$homedir/$filename.gz"
	  chown $name "$homedir/$filename.gz"

	elif [ -z "${output##_zip}" ]
	then
	  mv output "$filename"
	  zip -j \
	    -$compress_zip "$homedir/$filename.zip" "$filename"
	  chown $name "$homedir/$filename.gz"

	else
	  cp output "$homedir/$filename"
	  chown $name "$homedir/$filename"
	fi ;;

      EMAIL|FAX)

	##  If we are compressing, override the mime type with the mime type
	##  for the compression method and add the appropriate extra filename
	##  extension on.

	if [ -z "${output##*_gz}" ]
	then
	  content_type="application/x-gzip"
	  filename="$filename.gz"

	elif [ -z "${output##*_zip}" ]
	then
	  content_type="application/zip"
	  filename="$filename.zip"
	fi

	##  Insert the filename into the subject and body if needed.

	substitute "$filename" '$subject' '$body'

	##  Compose a mime-encoded email with the scan as an attachment.

	( echo "To: <$recipient>"
	  echo "Subject: $subject"
	  echo "Mime-Version: 1.0"
	  echo "Content-Type: multipart/mixed; boundary=\"-\""
	  echo
	  echo "---"
	  echo "Content-Type: text/plain; format=flowed"
	  echo "Content-Transfer-Encoding: quoted-printable"
	  echo
	  echo "$body"
	  echo
	  echo "---"
	  echo "Content-Type: $content_type; name=\"$filename\""
	  echo "Content-Transfer-Encoding: base64"
	  echo "Content-Disposition: inline; filename=\"$filename\""
	  echo

	  ##  Base64 encode the file into the stream. If any sort of extra
	  ##  compression was selected, do it now. In FreeBSD and at least
	  ##  some Linux, the -m flag on uuencode does base 64 encoding

	  if [ -z "${output##*_gz}" ]
	  then
	    gzip -c -$compress_gzip < output |
	    uuencode -m output | sed -e '1d' -e '$d'
	
	  elif [ -z "${output##*_zip}" ]
	  then
	    mv output "${filename%.zip}"
	    zip -j -$compress_zip - "${filename%.zip}" |
	    uuencode -m output | sed -e '1d' -e '$d'
	
	  else
	    uuencode -m output output | sed -e '1d' -e '$d'
	  fi

	  echo
	  echo "-----"

	) | sendmail -t -f "<$sender>" ;;

    esac

    ##  All done, so remove the staging directory for this document

    cd ..
    rm -rf "$directory"

  done
)
