Start
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 7 Oct 2004 15:04:35 +0000 (15:04 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 7 Oct 2004 15:04:35 +0000 (15:04 +0000)
30 files changed:
doc/doc-scripts/BuildFAQ [new file with mode: 0755]
doc/doc-scripts/BuildHTML [new file with mode: 0755]
doc/doc-scripts/BuildInfo [new file with mode: 0755]
doc/doc-scripts/BuildPDF [new file with mode: 0755]
doc/doc-scripts/DoConts [new file with mode: 0755]
doc/doc-scripts/DoIndex [new file with mode: 0755]
doc/doc-scripts/JoinPS [new file with mode: 0755]
doc/doc-scripts/Makefile [new file with mode: 0644]
doc/doc-scripts/f2h [new file with mode: 0755]
doc/doc-scripts/f2txt [new file with mode: 0755]
doc/doc-scripts/faqchk [new file with mode: 0755]
doc/doc-scripts/fc2k [new file with mode: 0755]
doc/doc-scripts/g2h [new file with mode: 0755]
doc/doc-scripts/g2man [new file with mode: 0755]
doc/doc-scripts/g2t [new file with mode: 0755]
doc/doc-src/FAQ.src [new file with mode: 0644]
doc/doc-src/filter.src [new file with mode: 0644]
doc/doc-src/markup.sg [new file with mode: 0644]
doc/doc-src/spec.src [new file with mode: 0644]
doc/doc-txt/ChangeLog [new file with mode: 0644]
doc/doc-txt/ChangeLog.0 [new file with mode: 0644]
doc/doc-txt/Exim3.upgrade [new file with mode: 0644]
doc/doc-txt/Exim4.upgrade [new file with mode: 0644]
doc/doc-txt/NewStuff [new file with mode: 0644]
doc/doc-txt/OptionLists.txt [new file with mode: 0644]
doc/doc-txt/README [new file with mode: 0644]
doc/doc-txt/README.SIEVE [new file with mode: 0644]
doc/doc-txt/dbm.discuss.txt [new file with mode: 0644]
doc/doc-txt/pcrepattern.txt [new file with mode: 0644]
doc/doc-txt/pcretest.txt [new file with mode: 0644]

diff --git a/doc/doc-scripts/BuildFAQ b/doc/doc-scripts/BuildFAQ
new file mode 100755 (executable)
index 0000000..9712eff
--- /dev/null
@@ -0,0 +1,59 @@
+#! /bin/sh
+# $Cambridge: exim/doc/doc-scripts/BuildFAQ,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Script to build the Exim FAQ in text and HTML formats.
+
+/bin/rm -f FAQ.txt* html/FAQ* FAQ-html/* FAQ-html.tar.*
+/bin/rm -f config.samples.tar.gz config.samples.tar.bz2
+
+# The FAQchk Perl script checks for the numbers being in order and for the
+# right number of blank lines at various places.
+
+faqchk FAQ.src
+if [ $? != 0 ]; then exit 1; fi
+
+# HTML version
+
+f2h FAQ.src html
+echo "html/FAQ*.html made"
+
+fc2k
+echo "html/FAQ-KWIC*.html made"
+
+cp html/FAQ* html/*.txt FAQ-html
+echo "copied to FAQ-html"
+
+tar cf FAQ-html.tar FAQ-html
+gzip FAQ-html.tar
+echo "FAQ-html.tar.gz made"
+
+tar cf FAQ-html.tar FAQ-html
+bzip2 -9 FAQ-html.tar
+echo "FAQ-html.tar.gz2 made"
+
+# ASCII version
+
+f2txt FAQ.src FAQ.txt
+echo "FAQ.txt made"
+
+cp FAQ.txt FAQ.txt-t
+gzip -v --best FAQ.txt-t
+mv FAQ.txt-t.gz FAQ.txt.gz
+echo "FAQ.txt.gz made"
+
+cp FAQ.txt FAQ.txt-t
+bzip2 -v -9 FAQ.txt-t
+mv FAQ.txt-t.bz2 FAQ.txt.bz2
+echo "FAQ.txt.bz2 made"
+
+# Configuration samples
+
+tar cf config.samples.tar config.samples
+gzip config.samples.tar
+echo "config.samples.tar.gz made"
+
+tar cf config.samples.tar config.samples
+bzip2 -9 config.samples.tar
+echo "config.samples.tar.bz2 made"
+
+# End
diff --git a/doc/doc-scripts/BuildHTML b/doc/doc-scripts/BuildHTML
new file mode 100755 (executable)
index 0000000..9d60034
--- /dev/null
@@ -0,0 +1,12 @@
+#! /bin/sh
+# $Cambridge: exim/doc/doc-scripts/BuildHTML,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+if [ $# != 1 ]; then
+  echo "*** Usage: BuildHTML <Exim version>"
+  exit 1
+fi
+
+g2h -split chapter filter.src "Exim Filter Specification"
+g2h -split chapter spec.src "Exim $1 Specification"
+
+# End
diff --git a/doc/doc-scripts/BuildInfo b/doc/doc-scripts/BuildInfo
new file mode 100755 (executable)
index 0000000..9f8d105
--- /dev/null
@@ -0,0 +1,32 @@
+#! /bin/sh
+# $Cambridge: exim/doc/doc-scripts/BuildInfo,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+if [ "$1" = "filter" ]; then
+g2t -filter filter.src >filter.texinfo
+if [ $? != 0 ]; then exit 1; fi
+cd info
+makeinfo filter.texinfo
+if [ $? != 0 ]; then exit 1; fi
+echo ""
+echo info filter.info
+echo ""
+info -f ./filter.info
+exit
+fi
+
+if [ "$1" = "" ]; then
+g2t spec.src >spec.texinfo
+if [ $? != 0 ]; then exit 1; fi
+cd info
+makeinfo spec.texinfo
+if [ $? != 0 ]; then exit 1; fi
+echo ""
+echo info spec.info
+echo ""
+info -f ./spec.info
+exit
+fi
+
+echo "***Usage: null or filter argument required"
+
+####
diff --git a/doc/doc-scripts/BuildPDF b/doc/doc-scripts/BuildPDF
new file mode 100755 (executable)
index 0000000..c8a2bc2
--- /dev/null
@@ -0,0 +1,10 @@
+#! /bin/sh
+# $Cambridge: exim/doc/doc-scripts/BuildPDF,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+echo "PDFing the spec"
+ps2pdf spec.ps spec.pdf
+
+echo "PDFing the filter spec"
+ps2pdf filter.ps filter.pdf
+
+# End
diff --git a/doc/doc-scripts/DoConts b/doc/doc-scripts/DoConts
new file mode 100755 (executable)
index 0000000..410c3ba
--- /dev/null
@@ -0,0 +1,71 @@
+#! /usr/bin/perl -w
+# $Cambridge: exim/doc/doc-scripts/DoConts,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+$style = (@ARGV > 0)? $ARGV[0] : "a4ps";
+
+open(IN, "z-rawindex")   || die "Can't open z-rawindex\n";
+open(OUT, ">z-contents") || die "Can't open z-contents\n";
+
+print OUT <<'EOF';
+.if ~~sys.fancy
+.linelength ~~sys.linelength + 0.2in
+.pagedepth ~~sys.pagedepth - 0.2in
+.linedepth 12.24
+.fi
+.include "markup.sg"
+.set chapter -1
+.set p 0
+.format p roman
+.tabset 2em 2em
+.
+.foot
+.set p ~~sys.pagenumber
+$c [~~p]
+.endfoot
+.
+.chapter Contents
+.disable filling
+.justify left
+EOF
+
+while(<IN>)
+  {
+  if (/\$e/)
+    {
+    s/\$e\s*$//;                      # "see also" lines have no line number
+    s/--\s*\d+$//;                    # remove "extra" number for index page 
+
+    s/\n$//;                          # trailing newline
+    
+    if (!/^\$/)
+      {
+      print OUT ".blank\n";
+      print OUT ".if ~~sys.leftonpage < 2*~~sys.linedepth\n";
+      print OUT ".newpage\n";
+      print OUT ".fi\n";  
+      print OUT "\$shead\{$_\}\n"; 
+      print OUT ".blank\n";
+      }  
+    else
+      { 
+      print OUT "$_\n";
+      } 
+    }  
+  } 
+
+close(IN);
+close(OUT);
+
+system("sgcal z-contents -to zc-gcode -style $style -index /dev/null");
+if ($style eq "a4ps")
+  {
+  system("sgtops zc-gcode -to zc-ps");
+  print "PostScript in zc-ps\n";
+  }
+else
+  {
+  system("mv -f zc-gcode zc-txt");
+  print "Text in zc-txt\n";       
+  }
+
+# End
diff --git a/doc/doc-scripts/DoIndex b/doc/doc-scripts/DoIndex
new file mode 100755 (executable)
index 0000000..1caddbd
--- /dev/null
@@ -0,0 +1,430 @@
+#! /usr/bin/perl -w
+# $Cambridge: exim/doc/doc-scripts/DoIndex,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Script for producing the Index for the Exim manual from the output of the
+# SGCAL run. This is copied from the script for the Exim book.
+
+
+##############################################################################
+# Patterns for matching things to be removed from the sort keys
+
+# This was copied from the Exim book processor, but we have now found a
+# better way of doing this. Leave the code until I am quite sure...
+
+# $pat[0]  = qr/ \(\\\*see also\*\\[^)]+\)/;
+# $pat[1]  = qr/(?<!@)\/\//;                     # //
+# $pat[2]  = qr/(?<!@)\/\\/;                     # /\
+# $pat[3]  = qr/(?<!@)\\\//;                     # \/
+# $pat[4]  = qr/(?<!@) \\                        # non-@ \, followed by one of
+#                             (?:
+#                             [\.\/] |           # dot or slash
+#                             !- |               # !-
+#                             !\+ |              # !+
+#                             !\. |              # !.
+#                             "\+ |              # "+
+#                             \([.\/]? |         # ( and optional . or slash
+#                             [[\$\\%?!-"] |     # [ $ \ % ! " or -
+#                             \*{1,2} |          # * or **
+#                             \^{1,2}\/?         # ^ or ^^ and optional slash
+#                             )/x;
+# $pat[5]  = qr/(?: []\$\\%)?!"] |               # ] $ \ % ) ? " or ! )
+#                   \*{1,2}  |                   # * or **            ) optional
+#                   \^{1,2})?                    # ^ or ^^            )
+#                   \\/x;                        # then \
+# $pat[6]  = qr/(?<!@)::/;
+# $pat[7]  = qr/\sR[FS]\b/;
+# $pat[8]  = qr/``/;
+# $pat[9]  = qr/''/;
+# $pat[10] = qr/`/;
+# $pat[11] = qr/'/;
+# $pat[12] = qr/,/;
+# $pat[13] = qr/\(e?s\)/;
+
+
+# Other patterns
+
+# $keysplit = qr/^(.*?)(\|\|.*?)?\s(R[AZ])?\s?(\d+)$/;
+
+$keysplit = qr/^(.*?)(\@\|\@\|.*?)?\s(R[AZ])?\s?(\d+)$/;
+
+
+# The sort function
+
+sub cf {
+my($x,$y) = ($a,$b);
+
+############old#############
+#foreach $pattern (@pat)    # Remove strings by pattern
+#  {
+#  $x =~ s/$pattern//g;
+#  $y =~ s/$pattern//g; 
+#  } 
+##########################
+
+
+# Turn || into @|@|
+
+$x =~ s/\|\|/@|@|/g;
+$y =~ s/\|\|/@|@|/g;
+
+# Remove all special characters, except those preceded by @
+
+$x =~ s/(?<!\@)[^\w\@\s]//g;
+$y =~ s/(?<!\@)[^\w\@\s]//g;
+
+# Remove the escaping @s
+
+#$x =~ s/\@(.)/$1/g;
+#$y =~ s/\@(.)/$1/g;
+
+
+  
+################old ########################
+#$x =~ s/:(\w+):/$1/g;      # :fail: etc => fail
+#$y =~ s/:(\w+):/$1/g;
+
+#$x =~ s/^\@[^a-z]+/\@/i;   # Make keys starting with @ 
+#$y =~ s/^\@[^a-z]+/\@/i;   # sort on @ followed by the first letter
+##############################################3
+
+
+$x =~ s/\@_/\x7f/g;        # Make underscore sort late (option names)
+$y =~ s/\@_/\x7f/g; 
+   
+# Split up to sort on individual parts
+
+my($xp,$xs,$xr,$xn) = $x =~ /$keysplit/;
+my($yp,$ys,$yr,$yn) = $y =~ /$keysplit/;
+
+$xr = "" if !defined $xr;
+$yr = "" if !defined $yr;
+
+$xs = "" if !defined $xs;
+$ys = "" if !defined $ys;
+
+if ($show_keys)
+  {
+  print "a=$a\n  x=$x\n  xp=$xp\n  xs=$xs\n  xr=$xr\n  xn=$xn\n";
+  print "b=$b\n  y=$y\n  yp=$yp\n  ys=$ys\n  yr=$yr\n  yn=$yn\n";
+  } 
+
+my ($c) = "\L$xp" cmp "\L$yp";        # Caseless, primary text only
+$c = $xp cmp $yp if $c == 0;          # Caseful, primary text only
+$c = "\L$xs" cmp "\L$ys" if $c == 0;  # Caseless, secondary text only
+$c = $xs cmp $ys if $c == 0;          # Caseful, secondary text only
+$c = $xn <=> $yn if $c == 0;          # Compare the numbers
+$c = $xr cmp $yr if $c == 0;          # Sort RA before RZ
+return $c;
+}
+
+
+
+##############################################################################
+# Function for getting the next line from the @lines vector, using the global
+# index $1. If the next pair of lines specifies a range of pages, combine them.
+# That's why $linenumber has to be global - so we can increment it. If there's
+# a range error, return "".
+
+sub getnextentry {
+my($line) = $lines[$linenumber];
+my($aa,$zz,$tline,$nextline,$tnextline);
+
+if ($line =~ / RA (\d+)/)
+  {
+  $aa = $1; 
+  $nextline = $lines[++$linenumber];
+  if ($nextline =~ / RZ (\d+)/) 
+    { 
+    $zz = $1;
+    }
+  else    
+    {
+    print STDERR "** Bad range data (1)\n";
+    print STDERR "   $line\n";
+    print STDERR "   $nextline\n";
+    return "";
+    }  
+    
+  $tline = $line;
+  $tnextline = $nextline; 
+   
+  $tline =~ s/ RA \d+//; 
+  $tnextline =~ s/ RZ \d+//;
+  
+  if ($tline ne $tnextline)
+    {
+    print STDERR "** Bad range data (2)\n";
+    print STDERR "   $line\n";
+    print STDERR "   $nextline\n";
+    return "";
+    }  
+
+  $line = ($aa eq $zz)? "$tline $aa" : "$tline $aa--$zz";
+  }   
+  
+elsif ($line =~ / RZ (\d+)/)
+  {
+  print STDERR "** Bad range data (RZ without RA)\n";
+  print STDERR "   $line\n";
+  return "";
+  } 
+
+return $line
+}
+
+
+
+
+##############################################################################
+# Function for outputting a line, checking for the current primary
+# and indenting a bit for secondaries. We also need a newpar
+# before each item, because the main indent is set to a largish indent
+# for long reference lists, but the parindent is set to counter this.
+# This is where we handle the break between letters. We know that any non-
+# alphamerics at the start of lines are markup, except for @. A reference
+# value of 99999 is for the "see also" lines. Suppress it.
+
+sub outline {
+my($text,$ref) = ($_[0],$_[1]);
+my ($letter) = $text =~ /^[^A-Za-z0-9\@]*(.)/;
+
+return if $text =~ /^\s*$/;
+
+if ($ref eq "99999")    # dummy for see also
+  {
+  $ref = "" 
+  } 
+else
+  {
+  $ref = "#$ref";       # prepend space
+  }    
+
+if ($letter =~ /\d/) { $letter = "0"; } else { $letter = "\U$letter"; } 
+
+print OUT ".newpar\n";
+
+if ($letter ne $currentletter && $letter ge "A")
+  {
+  print OUT ".newletter\n"; 
+  $currentletter = $letter;   
+  } 
+    
+$text =~ s/\@'/\$'/g;   # Turns @' into $' so that it prints a non-curly quote
+
+if ($text =~ /^(.+)\|\|(.*)$/)
+  {
+  my($primary,$secondary) = ($1,$2);
+  if ($primary ne $lastprimary)
+    {
+    print OUT ".primary $primary\n"; 
+    $lastprimary = $primary;
+    }
+  $primary =~ s/"/""/g;
+  $secondary =~ s/"/""/g;   
+   
+  my($contprim) = $primary;
+  $contprim =~ s/ \(\\\*see also\*\\[^)]+\)//; 
+
+  print OUT ".secondary \"$primary\" \"$secondary$ref\" \"$contprim\"\n";
+  } 
+
+# Not a two-part item; insert @ if the first char is a dot
+
+else
+  {
+  print OUT "@" if $text =~ /^\./; 
+  print OUT "$text$ref\n";
+  $lastprimary = $text; 
+  } 
+}
+
+
+
+
+
+##############################################################################
+# The main script
+
+$save_sorted = 0;
+$test_index = 0;
+$show_keys = 0;
+
+while (@ARGV > 0)
+  {
+  my($arg) = shift @ARGV;
+  if    ($arg eq "-k") { $show_keys = 1; }
+  elsif ($arg eq "-s") { $save_sorted = 1; }
+  elsif ($arg eq "-t") { $test_index = $save_sorted = 1; }
+  else  { die "Unknown option $arg\n"; }  
+  } 
+
+if ($test_index)
+  {
+  open(IN, "z-testindex") || die "Can't open z-testindex\n";
+  }
+else
+  {   
+  open(IN, "z-rawindex") || die "Can't open z-rawindex\n";
+  }
+
+open(OUT, ">z-index")  || die "Can't open z-index\n";
+
+# Extract index lines ($e lines are contents). Until we hit the first
+# $e line, we are dealing with "see also" index lines, for which we want
+# to turn the line number into 99999.
+
+$#lines = -1;
+$prestuff = 1;
+
+while (<IN>)
+  {
+  s/\n$//; 
+  if (/\$e/)
+    {
+    $prestuff = 0; 
+    }
+  else
+    {
+    s/(\D)$/$1 99999/ if $prestuff;          # No number in "see also"
+    push(@lines, $_);
+    } 
+  $index_pagenumber = $1 if /^Index\$e(\d+)/;
+  } 
+close(IN);
+
+# Sort, ignoring markup
+
+print STDERR "Sorting ...\n";
+@lines = sort cf @lines;
+
+# Keep a copy of the sorted data, for reference
+
+if ($save_sorted)
+  {
+  open(X, ">z-indexsorted") || die "Can't open z-indexsorted\n";
+  foreach $line (@lines)
+   {
+   print X "$line\n";
+   }
+  close(X);     
+  } 
+
+# Heading for the index file
+
+print OUT <<"EOF";
+.library "a4ps"
+.linelength ~~sys.linelength + 16.0
+
+.include "markup.sg"
+
+.indent 3em
+.parspace 0
+.parindent -3em
+.justify left
+.
+.foot
+\$c [~~sys.pagenumber]
+.endfoot
+.
+.cancelflag #
+.flag # "\$S*1"
+.set INDEX true
+.
+.macro primary "text"
+.if ~~sys.leftonpage < 2ld
+.newcolumn
+.fi
+~~1
+.newpar
+.endm
+.
+.macro secondary "prim" "sec" "contprim"
+.if ~~sys.leftonpage < 1ld
+.newcolumn
+.newpar
+~~3 \$it\{(continued)\}
+.newpar
+.fi
+##~~2
+.endm
+.
+.macro newletter
+.if ~~sys.leftonpage < 4ld
+.newcolumn
+.else
+.space 1ld
+.fi
+.newpar
+.endm
+.
+.set chapter -1
+.page $index_pagenumber
+.chapter Index
+.columns 2
+.newpar
+.
+EOF
+
+# Process the lines and output the result.
+# Note that $linenumber is global, and is changed by getnextentry() for
+# pairs of lines that represent ranges.
+
+$lastprimary = "";
+$lastref = "";
+$currenttext = $currentref = "";
+$currentletter = "";
+$badrange = 0;
+
+print STDERR "Processing ...\n";
+
+for ($linenumber = 0; $linenumber < @lines; $linenumber++) 
+  { 
+  $line = &getnextentry();
+  
+  if ($line eq "")   # Bad range data - but carry on to get all of it
+    {
+    $badrange = 1;
+    next;
+    }   
+    
+  # Split off the text and reference
+  
+  ($text,$ref) = $line =~ /^(.*)\s+([\d-]+)$/;
+
+  # If same as current text, just add the new reference, unless its a duplicate
+
+  if ($text eq $currenttext)
+    {
+    if ($ref ne $lastref)
+      {  
+      $currentref .= ", $ref"; 
+      $lastref = $ref;
+      }  
+    next;
+    }
+    
+  # Not the same as the current text. Output the current text, then 
+  # set up a new current. 
+    
+  &outline($currenttext, $currentref);
+   
+  $currenttext = $text; 
+  $currentref = $lastref = $ref; 
+  }
+  
+# Output the final line and close the file
+
+&outline($currenttext, $currentref);
+close(OUT);
+
+die "** Aborted\n" if $badrange;
+
+# Format the index
+
+system("sgcal z-index -to zi-gcode -index /dev/null");
+system("sgtops zi-gcode -to zi-ps");
+print "PostScript in zi-ps\n";
+
+# End
diff --git a/doc/doc-scripts/JoinPS b/doc/doc-scripts/JoinPS
new file mode 100755 (executable)
index 0000000..92ba59a
--- /dev/null
@@ -0,0 +1,130 @@
+#!/usr/bin/perl
+# $Cambridge: exim/doc/doc-scripts/JoinPS,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Make the basic PostScript file for the Exim spec from the gcode file, then
+# join it together with the contents and the index, to make a single
+# PostScript file, suitable for double-sided printing.
+
+sub blank_page {
+my($title) = shift @_;
+printf(OUT "%%%%Page: %s %d\nxpage\n\n", $title, $pagenumber++);
+}
+
+
+@roman = ("i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x",
+          "xi", "xii", "xiii", "xiv", "xv", "xvi", "xvii", "xviii", "xix");
+
+$pagenumber = 1;
+
+system("sgtops z-gcode -to z-ps") && die "sgtops run failed\n";
+
+open(SPEC, "z-ps") || die "Can't open z-ps\n";
+open(CONTS, "zc-ps") || die "Can't open zc-ps\n";
+open(INDEX, "zi-ps") || die "Can't open zi-ps\n";
+open(OUT, ">spec.ps") || die "Can't open spec.ps\n";
+
+# Copy spec headings etc.
+
+while (<SPEC>)
+  {
+  last if (/^%%Page:/) ;
+  print OUT;
+  }
+
+# Copy the first two pages - the title page, and its blank verso
+
+for ($i = 1; $i < 3; $i++)
+  {
+  printf(OUT "%%%%Page: title%s %d\n", ($i == 1)? "" : "-verso", $pagenumber++);
+  while (<SPEC>)
+    {
+    last if (/^%%Page:/) ;
+    print OUT;
+    }
+  }   
+
+# Skip the contents heading
+
+while (<CONTS>)
+  {
+  last if (/^%%Page:/) ;
+  }
+
+# Output the contents pages - fudge the roman numerals as we know there
+# won't be a vast number of them.
+
+$subpagenumber = 0;
+while (!eof CONTS)
+  {
+  printf(OUT "%%%%Page: %s %d\n", $roman[$subpagenumber++], $pagenumber++);
+  while (<CONTS>)
+    {
+    next if (/^%%Pages:/);
+    next if (/^%%Trailer/);
+    last if (/^%%Page:/) ;
+    print OUT;
+    }
+  }
+printf(OUT "\n");
+
+# If contents was an odd number of pages, insert a blank page
+
+&blank_page("contents-pad") if ($pagenumber & 1) == 0;
+
+# Copy the rest of the main file
+
+$subpagenumber = 1;
+
+while (!eof SPEC)
+  {
+  printf(OUT "%%%%Page: %d %d\n", $subpagenumber++, $pagenumber++);
+  while (<SPEC>)
+    {
+    next if (/^%%Pages:/);
+    next if (/^%%Trailer/);
+    last if (/^%%Page:/) ;
+    print OUT;
+    }
+  }
+printf(OUT "\n");
+
+# If contents was an odd number of pages, insert a blank page
+
+&blank_page("body-pad") if ($pagenumber & 1) == 0;
+
+# Skip the index heading
+
+while (<INDEX>)
+  {
+  last if (/^%%Page:/) ;
+  }
+
+# Copy the index pages
+
+$subpagenumber = 1;
+
+while (!eof INDEX)
+  {
+  printf(OUT "%%%%Page: I%d %d\n", $subpagenumber++, $pagenumber++);
+  while (<INDEX>)
+    {
+    next if (/^%%Pages:/);
+    next if (/^%%Trailer/);
+    last if (/^%%Page:/) ;
+    print OUT;
+    }
+  }
+
+# Add final comments
+
+printf(OUT "%%%%Trailer\n");
+printf(OUT "%%%%Pages: %d\n", $pagenumber-1);
+
+# That's it
+
+close(SPEC);
+close(CONTS);
+close(INDEX);
+close(OUT);
+
+# End
diff --git a/doc/doc-scripts/Makefile b/doc/doc-scripts/Makefile
new file mode 100644 (file)
index 0000000..79b1f04
--- /dev/null
@@ -0,0 +1,31 @@
+# $Cambridge: exim/doc/doc-scripts/Makefile,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Makefile for Exim documentation
+
+ps:;        sgcal-fr spec.src -v -to z-gcode -index z-rawindex
+           sgtops z-gcode -to z-ps
+
+txt:;       g2man       
+           sgcal-fr spec.src -style online -v -to z-txt -index z-rawindex
+
+contents:;  @DoConts
+
+index:;     @DoIndex
+
+# The file z-rawindex is included by the filter source to create a TOC.
+# First empty it, then do a dummy format to create it, then do a second
+# pass. This works because the TOC occupies no more than the rest of the
+# first page.
+
+filterps:;  /bin/rm -rf z-rawindex
+           touch z-rawindex
+           sgcal-fr filter.src -v -to z-gcode -index z-rawindex
+           sgcal-fr filter.src -v -to z-gcode -index /dev/null
+           sgtops z-gcode -to filter.ps
+
+filtertxt:; /bin/rm -rf z-rawindex
+           touch z-rawindex
+           sgcal-fr filter.src -style online -v -to filter.txt -index z-rawindex
+           sgcal-fr filter.src -style online -v -to filter.txt -index /dev/null
+
+clean:;     /bin/rm -f z*
diff --git a/doc/doc-scripts/f2h b/doc/doc-scripts/f2h
new file mode 100755 (executable)
index 0000000..426e46e
--- /dev/null
@@ -0,0 +1,338 @@
+#!/usr/bin/perl
+# $Cambridge: exim/doc/doc-scripts/f2h,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Script to turn the Exim FAQ into HTML.
+
+use integer;
+
+# Function to do text conversions that apply to both displays and non displays
+
+sub process_both {
+my($s) = $_[0];
+$s =~ s/</&#60;/g;                                 # Deal with < and >
+$s =~ s/>/&#62;/g;
+return $s;
+}
+
+
+# Function to do text conversions to display paragraphs
+
+sub process_display {
+my($s) = $_[0];
+$s =~ s/^==>/   /;
+my($indent) = $s =~ /^(\s+)/;
+my($remove) = " " x (length($indent) - 3);
+$s =~ s/^$remove//mg;
+$s = &process_both($s);
+return $s;
+}
+
+
+# Function to do text conversions to paragraphs not in displays.
+
+sub process_non_display {
+my($s) = &process_both($_[0]);
+
+$s =~ s/@\\/@@backslash@@/g;                       # @\ temporarily hidden
+
+$s =~ s/\\#/&nbsp;/g;                              # \# is a hard space
+
+$s =~ s/\\\*\*([^*]*)\*\*\\/<b>$1<\/b>/g;          # \**...**\   => bold
+$s =~ s/\\\*([^*]*)\*\\/<i>$1<\/i>/g;              # \*.....*\   => italic
+$s =~ s/\\"([^"]*)"\\/<tt>$1<\/tt>/g;              # \"....."\   => fixed pitch
+$s =~ s/\\\$([^\$]*)\$\\/<i>\$$1<\/i>/g;           # \$.....$\   => $italic
+$s =~ s/\\\\([^\\]*)\\\\/<small>$1<\/small>/g;     # \\.....\\   => small
+$s =~ s/\\\(([^)]*)\)\\/<i>$1<\/i>/g;              # \(.....)\   => italic
+$s =~ s/\\-([^\\]*)-\\/<b>-$1<\/b>/g;              # \-.....-\   => -bold
+$s =~ s/\\\[([^]]*)\]\\/&\#60;<i>$1<\/i>&\#62;/gx; # \[.....]\   => <italic>
+$s =~ s/\\\?(.*?)\?\\/<a href="$1">$1<\/a>/g;      # \?.....?\   => URL
+$s =~ s/\\\^\^([^^]*)\^\^\\/<i>$1<\/i>/g;          # \^^...^^\   => italic
+$s =~ s/\\\^([^^]*)\^\\/<i>$1<\/i>/g;              # \^.....^\   => italic
+$s =~ s/\\%([^%]*)%\\/<b>$1<\/b>/g;                # \%.....%\   => bold
+$s =~ s/\\\/([^\/]*)\/\\/<i>$1<\/i>/g;             # \/...../\   => italic
+$s =~ s/\\([^\\]+)\\/<tt>$1<\/tt>/g;               # \.......\   => fixed pitch
+
+$s =~ s"//([^/\"]*)//"<i>$1</i>"g;                 # //.....//   => italic
+$s =~ s/::([^:]*)::/<i>$1:<\/i>/g;                 # ::.....::   => italic:
+
+$s =~ s/``(.*?)''/&#147;$1&#148;/g;                # ``.....''   => quoted text
+
+$s =~ s/\s*\[\[br\]\]\s*/<br>/g;                   # [[br]]      => <br>
+
+$s =~ s/@@backslash@@/\\/g;                        # Put back single backslash
+
+$s =~ s/^(\s*\(\d\)\s)/$1&nbsp;/;                  # Extra space after (1), etc.
+
+# Cross references within paragraphs
+
+$s =~ s/Q(\d{4})(?!:)/<a href="$xref{$1}">$&<\/a>/xg;
+
+# References to configuration samples
+
+$s =~ s/\b([CFLS]\d\d\d)\b/<a href="$1.txt">$1<\/a>/g;
+
+# Remove white space preceding a newline in the middle of paragraphs,
+# to keep the file smaller (and for human reading when debugging).
+
+$s =~ s/^\s+//mg;
+
+return $s;
+}
+
+
+# Main program
+
+# We want to read the file paragraph by paragraph; Perl only does this if the
+# separating lines are truly blank. Having been caught by lines containing
+# whitespace before, do a detrailing pass first.
+
+open(IN, "$ARGV[0]") || die "can't open $ARGV[0] (preliminary)\n";
+open(OUT, ">$ARGV[0]-$$") || die "can't open $ARGV[0]-$$\n";
+while (<IN>)
+  {
+  s/[ \t]+$//;
+  print OUT;
+  }
+close(IN);
+close(OUT);
+rename("$ARGV[0]-$$", "$ARGV[0]") ||
+  die "can't rename $ARGV[0]-$$ as $ARGV[0]\n";
+
+# The second argument is the name of a directory into which to put multiple
+# HTML files. We start off with FAQ.html.
+
+$hdir = $ARGV[1];
+open(OUT, ">$hdir/FAQ.html") || die "can't open $hdir/FAQ.html\n";
+
+# Initial output
+
+print OUT <<End ;
+<html>
+<head>
+<title>The Exim FAQ</title>
+</head>
+<body bgcolor="#F8F8F8" text="#00005A" link="#0066FF" alink="#0066FF" vlink="#000099">
+<h1>The Exim FAQ</h1>
+End
+
+$/ = "";
+
+# First pass to read the titles and questions and create the table of
+# contents. We save it up in a vector so that it can be written after the
+# introductory paragraphs.
+
+open(IN, "$ARGV[0]") || die "can't open $ARGV[0] (first time)\n";
+
+$toc = 0;
+$sec = -1;
+$inul = 0;
+
+while ($_ = <IN>)
+  {
+  $count = s/\n/\n/g - 1;          # Number of lines in paragraph
+
+  if ($count == 1 && /^\d+\./)     # Look for headings
+    {
+    chomp;
+    push @toc, "</ul>" if $inul;
+    $inul = 0;
+    push @toc, "<br>\n\n" if $sec++ >= 0;
+    push @toc, "<a name=\"TOC$toc\" href=\"FAQ_$sec.html\">$_</a>\n";
+    $toc++;
+
+    ($number,$title) = /^(\d+)\.\s+(.*)$/;
+    if ($title ne "UUCP" && $title ne "IRIX" && $title ne "BSDI" &&
+        $title ne "HP-UX")
+      {
+      ($initial,$rest) = $title =~ /^(.)(.*)$/;
+      $title = "$initial\L$rest";
+      $title =~ s/isdn/ISDN/;
+      $title =~ s/\btls\b/TLS/;
+      $title =~ s/\bssl\b/SSL/;
+      $title =~ s/ os x/ OS X/; 
+      }
+    push @seclist, "<a href=\"FAQ_$sec.html\">$number. $title</a>";
+
+    next;
+    }
+
+  if (/^(Q\d{4})/)                 # Q initial paragraph
+    {
+    if (!$inul)
+      {
+      push @toc, "<ul>\n";
+      $inul = 1;
+      }
+    $num = $1;
+    $rest = $';
+    $xref{substr($num,1)} = "FAQ_$sec.html#TOC$toc";
+    $rest =~ s/^: /:&nbsp;&nbsp;/;
+    $rest = &process_non_display($rest);
+    push @toc, "<li><a name=\"TOC$toc\" href=\"FAQ_$sec.html#TOC$toc\">$num</a>$rest<br><br></li>\n";
+    $toc++;
+    next;
+    }
+  }
+
+push @toc, "</ul>\n" if $inul;
+close(IN);
+
+
+# This is the main processing pass. We have to detect the different kinds of
+# "paragraph" and do appropriate things.
+
+open(IN, "$ARGV[0]") || die "can't open $ARGV[0] (second time)\n";
+
+# Skip the title line
+
+$_ = <IN>;
+
+# Handle the rest of the file
+
+$toc = 0;
+$maxsec = $sec;
+$sec = -1;
+
+while ($_ = <IN>)
+  {
+  $count = s/\n/\n/g - 1;          # Number of lines in paragraph
+  chomp;                           # Trailing newlines
+
+  if (/^The FAQ is divided into/)
+    {
+    my($count) = scalar(@seclist);
+    my($cols) = ($count + 1)/2;
+
+    print OUT "<hr><a name=\"TOC\"><h1>Index</h1></a>\n";
+    print OUT "<p>A <i>Keyword-in-context</i> <a href=\"FAQ-KWIC_A.html\">index</a> " .
+              "to the questions is available. This is usually the " .
+              "quickest way to find information in the FAQ.</p>\n";
+
+    print OUT "<h1>Contents</h1>\n";
+    print OUT "<p>The FAQ is divided into the following sections:<br><br></p>\n";
+
+    print OUT "<table>\n";
+
+    for ($i = 0; $i < $cols; $i++)
+      {
+      print OUT "<tr>\n";
+      print OUT "  <td>", "&nbsp;" x 4, "</td>\n";
+      print OUT "  <td>&nbsp;$seclist[$i]</td>\n";
+      print OUT "  <td>", "&nbsp;" x8, "$seclist[$cols+$i]</td>\n"
+        if $cols+$i < $count;
+      print OUT "</tr>\n";
+      }
+    print OUT "</table><br><p>\n<hr><br>\n";
+    print OUT "<h1>List of questions</h1>\n";
+
+    $_ = <IN>;                     # Skip section list
+    next;
+    }
+
+  if ($count == 1 && /^\d+\./)     # Look for headings
+    {
+    if (@toc != 0)                 # TOC when hit first heading
+      {
+      while (@toc != 0) { print OUT shift @toc; }
+      }
+
+    # Output links at the bottom of this page
+
+    print OUT "<hr><br>\n";
+    print OUT "<a href=\"FAQ.html#TOC\">Contents</a>&nbsp;&nbsp;\n";
+    if ($sec > 0)
+      {
+      printf OUT ("<a href=\"FAQ_%d.html\">Previous</a>&nbsp;&nbsp;\n", $sec-1);
+      }
+    printf OUT ("<a href=\"FAQ_%d.html\">Next</a>\n", $sec+1);
+
+    # New section goes in new file
+
+    print OUT "</body>\n</html>\n";
+    close OUT;
+
+    $sec++;
+    open(OUT, ">$hdir/FAQ_$sec.html") ||
+      die "Can't open $hdir/FAQ_$sec.html\n";
+
+    print OUT "<html>\n<head>\n" .
+      "<title>The Exim FAQ Section $sec</title>\n" .
+      "</head>\n" .
+      "<body bgcolor=\"#F8F8F8\" text=\"#00005A\" " .
+      "link=\"#FF6600\" alink=\"#FF9933\" vlink=\"#990000\">\n";
+
+    printf OUT "<h1>The Exim FAQ</h1>\n";
+
+    print OUT "<a href=\"FAQ.html#TOC\">Contents</a>&nbsp;&nbsp;\n";
+    if ($sec > 0)
+      {
+      printf OUT ("<a href=\"FAQ_%d.html\">Previous</a>&nbsp;&nbsp;\n", $sec-1);
+      }
+    if ($sec < $maxsec)
+      {
+      printf OUT ("<a href=\"FAQ_%d.html\">Next</a>\n", $sec+1);
+      }
+
+    print OUT "<hr><br>\n";
+
+    print OUT "<h2><a href=\"FAQ.html#TOC$toc\">$_</a></h2>\n";
+    $toc++;
+    next;
+    }
+
+  s/^([QA]\d{4}|[CFLS]\d{3}): /$1:&nbsp;&nbsp;/;
+
+  if (/^(Q\d{4}:)/)               # Q initial paragraph
+    {
+    print OUT "<p>\n<a name=\"TOC$toc\" href=\"FAQ.html#TOC$toc\">$1</a>";
+    $_ = &process_non_display($');
+    print OUT "$_\n</p>\n";
+    $toc++;
+    next;
+    }
+
+  if (/^A\d{4}:/)                 # A initial paragraph
+    {
+    $_ = &process_non_display($_);
+    s/^(A\d{4}:)/<font color="#00BB00">$1<\/font>/;
+    print OUT "<p>\n$_\n</p>\n";
+    next;
+    }
+
+  # If a paragraph begins ==> it is a display which must remain verbatin
+  # and not be reformatted. The flag gets turned into spaces.
+
+  if ($_ =~ /^==>/)
+    {
+    $_ = &process_display($_);
+    chomp;
+    print OUT "<pre>\n$_</pre>\n";
+    }
+
+  # Non-display paragraph; massage the final line & my sig.
+
+  elsif (/^\*\*\* End of Exim FAQ \*\*\*/)
+    {
+    }
+
+  else
+    {
+    $_ = &process_non_display($_);
+    if (/^Philip Hazel/)
+      {
+      s/\n/<br>\n/g;
+      s/<br>$/<hr><br>/;
+      }
+    print OUT "<p>\n$_\n</p>\n";
+    }
+  }
+
+close(IN);
+
+print OUT "<hr><br>\n";
+print OUT "<a href=\"FAQ.html#TOC\">Contents</a>&nbsp;&nbsp;\n";
+printf OUT ("<a href=\"FAQ_%d.html\">Previous</a>\n", $sec-1);
+
+print OUT "</body>\n</html>\n";
+close(OUT);
+End
diff --git a/doc/doc-scripts/f2txt b/doc/doc-scripts/f2txt
new file mode 100755 (executable)
index 0000000..ff5d703
--- /dev/null
@@ -0,0 +1,107 @@
+#!/usr/bin/perl
+# $Cambridge: exim/doc/doc-scripts/f2txt,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Script to turn the Exim FAQ into plain ASCII.
+
+use integer;
+
+
+# Function to do text conversions to display paragraphs
+
+sub process_display {
+my($s) = $_[0];
+$s =~ s/^==>/   /;
+return $s;
+}
+
+
+# Function to do text conversions to paragraphs not in displays.
+
+sub process_non_display {
+my($s) = $_[0];
+
+$s =~ s/@\\/@@backslash@@/g;                 # @\ temporarily hidden
+
+$s =~ s/\\#/ /g;                             # \# is a hard space
+
+$s =~ s/\\\*\*([^*]*)\*\*\\/$1/g;            # \**...**\   => text
+$s =~ s/\\\*([^*]*)\*\\/"$1"/g;              # \*.....*\   => "text"
+$s =~ s/\\"([^"]*)"\\/"$1"/g;                # \"....."\   => "text"
+$s =~ s/\\\$([^\$]*)\$\\/\$$1/g;             # \$.....$\   => $text
+$s =~ s/\\\\([^\\]*)\\\\/$1/g;               # \\.....\\   => text
+$s =~ s/\\\(([^)]*)\)\\/$1/g;                # \(.....)\   => text
+$s =~ s/\\-([^-]*)-\\/-$1/g;                 # \-.....-\   => -text
+$s =~ s/\\\[([^]]*)\]\\/<$1>/gx;             # \[.....]\   => <text>
+$s =~ s/\\\?(.*?)\?\\/$1/g;                  # \?.....?\   => text
+$s =~ s/\\\^\^([^^]*)\^\^\\/$1/g;            # \^^...^^\   => text
+$s =~ s/\\\^([^^]*)\^\\/$1/g;                # \^.....^\   => text
+$s =~ s/\\%([^%]*)%\\/"$1"/g;                # \%.....%\   => "text"
+$s =~ s/\\\/([^\/]*)\/\\/$1/g;               # \/...../\   => text
+$s =~ s/\\([^\\]+)\\/"$1"/g;                 # \.......\   => "text"
+
+$s =~ s"//([^/\"]*)//"$1"g;                  # //.....//   => text
+$s =~ s/::([^:]*)::/$1:/g;                   # ::.....::   => text:
+
+$s =~ s/``(.*?)''/"$1"/g;                    # ``.....''   => "text"
+
+$s =~ s/\s*\[\[br\]\]\s*\n/\n/g;             # Remove [[br]]
+
+$s =~ s/@@backslash@@/\\/g;                  # Put back single backslash
+
+return $s;
+}
+
+
+# Main program
+
+# We want to read the file paragraph by paragraph; Perl only does this if the
+# separating lines are truly blank. Having been caught by lines containing
+# whitespace before, do a detrailing pass first.
+
+open(IN, "$ARGV[0]") || die "can't open $ARGV[0] (preliminary)\n";
+open(OUT, ">$ARGV[0]-$$") || die "can't open $ARGV[0]-$$\n";
+while (<IN>)
+  {
+  s/[ \t]+$//;
+  print OUT;
+  }
+close(IN);
+close(OUT);
+rename("$ARGV[0]-$$", "$ARGV[0]") ||
+  die "can't rename $ARGV[0]-$$ as $ARGV[0]\n";
+
+# The second argument is the name of the output file.
+
+open(IN, "$ARGV[0]") || die "can't open $ARGV[0] (for real)\n";
+open(OUT, ">$ARGV[1]") || die "can't open $ARGV[1]\n";
+
+$/ = "";
+
+while ($_ = <IN>)
+  {
+  # Comment lines start with ##
+
+  next if /^\#\#/;
+
+  # If a paragraph begins ==> it is a display which must remain verbatin
+  # and not be reformatted. The flag gets turned into spaces.
+
+  if ($_ =~ /^==>/)
+    {
+    $_ = &process_display($_);
+    }
+
+  # Non-display paragraph
+
+  else
+    {
+    $_ = &process_non_display($_);
+    }
+
+  print OUT;
+  }
+
+close(IN);
+close(OUT);
+
+End
diff --git a/doc/doc-scripts/faqchk b/doc/doc-scripts/faqchk
new file mode 100755 (executable)
index 0000000..939d0b2
--- /dev/null
@@ -0,0 +1,102 @@
+#!/usr/bin/perl -w
+# $Cambridge: exim/doc/doc-scripts/faqchk,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Script to check the FAQ source and make sure I have all the numbers
+# in the right order without duplication. Also check the numbers of blank
+# lines. It gives up on any error (other than bad blank line counts).
+
+sub oops {
+print "\nLine $line: $_[0]\n";
+print;
+exit 1;
+}
+
+sub poops {
+print "\nLine $line: $_[0]\n";
+print;
+$precede_fail = 1;
+}
+
+
+$line = 0;
+$section = -1;
+$expect_answer = 0;
+$precede_fail = 0;
+
+while (<>)
+  {
+  $line++;
+  if (/^\s*$/)
+    {
+    $blankcount++;
+    next;
+    }
+  $preceded = $blankcount;
+  $blankcount = 0;
+
+  if (/^(\d+)\./)
+    {
+    &poops("$preceded empty lines precede (3 expected)") if $preceded != 3;
+    &oops(sprint("Answer %02d%02d is missing\n", $section, $question))
+      if $expect_answer;
+    $section = $1;
+    $question = ($section == 20)? 0 : 1;
+    $expected = 1;
+    if ($section == 99)
+      {
+      $c = 1;
+      $f = 1;
+      }
+    next;
+    }
+
+  if ($section != 99)
+    {
+    if (/^Q(\d\d)(\d\d):/)
+      {
+      &poops("$preceded empty lines precede ($expected expected)")
+        if $preceded != $expected;
+      $expected = 2;
+
+      &oops("Answer expected") if $expect_answer;
+      &oops("Q$1$2 is in the wrong section") if ($1 != $section);
+      &oops("Q$1$2 is out of order") if $2 != $question;
+
+      $expect_answer = 1;
+      next;
+      }
+
+    if (/^A(\d\d)(\d\d):/)
+      {
+      &poops("$preceded empty lines precede (1 expected)") if $preceded != 1;
+
+      &oops("Question expected") if !$expect_answer;
+      &oops("A$1$2 is in the wrong section") if $1 != $section;
+      &oops("A$1$2 is out of order") if $2 != $question++;
+
+      $expect_answer = 0;
+      next;
+      }
+    }
+
+  else
+    {
+    if (/^C(\d\d\d):/)
+      {
+      &oops("C$1 is mixed up in the Fs") if $f != 1;
+      # Some Cxxx configs are omitted (not translated from Exim 3) so can
+      # only check increasing number.
+      &oops("C$1 is out of order") if $1 < $c;
+      $c = $1;
+      }
+    elsif (/^F(\d\d\d):/)
+      {
+      &oops("F$1 is out of order") if $1 != $f++;
+      next;
+      }
+    }
+  }
+
+exit 1 if $precede_fail;
+
+# End
diff --git a/doc/doc-scripts/fc2k b/doc/doc-scripts/fc2k
new file mode 100755 (executable)
index 0000000..9363929
--- /dev/null
@@ -0,0 +1,344 @@
+#! /usr/bin/perl -w
+# $Cambridge: exim/doc/doc-scripts/fc2k,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Script to read the HTML table of contents for the Exim FAQ and create an
+# HTML KWIC index out of it.
+
+
+########################################################################
+# List of words to ignore - kept alphabetically for reference, but they
+# don't have to be in order.
+
+$ignore_list = "
+
+a ability able about address addresses addressed affect affected
+after against all allow allowed allows already also although always am an and
+and/or any anybody anyone anything anywhere are aren't arrange arrive as at
+
+back bad based basically be because been behave behaviour being best between
+bob both bug build builds built busy but by
+
+call called calls can can't cannot causes causing central certain code comes
+coming command commands complain complaining complains configure configured
+conjunction contact contain contains contained correct correctly could
+currently customer
+
+day days defined deliver delivers delivered delivery deliveries did do does
+doesn't doing don't down during
+
+e-mail e-mails each easy else email emails entirely entries entry especially
+etc even ever every example exim exim's experiencing
+
+far few file files find fine fly following for form found from fully
+
+get gets getting given gives giving go goes going got
+
+handle handles handled handling happen happens has have haven't having helpful
+him host hosts how however
+
+i i'd i'm i've if in indeed instead into is issue issues isn't it it's its
+
+jim just
+
+keep keeps know knows
+
+like line lines look looked looking lot
+
+machine machines machine's mail mails main make me mean means message messages
+might more must my myself
+
+near need neither no nor not now
+
+occur of off often ok on one only or other our out over own
+
+part parts particular per place possibility possible present problem problems
+put puts
+
+quite
+
+raised rather really reason rid right round run runs
+
+same say saying see seeing seem seems seen sees set setting she should so some
+somehow something sometimes stand state statement still strange such supposed
+system systems
+
+take takes than that the their them then there these they things think this
+those to try though to/for told too tried tries trying
+
+under until up use uses used using usually
+
+valid value values via
+
+want wanted wanting was way we we've well what what's when where whereabouts
+whenever whether which while who whose why will with within without wish won't
+wondered work worked working works would wrong
+
+xxx
+
+yet yyy
+
+";
+########################################################################
+
+
+# The regular expression fragment that defines the separator between words
+
+$wordgap = "(?:[]().?,;:\"']|(?><[^>]*>))*(?:\\s+|\$)(?:[[(\"'`]|(?><[^>]*>))*";
+
+
+########################################################################
+# Function to add to a length to accommodate HTML stuff
+
+sub setlen{
+my($len, $s) = @_;
+
+$len += length($1) while ($s =~ /(<\/?[a-z]+>)/ig);
+$len += 1 while ($s =~ /&#\d+;/g);
+
+return $len;
+}
+
+
+########################################################################
+# Function to write out the list of initials with references
+
+sub write_initials {
+my($this_initial) = "$_[0]";
+
+print OUT "<p>\n&nbsp;&nbsp;";
+
+foreach $initial (sort keys %initials)
+  {
+  if ($initial eq $this_initial)
+    {
+    print OUT "&nbsp;&nbsp;&nbsp;<font size=7 color=\"#FF0A0A\"><b>$initial</b></font>&nbsp;";
+    }
+  else
+    {
+    print OUT "<a href=\"FAQ-KWIC_$initial.html\">&nbsp;&nbsp;$initial</a>";
+    }
+  }
+
+print OUT "&nbsp;"x4 . "<a href=\"FAQ.html#TOC\">FAQ Contents</a>\n</p>\n";
+}
+
+
+
+########################################################################
+# The main program. We can pick out the contents lines because they lie
+# between <li> and </li> in the file, sometimes on more than one physical
+# line.
+
+# Turn the list of ignorable words into a hash for quick lookup. Add the
+# empty word to the list.
+
+@words = split /\s+/, $ignore_list;
+foreach $word (@words) { $ignore{$word} = 1; }
+$ignore{""} = 1;
+
+
+# Open the file and do the job
+
+open(IN, "html/FAQ.html") || die "Can't open html/FAQ.html\n";
+
+while (<IN>)
+  {
+  next unless /^<li>/;
+  $_ .= <IN> while !/<\/li>$/;
+  chomp;
+  s/\n\s*/ /g;
+
+  # Extract the operative text into $text, with the beginning in $pre.
+
+  my($pre,$text,$post) = /^<li>(.*<\/a>:(?:&nbsp;)*)(.*)<br><br><\/li>$/;
+
+  # Now split into words. As well as punctuation, there may be HTML thingies
+  # between words. Absorb them into the separators.
+
+  my(@words) = split /$wordgap/, $text;
+
+  # Lower case all the words, and remove those that we don't want.
+  # Then keep a list of all the used initials.
+
+  REMOVE_IGNORE:
+  for ($i = 0; $i < scalar @words; $i++)
+    {
+    my($word) = $words[$i] = "\L$words[$i]\E";
+
+    # Remove certain forms of word and those on the ignore list
+
+    if (defined $ignore{$word} ||  # word on ignore list
+        $word =~ /^-+$/        ||  # word consists entirely of hyphens
+        $word =~ /^-[^a-z]/    ||  # follows leading hyphen with non-letter
+        $word =~ /^[^a-z-]/    ||  # starts with a non-letter or hyphen
+        $word =~ /[@^.]/           # contains @ or ^ or .
+       )
+      {
+      splice(@words, $i, 1);
+      redo REMOVE_IGNORE if $i < scalar @words;
+      }
+      
+    # Otherwise, build up a list of initials
+     
+    else
+      {
+      my($inword) = $word; 
+      $inword =~ s/^-//; 
+      $initial = substr($inword, 0, 1);
+      $initials{"\U$initial\E"} = 1;
+      }
+    }
+
+  # Create the lines for the KWIC index, and store them in associative
+  # arrays, with the keyword as the key. That will get them sorted
+  # automatically.
+
+  while (scalar @words > 0)
+    {
+    my($word) = shift @words;
+    my($pretext, $casedword, $posttext) =
+      $text =~ /(.*?)(?<![a-z])(\Q$word\E)(?![a-z])(.*)/i;
+      
+    # Remove a leading hyphen from $word so that it sorts according to
+    # the leading letter. What is actually output is $casedword, which
+    # retains the hyphen.
+    
+    $word =~ s/^-//;   
+
+    my($prelen) = length $pretext;
+    my($postlen) = length $posttext;
+
+    # We want to chop excessively long entries on either side. We can't set
+    # a fixed length because of the HTML control data. Call a function to
+    # add the given length to allow for HTML stuff. This is crude, but it
+    # does roughtly the right thing.
+
+    my($leftlen) = &setlen(70, $pretext);
+    my($rightlen) = &setlen(70, $posttext);
+
+    if ($prelen > $leftlen)
+      {
+      my($cutoff) = $leftlen;
+      $cutoff++
+        while ($cutoff < $prelen && substr($pretext, -$cutoff, 1) ne " ");
+      $pretext = "... " . substr($pretext, -$cutoff);
+      }
+
+    if ($postlen > $rightlen)
+      {
+      my($cutoff) = $rightlen;
+      $cutoff++
+        while ($cutoff < $postlen && substr($posttext, $cutoff, 1) ne " ");
+      $posttext = substr($posttext, 0, $cutoff) . "...";
+      }
+
+    # If the pre text has a font-ending not preceded by a font beginning
+    # (i.e. we've chopped the beginning off), we must insert a beginning.
+
+    while ($pretext =~ /^(.*?)<\/(small|tt|b|i)>/ && $1 !~ /<$2>/)
+      {
+      $pretext = "<$2>" . $pretext;
+      }
+
+    # If the pre text ends in a special font, we have to terminate that,
+    # and reset it at the start of the post text.
+
+    my($poststart) = "";
+
+    while ($pretext =~ /<(small|tt|b|i)>(?!.*?<\/\1>)/)
+      {
+      $pretext .= "</$1>";
+      $poststart .= "<$1>";
+      }
+
+    # If the post text changes font but doesn't close it, we must add
+    # the closure.
+
+    while ($posttext =~ /<(small|tt|b|i)>(?!.*?<\/\1>)/)
+      {
+      $posttext .= "</$1>";
+      }
+
+    # Remove any unnecessary changes in either of them
+
+    $pretext  =~ s/<(small|tt|b|i)>\s*<\/\1>//g;
+    $posttext =~ s/<(small|tt|b|i)>\s*<\/\1>//g;
+
+    # Save the texts in associative arrays. Add the question number to
+    # the end of the word to make the key.
+
+    $pre =~ /(Q\d\d\d\d)/;
+    my($key) = "$word-$1";
+
+    $tableft{$key}  = $pre . $pretext;
+    $tabright{$key} = $poststart .
+      "<font color=\"#FF0A0A\">$casedword</font>" . $posttext;
+    }
+  }
+
+close(IN);
+
+# Now write out the files. Each letter in the index goes in a different file
+
+$current_initial = "";
+
+foreach $key (sort keys %tableft)
+  {
+  my($initial) = $key =~ /^(.)/;
+  $initial = "\U$initial\E";
+
+  if ($initial ne $current_initial)
+    {
+    if ($current_initial ne "")
+      {
+      print OUT "</table>\n";
+      &write_initials($current_initial);
+      print OUT "</body>\n</html>\n";
+      close OUT;
+      }
+
+    open (OUT, ">html/FAQ-KWIC_$initial.html") ||
+      die "Can't open html/FAQ-KWIC_$initial.html\n";
+    print OUT
+      "<html>\n" .
+      "<head>\n" .
+      "<title>Exim FAQ: KWIC index section $initial</title>\n" .
+      "</head>\n" .
+      "<body bgcolor=\"#F8F8F8\" text=\"#00005A\" link=\"#0066FF\" alink=\"#0066FF\" vlink=\"#000099\">\n" .
+      "<h1>Exim FAQ: Keyword-in-context index</h1>\n";
+
+    write_initials($initial);
+
+    if ($initial eq "A")
+      {
+      print OUT <<End ;
+<p>
+This <i>Keyword-in-context</i> index for the Exim FAQ is generated
+automatically from the FAQ source. Browsers may not display the data very
+prettily, but it is hoped that it may provide a useful aid for finding things
+in the FAQ.
+</p>
+End
+      }
+
+    print OUT "<table border>\n";
+    $current_initial = $initial;
+    }
+
+  print OUT "<tr>\n";
+  print OUT "<td align=\"right\">$tableft{$key}</td>\n";
+  print OUT "<td align=\"left\">$tabright{$key}</td>\n";
+  print OUT "</tr>\n";
+  }
+
+# Close the final file
+
+if ($current_initial ne "")
+  {
+  print OUT "</table>\n";
+  &write_initials($current_initial);
+  print OUT "</body>\n</html>\n";
+  close OUT;
+  }
+
+# End
diff --git a/doc/doc-scripts/g2h b/doc/doc-scripts/g2h
new file mode 100755 (executable)
index 0000000..e940e66
--- /dev/null
@@ -0,0 +1,1451 @@
+#! /usr/bin/perl -w
+# $Cambridge: exim/doc/doc-scripts/g2h,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# This is a script that turns the SGCAL source of Exim's documentation into
+# HTML. It can be used for both the filter document and the main Exim
+# specification. The syntax is
+#
+#    g2h [-split no|section|chapter] <source file> <title>
+#
+# Previously, -split section was used for the filter document, and -split
+# chapter for the main specification. However, the filter document has gained
+# some chapters, so they are both split by chapter now. Only one -split can be
+# specified.
+#
+# A number of assumptions about the style of the input markup are made.
+#
+# The HTML is written into the directory html/ using the source file base
+# name as its base.
+
+# Written by Philip Hazel
+# Starting 21-Dec-2001
+# Last modified 26-Nov-2003
+
+#############################################################################
+
+
+
+##################################################
+#             Open an output file                #
+##################################################
+
+sub openout {
+open (OUT, ">$_[0]") || die "Can't open $_[0]\n";
+
+# Boilerplate
+
+print OUT "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n";
+
+print OUT "<html>\n<head>\n<title>$doctitle" .
+  (($thischapter > 0)? " chapter $thischapter" : "") .
+  (($thissection > 0)? " section $thissection" : "") .
+  "</title>\n</head>\n" .
+  "<body bgcolor=\"#F8F8F8\" text=\"#00005A\" " .
+  "link=\"#FF6600\" alink=\"#FF9933\" vlink=\"#990000\">\n";
+
+# Forward/backward links when chapter splitting
+
+if ($chapsplit)
+  {
+  print OUT "<font size=2>\n";
+  printf OUT ("<a href=\"${file_base}_%s.html\">Previous</a>&nbsp;&nbsp;\n",
+    $thischapter - 1) if $thischapter > 1;
+  printf OUT ("<a href=\"${file_base}_%s.html\">Next</a>&nbsp;&nbsp;\n",
+    $thischapter + 1) if $thischapter < $maxchapter;
+  print OUT "<a href=\"${file_base}_toc.html\">Contents</a>\n";
+  print OUT "&nbsp;" x 6, "($doctitle)\n</font><hr>\n";
+  }
+
+# Forward/backward links when section splitting
+
+elsif ($sectsplit)
+  {
+  print OUT "<font size=2>\n";
+  printf OUT ("<a href=\"${file_base}_%s.html\">Previous</a>&nbsp;&nbsp;\n",
+    $thissection - 1) if $thissection > 1;
+  printf OUT ("<a href=\"${file_base}_%s.html\">Next</a>&nbsp;&nbsp;\n",
+    $thissection + 1) if $thissection < $maxsection;
+  print OUT "<a href=\"${file_base}_toc.html\">Contents</a>\n";
+  print OUT "&nbsp;" x 6, "($doctitle)\n</font><hr>\n";
+  }
+
+# Save the final component of the current file name (for TOC creation)
+
+$_[0] =~ /^(?:.*)\/([^\/]+)$/;
+$current_file = $1;
+}
+
+
+
+##################################################
+#              Close an output file              #
+##################################################
+
+# The first argument is one of:
+#
+# "CHAP"   a chapter is ending
+# "SECT"   a section is ending
+# ""       the whole thing is ending
+#
+# In the first two cases $thischapter and $thissection contain the new chapter
+# and section numbers, respectively. In the third case, we can deduce what is
+# ending from the flags. The variables contain the current values.
+
+sub closeout {
+my($s) = $_[0];
+
+print OUT "<hr>\n" if !$lastwasrule;
+&setpar(0);
+
+if ($s eq "CHAP")
+  {
+  print OUT "<font size=2>\n";
+  printf OUT ("<a href=\"${file_base}_%s.html\">Previous</a>&nbsp;&nbsp;",
+    $thischapter - 2) if ($thischapter > 2);
+  print OUT "<a href=\"${file_base}_$thischapter.html\">Next</a>&nbsp;&nbsp;";
+  print OUT "<a href=\"${file_base}_toc.html\">Contents</a>\n";
+  print OUT "&nbsp;" x 6, "($doctitle)\n</font>\n";
+  }
+
+elsif ($s eq "SECT")
+  {
+  print OUT "<font size=2>\n";
+  printf OUT ("<a href=\"${file_base}_%s.html\">Previous</a>&nbsp;&nbsp;",
+    $thissection - 2) if ($thissection > 2);
+  print OUT "<a href=\"${file_base}_$thissection.html\">Next</a>&nbsp;&nbsp;";
+  print OUT "<a href=\"${file_base}_toc.html\">Contents</a>\n";
+  print OUT "&nbsp;" x 6, "($doctitle)\n</font>\n";
+  }
+
+else
+  {
+  if ($chapsplit)
+    {
+    print OUT "<font size=2>\n";
+    printf OUT ("<a href=\"${file_base}_%s.html\">Previous</a>&nbsp;&nbsp;",
+      $thischapter - 1) if ($thischapter > 1);
+    print OUT "<a href=\"${file_base}_toc.html\">Contents</a>\n";
+    print OUT "&nbsp;" x 6, "($doctitle)\n</font>\n";
+    }
+  elsif ($sectsplit)
+    {
+    print OUT "<font size=2>\n";
+    printf OUT ("<a href=\"${file_base}_%s.html\">Previous</a>&nbsp;&nbsp;",
+      $thissection - 1) if ($thissection > 1);
+    print OUT "<a href=\"${file_base}_toc.html\">Contents</a>\n";
+    print OUT "&nbsp;" x 6, "($doctitle)\n</font>\n";
+    }
+  }
+
+print OUT "</body>\n</html>\n";
+close(OUT);
+}
+
+
+
+##################################################
+#            Handle an index line                #
+##################################################
+
+# This function returns an empty string so that it can be called as part
+# of an s operator when handling index items within paragraphs. The two
+# arguments are:
+#
+#   the text to index, already converted to HTML
+#   1 for the concept index, 0 for the options index
+
+sub handle_index {
+my($text) = $_[0];
+my($hash) = $_[1]? \%cindex : \%oindex;
+my ($key,$ref);
+
+# Up the index count, and compute the reference to the file and the
+# label within it.
+
+$index_count++;
+$ref = $chapsplit?
+      "${file_base}_$thischapter.html#IX$index_count"
+  : $sectsplit?
+      "${file_base}_$thissection.html#IX$index_count"
+  :
+      "#IX$index_count";
+
+# Create the index key, which consists of the text with all the HTML
+# coding and any leading quotation marks removed. Turn the primary/secondary
+# splitting string "||" into ":".
+
+$text =~ s/\|\|/:/g;
+
+$key = "$text";
+$key =~ s/<[^>]+>//g;
+$key =~ s/&#(\d+);/chr($1)/eg;
+$key =~ s/^`+//;
+
+# Turn all spaces in the text into &nbsp; so that they don't ever split.
+# However, there may be spaces in the HTML that already exists in the
+# text, so we have to avoid changing spaces inside <>.
+
+$text =~ s/ (?=[^<>]*(?:<|$))/&nbsp;/g;
+
+# If this is the first encounter with this index key, we create a
+# straightforward reference.
+
+if (!defined $$hash{$key})
+  {
+  $$hash{$key} = "<a href=\"$ref\">$text</a>";
+  }
+
+# For the second and subsequent encounters, add "[2]" etc. to the
+# index text. We find out the number by counting occurrences of "<a"
+# in the existing string.
+
+else
+  {
+  my($number) = 1;
+  $number++ while $$hash{$key} =~ /<a/g;
+  $$hash{$key} .= " &nbsp;<a href=\"$ref\">[$number]</a>";
+  }
+
+# Place the name in the current output
+
+print OUT "<a name=\"IX$index_count\"></a>\n";
+return "";
+}
+
+
+
+##################################################
+#             Handle emphasis bars               #
+##################################################
+
+# Set colour green for text marked with "emphasis bars", keeping
+# track in case the matching isn't perfect.
+
+sub setinem {
+if ($_[0])
+  {
+  return "" if $inem;
+  $inem = 1;
+  return "<font color=green>\n";
+  }
+else
+  {
+  return "" if !$inem;
+  $inem = 0;
+  return "</font>\n";
+  }
+}
+
+
+
+##################################################
+#          Convert marked-up text                #
+##################################################
+
+# This function converts text from SGCAL markup to HTML markup, with a couple
+# of exceptions:
+#
+# 1. We don't touch $t because that is handled by the .display code.
+#
+# 2. The text may contain embedded .index, .em, and .nem directives. We
+#    handle .em and .nem, but leave .index because it must be done during
+#    paragraph outputting.
+#
+# In a non-"rm" display, we turn $rm{ into cancelling of <tt>. Otherwise
+# it is ignored - in practice it is only used in that special case.
+#
+# The order in which things are done in this function is highly sensitive!
+
+sub handle_text {
+my($s) = $_[0];
+my($rmspecial) = $_[1];
+
+# Escape all & characters (they aren't involved in markup) but for the moment
+# use &+ instead of &# so that we can handle # characters in the text.
+
+$s =~ s/&/&+038;/g;
+
+# Turn SGCAL literals into HTML literals that don't look like SGCAL
+# markup, so won't be touched by what follows. Again, use + instead of #.
+
+$s =~ s/@@/&+064;/g;
+$s =~ s/@([^@])/"&+".sprintf("%0.3d",ord($1)).";"/eg;
+
+# Now turn any #s that are markup into spaces, and convert the previously
+# created literals to the correct form.
+
+$s =~ s/#/&nbsp;/g;
+$s =~ s/&\+(\d+);/&#$1;/g;
+
+# Some simple markup that doesn't involve argument text.
+
+$s =~ s/\$~//g;                   # turn $~  into nothing
+$s =~ s/__/_/g;                   # turn __  into _
+$s =~ s/--(?=$|\s|\d)/&#150;/mg;  # turn --  into endash in text or number range
+$s =~ s/\(c\)/&copy;/g;           # turn (c) into copyright symbol
+
+# Use double quotes
+
+# $s =~ s/`([^']+)'/``$1''/g;
+
+$s =~ s/`([^']+)'/&#147;$1&#148;/g;
+
+# This is a fudge for some specific usages of $<; can't just do a global
+# is it occurs in things like "$<variable name>" as well.
+
+$s =~ s/(\d)\$<-/$1-/g;  # turn 0$<- into 0-
+$s =~ s/\$<//g;          # other $< is ignored
+
+# Turn <<...>> into equivalent SGCAL markup that doesn't involve the use of
+# < and >, and then escape the remaining < and > characters in the text.
+
+$s =~ s/<<([^>]*?)>>/<\$it{$1}>/g;   # turn <<xxx>> into <$it{xxx}>
+$s =~ s/</&#060;/g;
+$s =~ s/>/&#062;/g;
+
+# Other markup...
+
+$s =~ s/\$sm\{//g;              # turn $sm{     into nothing
+$s =~ s/\$smc\{//g;             # turn $smc{    into nothing
+$s =~ s/\$smi\{//g;             # turn $smi{    into nothing
+
+$s =~ s/\$tt\{([^\}]*?)\}/<tt>$1<\/tt>/g;    # turn $tt{xxx} into <tt>xxx</tt>
+$s =~ s/\$it\{([^\}]*?)\}/<em>$1<\/em>/g;    # turn $it{xxx} into <em>xxx</em>
+$s =~ s/\$bf\{([^\}]*?)\}/<b>$1<\/b>/g;      # turn $bf{xxx} into <b>xxx</b>
+
+$s =~ s/\$cb\{([^\}]*?)\}/<tt><b>$1<\/b><\/tt>/g; # turn $cb{xxx} into
+                                                  #   <tt><b>xxx</b></tt>
+
+$s =~ s/\\\\([^\\]*?)\\\\/<font size=-1>$1<\/font>/g; # turn \\xxx\\ into
+                                                      #  small font
+$s =~ s/\\\?([^?]*?)\?\\/<a href="$1">$1<\/a>/g;      # turn \?URL?\ into URL
+
+$s =~ s/\\\(([^)]*?)\)\\/<i>$1<\/i>/g;       # turn \(xxx)\ into <i>xxx</i>
+$s =~ s/\\\"([^\"]*?)\"\\/<tt>$1<\/tt>/g;    # turn \"xxx"\ into <tt>xxx</tt>
+
+
+$s =~ s/\\\$([^\$]*?)\$\\/<tt>\$$1<\/tt>/g;  # turn \$xxx$\   into <tt>$xxx</tt>
+$s =~ s/\\\-([^\\]*?)\-\\/<i>-$1<\/i>/g;     # turn \-xxx-\   into -italic
+$s =~ s/\\\*\*([^*]*?)\*\*\\/<b>$1<\/b>/g;   # turn \**xxx**\ into <b>xxx</b>
+$s =~ s/\\\*([^*]*?)\*\\/<i>$1<\/i>/g;       # turn \*xxx*\   into italic
+$s =~ s/\\%([^*]*?)%\\/<b>$1<\/b>/g;         # turn \%xxx%\   into bold
+$s =~ s/\\([^\\]*?)\\/<tt>$1<\/tt>/g;        # turn \xxx\     into <tt>xxx</tt>
+$s =~ s/::([^\$]*?)::/<i>$1:<\/i>/g;         # turn ::xxx::   into italic:
+$s =~ s/\$\*\$/\*/g;                         # turn $*$       into *
+
+# Handle $rm{...}
+
+if ($rmspecial)
+  {
+  $s =~ s/\$rm\{([^\}]*?)\}/<\/tt>$1<tt>/g;  # turn $rm{xxx} into </tt>xxx<tt>
+  }
+else
+  {
+  $s =~ s/\$rm\{([^\}]*?)\}/$1/g;            # turn $rm{xxx} into xxx
+  }
+
+# There is one case where the terminating } of an escape sequence is
+# in another paragraph - this follows $sm{ - it can be fixed by
+# removing any stray } in a paragraph that contains no { chars.
+
+$s =~ s/\}//g if !/\{/;
+
+# Remove any null flags ($$)
+
+$s =~ s/\$\$//g;
+
+# If the paragraph starts with $c\b, remove it.
+
+$s =~ s/^\$c\b//;
+
+# If the paragraph starts with $e\b, indent it slightly.
+
+$s =~ s/^\$e\b/&nbsp;&nbsp;/;
+
+# Handle .em, and .nem directives that occur within the paragraph
+
+$s =~ s/\.em\s*\n/&setinem(1)/eg;
+$s =~ s/\.nem\s*\n/&setinem(0)/eg;
+
+# Explicitly included HTML
+
+$s =~ s/\[\(([^)]+)\)\]/<$1>/g;  # turn [(...)] into <...>
+
+# Finally, do the substitutions and return the modified text.
+
+$s =~ s/~~(\w+)/$var_value{$1}/eg;
+
+return $s;
+}
+
+
+
+##################################################
+#            Start/end a paragraph               #
+##################################################
+
+# We want to leave paragraphs unterminated until we know that a horizontal
+# rule does not follow, to avoid getting space inserted before the rule,
+# which doesn't look good. So we have this function to help control things.
+# If the argument is 1 we are starting a new paragraph; if it is 0 we want
+# to force the ending of any incomplete paragraph.
+
+sub setpar {
+if ($inpar)
+  {
+  print OUT "</p>\n";
+  $inpar = 0;
+  }
+if ($_[0])
+  {
+  print OUT "<p>\n";
+  $inpar = 1;
+  }
+}
+
+
+
+##################################################
+#            Handle a "paragraph"                #
+##################################################
+
+# Read a paragraph of text, which may contain many lines and may contain
+# .index, .em, and .nem directives within it. We may also encounter
+# ".if ~~html" within paragraphs. Process those directives,
+# convert the markup, and output the rest as an HTML paragraph.
+
+
+sub handle_paragraph{
+my($par) = $_;
+my($htmlcond) = 0;
+while(<IN>)
+  {
+  if (/^\.if\s+~~html\b/)
+    {
+    $htmlcond = 1;
+    $par =~ s/\s+$//;         # lose unwanted whitespace and newlines
+    next;
+    }
+  elsif ($htmlcond && /^\.else\b/)
+    {
+    while (<IN>) { last if /^\.fi\b/; }
+    $htmlcond = 0;
+    next;
+    }
+  elsif ($htmlcond && /^\.fi\b/)
+    {
+    $htmlcond = 0;
+    next;
+    }
+
+  last if /^\s*$/ || (/^\./ && !/^\.index\b/ && !/^\.em\b/ && !/^\.nem\b/);
+  $par .= $_;
+  }
+$par = &handle_text($par, 0);
+
+# We can't handle .index until this point, when we do it just before
+# outputting the paragraph.
+
+if ($par !~ /^\s*$/)
+  {
+  &setpar(1);
+  $par =~ s/\.index\s+([^\n]+)\n/&handle_index($1, 1)/eg;
+  print OUT "$par";
+  }
+}
+
+
+
+##################################################
+#         Handle a non-paragraph directive       #
+##################################################
+
+# The directives .index, .em, and .nem can also appear within paragraphs,
+# and are then handled within the handle_paragraph() code.
+
+sub handle_directive{
+my($new_lastwasitem) = 0;
+
+$lastwasrule = 0;
+
+if (/^\.r?set\b/ || /^\.(?:\s|$)/) {}      # ignore .(r)set and comments
+
+elsif (/^\.justify\b/) {}                  # and .justify
+
+elsif (/^\.newline\b/) { print OUT "<br>\n"; }
+
+elsif (/^\.blank\b/ || /^\.space\b/) { print OUT "<br>\n"; }
+
+elsif (/^\.rule\b/)  { &setpar(0); print OUT "<hr>\n"; $lastwasrule = 1; }
+
+elsif (/^\.index\s+(.*)/) { &handle_index(&handle_text($1), 1); }
+
+# Emphasis is handled by colour
+
+elsif (/^\.em\b/)
+  {
+  &setpar(0);
+  print OUT "<font color=green>" if ! $inem;
+  $inem = 1;
+  }
+
+elsif (/^\.nem\b/)
+  {
+  &setpar(0);
+  print OUT "</font>" if $inem;
+  $inem = 0;
+  }
+
+# Ignore tab setting stuff - we use tables instead.
+
+elsif (/^\.tabs(?:et)?\b/) {}
+
+# .tempindent is used only to align some of the expansion stuff nicely;
+# just ignore it. It is used in conjunction with .push/.pop.
+
+elsif (/^\.(tempindent|push|pop)\b/) {}
+
+# There are some instances of .if ~~sys.fancy in the source. Some of those
+# that are not inside displays are two-part things, in which case we just keep
+# the non-fancy part. For diagrams, however, they are in three parts:
+#
+# .if ~~sys.fancy
+# <aspic drawing stuff for PostScript and PDF>
+# .elif !~~html
+# <ascii art for txt and Texinfo>
+# .else
+# <HTML instructions for including a gif>
+# .fi
+#
+# In this case, we skip to the third part.
+
+elsif (/^\.if\s+~~sys\.fancy/ || /^\.else\b/)
+  {
+  while (<IN>)
+    { last if /^\.else\b/ || /^\.elif\s+!\s*~~html/ || /^\.fi\b/; }
+
+  if (/^\.elif\b/)
+    {
+    while (<IN>) { last if /^\.else\b/ || /^\.fi\b/; }
+    }
+  }
+
+# Similarly, for .if !~~sys.fancy, take the non-fancy part.
+
+elsif (/^\.if\s+!\s*~~sys.fancy/) {}
+
+# There are some explicit tests for ~~html for direct HTML inclusions
+
+elsif (/^\.if\s+~~html\b/) {}
+
+# There are occasional requirements to do things differently for Texinfo/HTML
+# and PS/txt versions. The latter are produced by SGCAL, so that's what the
+# flag is called.
+
+elsif (/\.if\s+~~sgcal/)
+  {
+  while (<IN>) { last if /\.else\b/ || /\.fi\b/; }
+  }
+
+# Also there is a texinfo flag
+
+elsif (/^\.if\s+~~texinfo\b/)
+  {
+  while (<IN>)
+    { last if /^\.else\b/ || /^\.elif\s+!\s*~~html/ || /^\.fi\b/; }
+  }
+
+# Ignore any other .if, .else, or .fi directives
+
+elsif (/^\.if\b/ || /^\.fi\b/ || /^\.else\b/) {}
+
+# Ignore .indent
+
+elsif (/^\.indent\b/) {}
+
+# Various flavours of numberpars map to corresponding list types.
+
+elsif (/^\.numberpars\b/)
+  {
+  $rest = $';
+  &setpar(0);
+
+  if ($rest =~ /(?:\$\.|\" \")/)
+    {
+    unshift @endlist, "ul";
+    unshift @listtype, "";
+    print OUT "<ul>\n<li>";
+    }
+  else
+    {
+    $nptype = ($rest =~ /roman/)? "a" : "1";
+    unshift @endlist, "ol";
+    unshift @listtype, " TYPE=\"$nptype\"";
+    print OUT "<ol>\n<li$listtype[0]>";
+    }
+  }
+
+elsif (/^\.nextp\b/)
+  {
+  &setpar(0);
+  print OUT "</li>\n<li$listtype[0]>";
+  }
+
+elsif (/^\.endp\b/)
+  {
+  &setpar(0);
+  print OUT "</li>\n</$endlist[0]>\n";
+  shift @listtype;
+  shift @endlist;
+  }
+
+# .display asis can use <pre> which uses a typewriter font.
+# Otherwise, we have to do our own line breaking. Turn tabbed lines
+# into an HTML table. There will always be a .tabs line first.
+
+elsif (/^\.display\b/)
+  {
+  my($intable) = 0;
+  my($asis) = /asis/;
+  my($rm) = /rm/;
+  my($eol,$indent);
+
+  # For non asis displays, start a paragraph, and set up to put an
+  # explicit break after every line.
+
+  if (!$asis)
+    {
+    &setpar(1);
+    $eol = "<br>";
+    $indent = "<tt>&nbsp;&nbsp;</tt>";
+    }
+
+  # For asis displays, use <pre> and no explicit breaks
+
+  else
+    {
+    print OUT "<pre>\n";
+    $eol = "";
+    $indent = "&nbsp;&nbsp;";
+    }
+
+  # Now read through until we hit .endd (or EOF, but that shouldn't happen)
+  # and process the lines in the display.
+
+  while (<IN>)
+    {
+    last if /^\.endd\b/;
+
+    # The presence of .tabs[et] starts a table
+
+    if (/^\.tabs/)
+      {
+      $intable = 1;
+      print OUT "<table cellspacing=0 cellpadding=0>\n";
+      }
+
+    # Some displays have an indent setting - ignore
+
+    elsif (/^\.indent\b/) {}
+
+    # Some displays have .blank inside them
+
+    elsif (/^\.blank\b/)
+      {
+      print OUT "<br>\n";
+      }
+      
+    # Some displays have emphasis inside them
+    
+    elsif (/^\.em\b/)
+      {
+      print OUT "<font color=green>" if ! $inem;
+      $inem = 1;
+      }    
+
+    elsif (/^\.nem\b/)
+      {
+      print OUT "</font>" if $inem;
+      $inem = 0;
+      }    
+
+    # There are occasional instances of .if [!]~~sys.fancy inside displays.
+    # In both cases we want the non-fancy alternative. (The only thing that
+    # matters in practice is noticing .tabs[et] actually.) Assume the syntax
+    # is valid.
+
+    elsif (/^\.if\s+~~sys.fancy/ || /^\.else\b/)
+      {
+      while (<IN>)
+        {
+        last if /^\.fi\b/ || /^\.else/;
+        }
+      }
+
+    elsif (/^\.if\s+!\s*~~sys.fancy/) {}
+
+    elsif (/^\.fi\b/) {}
+
+    # Ignore .newline and .linelength
+
+    elsif (/^\.newline\b/ || /^\.linelength\b/) {}
+    
+    # Ignore comments
+    
+    elsif (/^\.(\s|$)/) {}  
+
+    # There shouldn't be any other directives inside displays
+
+    elsif (/^\./)
+      {
+      print "*** Ignored directive inside .display: $_";
+      }
+
+    # Handle a data line within a display. If it's an asis display, the only
+    # conversion is to escape the HTML characters. Otherwise, process the
+    # SGCAL markup.
+
+    else
+      {
+      chomp;
+      if ($asis)
+        {
+        s/&/&#038;/g;
+        s/</&#060;/g;
+        s/>/&#062;/g;
+        }
+      else
+        {
+        $_ = &handle_text($_, !$rm);
+        $_ = "<tt>$_</tt>" if !$rm && $_ ne "";
+        }
+
+      # In a table, break fields at $t. For non-rm we must break the
+      # <tt> group as well.
+
+      if ($intable)
+        {
+        if ($rm)
+          {
+          s/\s*\$t\s*/&nbsp;&nbsp;<\/td><td>/g;
+          }
+        else
+          {
+          s/\s*\$t\s*/&nbsp;&nbsp;<\/tt><\/td><td><tt>/g;
+          }
+        s/<tt><\/tt>//g;
+        print OUT "<tr><td>&nbsp;&nbsp;$_</td></tr>\n";
+        }
+
+      # Otherwise, output straight, with <br> for non asis displays
+
+      else
+        {
+        s/<tt><\/tt>//g;
+        print OUT "$indent$_$eol\n";
+        }
+      }
+    }    # Loop for display contents
+
+  # Finish off the table and the <pre> - leave a paragraph open
+
+  print OUT "</table>\n" if $intable;
+  print OUT "</pre>\n" if $asis;
+  }
+
+# Handle configuration option definitions
+
+elsif (/^\.startconf\b/) {}
+
+elsif (/^\.conf\b/)
+  {
+  my($option, $type, $default) =
+    /^\.conf\s+(\S+)\s+("(?:[^"]|"")+"|\S+)\s+("(?:[^"]|"")+"|.*)/;
+
+  $option =~ s/\@_/_/g;       # Underscore will be quoted in option name
+
+  # If $type ends with $**$, add ",expanded" as there doesn't seem to be
+  # a dagger character generally available.
+
+  $type =~ s/^"([^"]+)"/$1/;
+  $type =~ s/\$\*\*\$/, expanded/;
+
+  # Default may be quoted, and it may also have quotes that are required,
+  # if it is a string.
+
+  $default =~ s/^"(.*)"$/$1/;
+  $default =~ s/""/"/g;
+  $default = &handle_text($default, 0);
+
+  print OUT "<hr>";
+  &setpar(0);
+  &handle_index($option, 0);
+  print OUT "<h3>$option</h3>\n" .
+            "<i>Type:</i>&nbsp; $type<br><i>Default:</i>&nbsp; $default<br>\n";
+  }
+
+elsif (/^\.endconf\b/)
+  {
+  print OUT "<hr><br>\n";
+  }
+
+
+# Handle "items" - used for expansion items and the like. We force the
+# item text into bold, and put a rule between items.
+
+elsif (/^\.startitems\b/) {}
+
+elsif (/^\.item\s+(.*)/)
+  {
+  my($arg) = $1;
+  chomp($arg);
+  $arg =~ s/^"(.*)"$/$1/;
+  $arg = &handle_text($arg, 0);
+
+  # If there are two .items in a row, we don't want to put in the
+  # separator line or start a new paragraph.
+
+  if ($lastwasitem)
+    {
+    print OUT "<br>";
+    }
+  else
+    {
+    print OUT "<hr>";
+    &setpar(1);
+    }
+  print OUT "<b>$arg</b>\n";
+  $new_lastwasitem = 1;
+  }
+
+elsif (/^\.enditems\b/)
+  {
+  print OUT "<hr><br>\n";
+  }
+
+
+# Handle command line option items
+
+elsif (/^\.startoptions\b/) {}
+
+elsif (/^\.option\s+(.*)/)
+  {
+  my($arg) = $1;
+  $arg =~ s/^"(.*)"$/$1/;
+
+  print OUT "<hr>";
+  &setpar(0);
+
+  # For indexing, we want to take up to the first # or < in the line,
+  # before processing.
+
+  my($name) = $arg =~ /^([^#<]+)/;
+  $name = &handle_text($name, 0);
+  &handle_index("-$name", 0);
+
+  # Output as heading, after the index
+
+  $arg = &handle_text($arg, 0);
+  print OUT "<h3>-$arg</h3>\n";
+  }
+
+elsif (/^\.endoptions\b/)
+  {
+  print OUT "<hr><br>\n";
+  }
+
+# Found an SGCAL directive that isn't dealt with. Oh dear.
+
+else
+  {
+  print "*** Unexpected SGCAL directive: line $. ignored:\n";
+  print "$_\n";
+  }
+
+# Remember if last was a .item, and read the next line
+
+$lastwasitem = $new_lastwasitem;
+$_ = <IN>;
+}
+
+
+
+##################################################
+#         First Pass - collect references        #
+##################################################
+
+sub pass_one{
+$thischapter = 0;
+
+open (IN, $source_file) || die "Can't open $source_file (first pass)\n";
+$_ = <IN>;
+
+# At the start of the specification text, there are some textual replacement
+# definitions. They set values, but not cross-references.
+
+while (/^\.r?set\s+(\S+)\s+"?([^"]+)\"?\s*$/)
+  {
+  $var_value{$1} = $2;
+  $_ = <IN>;
+  }
+
+# Now skip on till we hit the start of the first chapter. It will be numbered
+# 0 if we hit ".set chapter -1". There is only ever one unnumbered chapter.
+
+while (!/^\.chapter/)
+  {
+  $thischapter = -1 if /^\.set\s+chapter\s+-1/;
+  $_ = <IN>;
+  }
+
+# Loop for handling chapters
+
+while ($_)
+  {
+  $thischapter++;
+  $thissection = 0;
+
+  # Scan through chapter, setting up cross-references to the chapter
+  # and to the sections within it.
+
+  while (<IN>)
+    {
+    last if /^\.chapter/;
+    chomp;
+
+    if (/^\.section/)
+      {
+      $thissection++;
+      next;
+      }
+
+    # Handle .(r)set directives.
+
+    if (/^\.r?set\s+(\S+)\s+"?([^"]+)\"?\s*$/ && $1 ne "runningfoot")
+      {
+      my($key,$value) = ($1,$2);
+      $value =~ s/~~chapter/$thischapter/e;
+      $value =~ s/~~section/$thissection/e;
+
+      # Only one of $chapsplit or $sectsplit can be set.
+
+      if ($key =~ /^CHAP/)
+        {
+        $value = $chapsplit?
+          "<a href=\"${file_base}_$thischapter.html\">$value</a>"
+          :
+          "<a href=\"#CHAP$thischapter\">$value</a>";
+        }
+
+      elsif ($key =~ /^SECT/)
+        {
+        $value = $chapsplit?
+          "<a href=\"${file_base}_$thischapter.html" .
+            "#SECT$thischapter.$thissection\">$value</a>"
+          :
+          $sectsplit? "<a href=\"${file_base}_$thissection.html\">$value</a>"
+          :
+          "<a href=\"#SECT$thischapter.$thissection\">$value</a>";
+        }
+
+      $var_value{$key} = $value;
+      }
+    }
+  }
+
+close(IN);
+}
+
+
+
+
+
+##################################################
+#         Second Pass - generate HTML            #
+##################################################
+
+sub pass_two{
+my($tocn) = 0;
+my($inmacro) = 0;
+my($insection) = 0;
+
+$inem = 0;
+$thischapter = 0;
+$thissection = 0;
+
+# Open the source file and get the first line
+
+open (IN, $source_file) || die "Can't open $source_file (2nd pass)\n";
+$_ = <IN>;
+
+# Skip on till we hit the start of the first chapter, but note if we
+# pass ".set chapter -1", which is used to indicate no chapter numbering for 
+# the first chapter (we number is 0). Keep track of whether we are in macro
+# definitions or not, and when not, notice occurrences of .index, because this
+# are the "x see y" type entries.
+
+while (!/^\.chapter/)
+  {
+  $thischapter = -1 if /^\.set\s+chapter\s+-1/;
+  $inmacro = 1 if /^\.macro/;
+  $inmacro = 0 if /^\.endm/;
+  if (!$inmacro && /^\.index\s+(.*)/)
+    {
+    my($key);
+    my($s) = $1;
+    $s = &handle_text($s, 0);
+    $s =~ s/ /&nbsp;/g;            # All spaces unsplittable
+    $key = "\L$s";
+    $key =~ s/<[^>]+>//g;
+    $key =~ s/&#(\d+);/chr($1)/eg;
+    $cindex{$key} = $s;
+    }
+  $_ = <IN>;
+  }
+  
+# Open the TOC file
+
+open (TOC, ">$html/${file_base}_toc.html") ||
+  die "Can't open $html/${file_base}_toc.html\n";
+
+print TOC "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n";
+print TOC "<html>\n<head>\n<title>$doctitle Contents</title>\n</head>\n" .
+  "<body bgcolor=\"#F8F8F8\" text=\"#00005A\" " .
+  "link=\"#FF6600\" alink=\"#FF9933\" vlink=\"#990000\">\n";
+print TOC "<h1>$doctitle</h1><hr>\n<ul>\n";
+
+# Open the data file if we are not splitting at chapters
+
+&openout("$html/${file_base}.html") if !$chapsplit;
+
+# Loop for handling chapters. At the start of this loop, $_ is either EOF,
+# or contains a .chapter line.
+
+$firstchapter = $thischapter + 1; 
+
+while ($_)
+  {
+  print TOC "</ul>\n" if $insection;
+  $insection = 0;
+
+  $thischapter++;
+  $thissection = 0;
+  $lastwasrule = 0;
+
+  # Start a new file if required
+
+  if ($chapsplit)
+    {
+    &closeout("CHAP") if $thischapter != $firstchapter;
+    &openout("$html/${file_base}_$thischapter.html");
+    }
+
+  # Set up the chapter title. Save it for the TOC. Set up the anchor and
+  # link back to the TOC and show the title.
+
+  $_ =~ /^\.chapter\s+(.*)/;
+
+  my($title) = (($thischapter > 0)? "$thischapter. " : "") . &handle_text($1, 0);
+
+  $tocn++;
+  print TOC "<li><a " .
+    "name=\"TOC$tocn\" " .
+    "href=\"$current_file#CHAP$thischapter\">$title</a></li>\n";
+
+  print OUT "<h1>\n";
+  print OUT "<a name=\"CHAP$thischapter\" href=\"${file_base}_toc.html#TOC$tocn\">\n";
+  print OUT "$title\n</a></h1>\n";
+
+  # Scan the contents of the chapter
+
+  $_ = <IN>;
+  while ($_)
+    {
+    last if /^\.chapter/;
+
+    # Handle the start of a new section, starting a new file if required
+
+    if (/^\.section\s+(.*)/)
+      {
+      $thissection++;
+
+      print TOC "<ul>\n" if !$insection;
+      $insection = 1;
+
+      my($title) = (($thischapter > 0)? "$thischapter." : "") .
+        "$thissection. " . &handle_text($1, 0);
+
+      if ($sectsplit)
+        {
+        &closeout("SECT");
+        &openout("$html/${file_base}_$thissection.html");
+        }
+
+      $tocn++;
+      printf TOC ("<li><a " .
+        "name=\"TOC$tocn\" " .
+        "href=\"$current_file#SECT%s$thissection\">%s</a></li>\n",
+          ($thischapter > 0)? "$thischapter." : "", $title);
+
+      &setpar(0);
+      print OUT "<h2>\n";
+      printf OUT ("<a name=\"SECT%s$thissection\" ",
+        ($thischapter > 0)? "$thischapter." : "");
+      print OUT "href=\"${file_base}_toc.html#TOC$tocn\">\n";
+      print OUT "$title\n</a></h2>\n";
+      $_ = <IN>;
+      $lastwasrule = 0;
+      }
+
+    # Blank lines at this level are ignored
+
+    elsif (/^\s*$/)
+      {
+      $_ = <IN>;
+      }
+
+    # Directive and non-directive lines are handled independently, though
+    # in each case further lines may be read. Afterwards, the next line is
+    # in $_. If .em is at the start of a paragraph, treat it with the
+    # paragraph, because the matching .nem will be too. Messy!
+
+    elsif (/^\./)
+      {
+      if (/^\.em\b/)
+        {
+        $_=<IN>;
+        if (/^\./)
+          {
+          print OUT "<font color=green>" if ! $inem;
+          $inem = 1;
+          # Used to handle it here - but that fails if it is .section.
+          # Just let the next iteration of the loop handle it.  
+          # &handle_directive();
+          }
+
+        else
+          {
+          $_ = ".em\n" . $_;
+          &handle_paragraph();
+          $lastwasrule = 0;
+          $lastwasitem = 0;
+          }
+        }
+
+      # Not .em
+
+      else
+        {
+        &handle_directive();
+        }
+      }
+
+    # Not a directive
+
+    else
+      {
+      &handle_paragraph();
+      $lastwasrule = 0;
+      $lastwasitem = 0;
+      }
+
+    } # Loop for each line in a chapter
+  }   # Loop for each chapter
+
+# Close the last file, end off the TOC, and we are done.
+
+&closeout("");
+
+print TOC "</ul>\n" if $insection;
+
+if (defined %cindex)
+  {
+  $cindex_tocn = ++$tocn;
+  print TOC "<li><a name=\"TOC$tocn\" ".
+    "href=\"${file_base}_cindex.html\">Concept Index</a></li>\n";
+  }
+
+if (defined %oindex)
+  {
+  $oindex_tocn = ++$tocn;
+  print TOC "<li><a name=\"TOC$tocn\" ".
+    "href=\"${file_base}_oindex.html\">Option Index</a></li>\n";
+  }
+
+print TOC "</ul>\n</body>\n</html>\n";
+close(TOC);
+close(IN);
+}
+
+
+
+
+##################################################
+#           Adjust index points                  #
+##################################################
+
+# Because of the way the source is written, there are often index entries
+# that immediately follow the start of chapters and sections and the definition
+# of "items" like "helo = verify". This gets the correct page numbers for the
+# PostScript and PDF formats. However, for HTML we want the index anchor to be
+# before the section heading, because browsers tend to put the index point at
+# the top of the screen. So we re-read all the files we've just created, and
+# move some of the index points about. This is necessary only if indexes exist.
+# The files are small enough to be handled entirely in memory.
+
+sub adjust_index_points {
+print "Adjusting index points to precede headings\n";
+
+$" = "";
+
+opendir(DIR, "$html") || die "Failed to opendir $html\n";
+while ($file = readdir(DIR))
+  {
+  my($i);
+  next unless $file =~ /^${file_base}_\d+\.html$/;
+
+  open(IN, "<$html/$file") ||
+    die "Failed to open $html/$file (read)\n";
+  my(@lines) = <IN>;
+  close(IN);
+
+  for ($i = 0; $i < @lines; $i++)
+    {
+    if ($lines[$i] =~ /^<a name="IX\d+"><\/a>$/)
+      {
+      # Handle an index line that follows a heading definition. Move it back
+      # to just before the <h1> or whatever. This preserves the order of
+      # multiple index lines, not that that matters.
+
+      if ($lines[$i-1] =~ /^<\/a><\/h(\d)>/)
+        {
+        my($j);
+        my($found) = 0;
+        for ($j = $i-2; $j > 0 && $j > $i - 10; $j--)
+          {
+          if ($lines[$j] =~ /<h$1>/)
+            {
+            $found = 1;
+            last;
+            }
+          }
+        if ($found)
+          {
+          splice(@lines, $j, 0, splice(@lines, $i, 1));
+          }
+        }
+
+      # Handle an index line that follows an "item". Move it back one line.
+
+      elsif ($lines[$i-1] =~ /^<b>.*<\/b>\s*$/)
+        {
+        splice(@lines, $i-1, 0, splice(@lines, $i, 1));
+        }
+
+      # Handle an index line that follows a "conf" definition
+
+      elsif ($lines[$i-1] =~ /^<i>Type:<\/i>/ && $lines[$i-2] =~ /^<h3>/)
+        {
+        splice(@lines, $i-2, 0, splice(@lines, $i, 1));
+        }
+
+      # Handle an index line that follows an "option" definition
+
+      elsif ($lines[$i-1] =~ /^<h3>/)
+        {
+        splice(@lines, $i-1, 0, splice(@lines, $i, 1));
+        }
+      }
+    }
+
+  open(OUT, ">$html/$file") ||
+    die "Failed to open $html/$file (write)\n";
+
+  print OUT "@lines";
+  close OUT;
+  undef @lines;
+  }
+}
+
+
+
+
+##################################################
+#               Create Index                     #
+##################################################
+
+sub create_index{
+my($hash)   = $_[0];
+my($ifname) = $_[1];
+my($ititle) = $_[2];
+my(%indexindex);
+
+open(INDEX, ">$html/${file_base}_$_[1].html") ||
+  die "Failed to open $html/${file_base}_$ifname\n";
+
+print INDEX "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n";
+print INDEX "<html>\n<head>\n<title>$doctitle $ititle</title>\n";
+print INDEX "<base target=\"body\">\n</head>\n";
+
+print INDEX "<body bgcolor=\"#FFFFDF\" text=\"#00005A\" " .
+  "link=\"#FF6600\" alink=\"#FF9933\" vlink=\"#990000\">\n";
+
+print INDEX "<h3>$ititle</h3>\n";
+
+# We have to scan the keys in the hash twice; first to build the list
+# of initial letters, and then to do the business. The first time we
+# do not need to sort them.
+
+foreach $key (keys %$hash)
+  {
+  my($initial) = substr($key,0,1);
+  $initial = "\U$initial";
+  $indexindex{$initial} = 1 if $initial ge "A";
+  }
+
+print INDEX "<p>\n";
+foreach $key (sort keys %indexindex)
+  {
+  print INDEX "&nbsp;<a href=\"#$key\" target=\"index\">$key</a>\n";
+  }
+print INDEX "<hr></p>\n";
+
+my($letter) = "";
+print INDEX "<p>\n";
+
+foreach $key (sort
+      { ("\L$a" eq "\L$b")? ("$a" cmp "$b") : ("\L$a" cmp "\L$b") }
+    keys %$hash)
+  {
+  my($initial) = substr($key,0,1);
+  $initial = "\U$initial";
+  if ($initial ne $letter)
+    {
+    if ($initial ge "A")
+      {
+      print INDEX "<br>\n" if $letter ne "";
+      print INDEX "<a name=\"$initial\"></a>\n";
+      print INDEX "<font size=\"+1\">\U$initial\E</font><br>\n";
+      }
+    $letter = $initial;
+    }
+  print INDEX "$$hash{$key}<br>\n";
+  }
+
+print INDEX "</p>\n";
+
+print INDEX "</body>\n</html>\n";
+close(INDEX);
+}
+
+
+
+
+##################################################
+#           Show usage and die                   #
+##################################################
+
+sub usage {
+die "Usage: g2h [-split no|section|chapter] <source> <title>\n";
+}
+
+
+
+##################################################
+#           Entry point and main program         #
+##################################################
+
+
+# Directory in which to put the new HTML files
+
+$html = "html";
+
+# Global variables.
+
+%cindex = ();
+%oindex = ();
+
+$chapsplit = 0;
+$cindex_tocn = 0;
+$file_base = "";
+$index_count = 0;
+$inem = 0;
+$inpar = 0;
+$lastwasitem = 0;
+$lastwasrule = 0;
+$oindex_tocn = 0;
+$sectsplit = 0;
+$source_file = "";
+$thischapter = 0;
+$thissection = 0;
+
+
+# Handle options
+
+my($splitset) = 0;
+
+while (scalar @ARGV > 0 && $ARGV[0] =~ /^-/)
+  {
+  if ($ARGV[0] eq "-split" && !$splitset)
+    {
+    $splitset = 1;
+    shift @ARGV;
+    my($type) = shift @ARGV;
+    if    ($type eq "section") { $sectsplit = 1; }
+    elsif ($type eq "chapter") { $chapsplit = 1; }
+    elsif ($type eq "no"     ) { $sectsplit = $chapsplit = 0; }
+    else                       { &usage(); }
+    }
+  else { &usage(); }
+  }
+
+# Get the source file and its base
+
+&usage() if scalar @ARGV <= 0;
+$source_file = shift @ARGV;
+($file_base) = $source_file =~ /^(.*)\.src$/;
+
+&usage() if scalar @ARGV <= 0;
+$doctitle = shift @ARGV;
+
+print "\nCreate HTML for $doctitle from $source_file\n";
+
+# Remove the old HTML files
+
+print "Removing old HTML files\n";
+system("/bin/rm -rf $html/${file_base}_*.html");
+
+# First pass identifies all the chapters and sections, and collects the
+# values of the cross-referencing variables.
+
+print "Scanning for cross-references\n";
+&pass_one();
+
+$maxchapter = $thischapter;      # Used if chapter splitting
+$maxsection = $thissection;      # Used if section splitting
+
+# Second pass actually creates the HTML files.
+
+print "Creating the HTML files\n";
+&pass_two();
+
+# Reprocess for moving some of the index points, if indexes were created
+
+&adjust_index_points() if scalar(keys %cindex) > 0 || scalar(keys %oindex) > 0;
+
+# Finally, we must create the option and concept indexes if any data
+# has been collected for them.
+
+if (scalar(keys %cindex) > 0)
+  {
+  print "Creating concept index\n";
+  &create_index(\%cindex, "cindex", "Concepts");
+  }
+
+if (scalar(keys %oindex) > 0)
+  {
+  print "Creating option index\n";
+  &create_index(\%oindex, "oindex", "Options");
+  }
+
+# End of g2h
diff --git a/doc/doc-scripts/g2man b/doc/doc-scripts/g2man
new file mode 100755 (executable)
index 0000000..e3006b5
--- /dev/null
@@ -0,0 +1,251 @@
+#! /usr/bin/perl -w
+# $Cambridge: exim/doc/doc-scripts/g2man,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# Script to find the command line options in the Exim spec, and turn them
+# into a man page, because people like that.
+
+
+##################################################
+#            De-markup one line                  #
+##################################################
+
+sub process {
+my($x) = $_[0];
+
+# Hide SGCAL escapes
+
+$x =~ s/\@\@/&&a/g;         # @@
+$x =~ s/\@\\/&&b/g;         # @\
+$x =~ s/\@</&&l/g;          # @<
+$x =~ s/\@>/&&g/g;          # @>
+$x =~ s/\@\{/&&c/g;         # @{
+$x =~ s/\@\}/&&d/g;         # @}
+$x =~ s/\@#/&&s/g;          # @#
+$x =~ s/\@(.)/$1/g;         # all other @s
+
+# Convert SGCAL markup
+
+$x =~ s/#/ /g;                            # turn #   into a space
+$x =~ s/\$~//g;                           # turn $~  into nothing
+$x =~ s/__/_/g;                           # turn __  into _
+$x =~ s/\$sc\{([^\}]*?)\}/$1/g;           # turn $sc{xxx}   into xxx
+$x =~ s/\$st\{([^\}]*?)\}/$1/g;           # turn $st{xxx}   into xxx
+$x =~ s/\$si\{([^\}]*?)\}/$1/g;           # turn $si{xxx}   into xxx
+$x =~ s/\$tt\{([^\}]*?)\}/$1/g;           # turn $tt{xxx}   into xxx
+$x =~ s/\$it\{([^\}]*?)\}/$1/g;           # turn $it{xxx}   into xxx
+$x =~ s/\$bf\{([^\}]*?)\}/$1/g;           # turn $bf{xxx}   into xxx
+$x =~ s/\$rm\{([^\}]*?)\}/$1/g;           # turn $rm{xxx}   into xxx
+$x =~ s/\$cb\{([^\}]*?)\}/$1/g;           # turn $cb{xxx}   into xxx
+
+
+$x =~ s/\\\\([^\\]*?)\\\\/\U$1/g;         # turn \\xxx\\    into XXX
+$x =~ s/\\\(([^)]*?)\)\\/$1/g;            # turn \(xxx)\    into xxx
+$x =~ s/\\\"([^\"]*?)\"\\/$1/g;           # turn \"xxx"\    into xxx
+$x =~ s/\\\%([^\%]*?)\%\\/"$1"/g;         # turn \%xxx%\    into "xxx"
+
+$x =~   s/\\\?([^?]*?)\?\\/$1/g;          # turn \?URL?\    into URL
+$x =~   s/<<([^>]*?)>>/<$1>/g;            # turn <<xxx>>    into <xxx>
+$x =~   s/\\\$([^\$]*?)\$\\/\$$1/g;       # turn \$xxx$\    into $xxx
+$x =~   s/\\\-([^\\]*?)\-\\/\-$1/g;       # turn \-xxx-\    into -xxx
+$x =~   s/\\\*\*([^*]*?)\*\*\\/$1/g;      # turn \**xxx**\  into xxx
+$x =~   s/\[\(([\w\/]*)\)\]//g;           # remove inline HTML
+
+$x =~ s/\\\*([^*]*?)\*\\/$1/g;            # turn \*xxx*\    into xxx
+$x =~ s/\\([^\\]*?)\\/"$1"/g;             # turn \xxx\      into "xxx"
+$x =~ s/\$\*\$/\*/g;                      # turn $*$        into *
+$x =~ s/\$t\b//g;                         # turn $t         into nothing
+
+$x =~ s/::([^:]+)::/$1:/g;                # turn ::xxx::    into xxx:
+
+# Put back escaped SGCAL specials
+
+$x =~ s/&&a/\@/g;             # @@ => @
+$x =~ s/&&b/\\/g;             # @\ => \          
+$x =~ s/&&l/</g;              # @< => <
+$x =~ s/&&g/>/g;              # @> => >
+$x =~ s/&&c/\@{/g;            # @{ => @{
+# $x =~ s/&&rc/{/g;             # 
+# $x =~ s/&&rd/}/g;             # 
+$x =~ s/&&d/\@}/g;            # @} => @}
+$x =~ s/&&s/#/g;              # @#
+
+# Remove any null flags ($$)
+
+$x =~ s/\$\$//g;
+
+$x;
+}
+
+
+##################################################
+#             De-reference a paragraph           #
+##################################################
+
+# Remove sentences or parenthetical comments that contain references.
+
+sub deref {
+my($t) = $_[0];
+
+$t =~ s/^(\n*)[^.()]+~~[^.]+\.\s*/$1/;
+$t =~ s/\s?\.[^.()]+~~[^.]+\././g;
+$t =~ s/\s?\([^~).]+~~[^)]+\)//g;
+
+$t;
+}
+
+
+##################################################
+#            Quote what needs quoting            #
+##################################################
+
+# This is for anything that must be quoted in the final output, independent
+# of whether it is in "asis" text or not.
+
+sub mustquote {
+my($t) = $_[0];
+$t =~ s/(?<!\\)-/\\-/g;
+
+$t;
+}
+
+
+
+##################################################
+#              Main Program                      #
+##################################################
+
+open(IN, "spec.src") || die "Can't open spec.src\n";
+open(OUT, ">exim.8" ) || die "Can't open exim.8\n";
+
+print OUT <<End;
+.TH EXIM 8
+.SH NAME
+exim \\- a Mail Transfer Agent
+.SH SYNOPSIS
+.B exim [options] arguments ...
+.br
+.B mailq [options] arguments ...
+.br
+.B rsmtp [options] arguments ...
+.br
+.B rmail [options] arguments ...
+.br
+.B runq [options] arguments ...
+.br
+.B newaliases [options] arguments ...
+
+.SH DESCRIPTION
+Exim is a mail transfer agent (MTA) developed at the University of Cambridge.
+It is a large program with very many facilities. For a full specification, see
+the reference manual. This man page contains only a description of the command
+line options. It has been automatically generated from the reference manual
+source, which is why the formatting is poor in some places.
+
+.SH SETTING OPTIONS BY PROGRAM NAME
+.TP 10
+\\fBmailq\\fR
+Behave as if the option \\-bp were present before any other options. The \\-bp
+option requests a listing of the contents of the mail queue on the standard
+output.
+.TP
+\\fBrsmtp\\fR
+Behaves as if the option \\-bS were present before any other options, for
+compatibility with Smail. The \\-bS option is used for reading in a number of
+messages in batched SMTP format.
+.TP
+\\fBrmail\\fR
+Behave as if the \\-i and \\-oee options were present before any other options,
+for compatibility with Smail. The name \\fBrmail\\fR is used as an interface by
+some UUCP systems. The \\-i option specifies that a dot on a line by itself
+does not terminate a non\\-SMTP message; \\-oee requests that errors detected in
+non\\-SMTP messages be reported by emailing the sender.
+.TP
+\\fBrunq\\fR
+Behave as if the option \\-q were present before any other options, for 
+compatibility with Smail. The \\-q option causes a single queue runner process
+to be started. It processes the queue once, then exits.
+.TP
+\\fBnewaliases\\fR
+Behave as if the option \\-bi were present before any other options, for
+compatibility with Sendmail. This option is used for rebuilding Sendmail's
+alias file. Exim does not have the concept of a single alias file, but can be
+configured to run a specified command if called with the \\-bi option.
+
+
+.SH OPTIONS
+.TP 10
+End
+
+while (<IN>) { last if /^\.startoptions/; }
+die "Can't find start of options\n" if ! defined $_;
+
+# Find the start of the first option
+
+while (<IN>) { last if /^\.option/; }
+die "Can't find start of first option\n" if ! defined $_;
+
+# Loop for each individual option
+
+while (/^\.option (.*)/)
+  {
+  $nlpending = 0;
+  $itemtext = "";
+
+  printf OUT ("\\fB\\-%s\\fR\n", &mustquote(&process($1)));
+
+  # Process the data for the option
+
+  while (<IN>)
+    {
+    last if /^\.(?:option|endoptions)/;
+    next if /^\.index/;
+    next if /^\.em\s*$/;
+    next if /^\.nem\s*$/;
+
+    if (/^\.display(?:\s+flow)?(?:\s+rm)?\s*$/)
+      {
+      print OUT &mustquote(&deref($itemtext));
+      $itemtext = "";
+      print OUT "\n";
+      while (($_ = <IN>) !~ /^\.endd/)
+        {
+        print OUT "  ", &mustquote(&deref(&process($_))) if ! /^\./;
+        }
+      $nlpending = 1;
+      }
+
+    elsif (/^\.display asis\s*$/)
+      {
+      print OUT &mustquote(&deref($itemtext));
+      $itemtext = "";
+      print OUT "\n";
+      while (($_ = <IN>) !~ /^\.endd/)
+        {
+        print OUT &mustquote("  $_");
+        }
+      $nlpending = 1;
+      }
+
+    elsif (/^\s*$/)
+      {
+      print OUT &mustquote(&deref($itemtext));
+      $itemtext = "";
+      $nlpending++;
+      }
+
+    else
+      {
+      while ($nlpending > 0)
+        {
+        $itemtext .= "\n";
+        $nlpending--;
+        }
+      $itemtext .= &process($_);
+      }
+    }
+
+  print OUT &mustquote(&deref($itemtext));
+  print OUT ".TP\n";
+  }
+
+# End of g2man
diff --git a/doc/doc-scripts/g2t b/doc/doc-scripts/g2t
new file mode 100755 (executable)
index 0000000..30c713c
--- /dev/null
@@ -0,0 +1,1347 @@
+#! /usr/bin/perl -w
+# $Cambridge: exim/doc/doc-scripts/g2t,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+
+# A Perl script to turn the SGCAL source of the Exim documentation into
+# Texinfo input, more or less...
+
+# Supply the source file names as arguments.
+# The output goes to the standard output.
+
+
+##################################################
+#         Ensure unique node name                #
+##################################################
+
+# Node names must be unique. Occasionally in the Exim spec there are duplicate
+# section names, and it's become too much of a hassle to keep them distinct
+# manually. So it is now automated.
+
+########### Never really got this working. Abandoned ###############
+
+sub unique {
+my($node) = $_[0];
+if (defined $node_names{$node})
+  {
+  $node_names{$node} += 1; 
+  $node = "$node ($node_names{$node})"; 
+  
+print STDERR "+++ $node\n";
+  }
+else
+  {
+  $node_names{$node} = 0;
+  }
+$node;
+}  
+
+
+
+##################################################
+#         De-comma a node name                   #
+##################################################
+
+# Commas, colons, and apostrophes are not permitted in Texinfo
+# node names. I find this incredible, but it is clearly documented.
+# The Exim manual has been re-organized not to have colons or
+# apostrophes in any chapter or section titles, but I can't manage
+# without commas. This function turns "," into " and", which is
+# the best that can be done; we can use some clever Perlery to
+# just take out commas before "and".
+
+# Sigh. The Sendmail option -p<rval>:<sval> now means that there's a colon
+# in the node name for that option. Turn the colon into <colon>. This is also
+# done for menus.
+
+# Another thing that causes problems in node names in some versions of
+# Texinfo is the use of @sc{xxx} for small caps. Just turn these all into
+# real caps. This is also done for menus.
+
+sub decomma {
+$_[0] =~ s/,(?!\sand)/ and/g;
+$_[0] =~ s/,//g;
+$_[0] =~ s/\@sc\{([^}]*)\}/\U$1/g;
+$_[0] =~ s/:/<colon>/g;
+$_[0];
+}
+
+
+
+##################################################
+#           De-quote a string                    #
+##################################################
+
+# @x is turned into x, except when x=@, or when asis is set,
+# in which case single @ must turn into @@. A single substitute
+# doesn't work in the non-asis case, because of the problems of
+# handling things like @@@$, so we do it the hard way.
+
+sub dequote {
+if ($asis) { $_[0] =~ s/@/@@/g; } else
+  {
+  $_[0] =~ s/@@/&at&/g;
+  $_[0] =~ s/@([^@])/$1/g;
+  $_[0] =~ s/&at&/@@/g;
+  }
+$_[0];
+}
+
+
+##################################################
+#           Get next line                        #
+##################################################
+
+# Called from handle_directive, to get the next source line
+# into $_.
+
+sub get_next_line {
+if ($processing_subsection)
+  { return $_ = shift @SUBBUFFER; }
+else
+  { return $_ = <>; }
+}
+
+
+
+##################################################
+#           Handle text lines                    #
+##################################################
+
+# This function is handed whole paragraphs, and we assume that
+# SGCAL font changing markup is always complete within a paragraph.
+# We have to replace escaped versions of significant characters with
+# some magic before performing general transformations, and then
+# put them back afterwards. The character & is not common in the text,
+# and && is unknown, so we use that.
+
+sub handle_text {
+$_ = $_[0];
+
+if ($asis)
+  {
+  $_ = dequote($_);
+  s/(\{|\})/\@$1/g;
+  return $_;
+  }
+
+while (/~~/)
+  {
+  $left = $`;
+  ($name) = $' =~ /^(\w+)/;
+  $right = $';
+
+  $value = $references{$name};
+  $value = "" if !defined($value);
+
+  if ($value =~ /\*\*\*\*/)
+    {
+    $value = ($` eq $current_chapter)? "\"$'\"" :
+      "\"$'\" in chapter \"$`\"";
+    $value = "" if $value eq "\"\"";
+    }
+  elsif ($value !~ /^[0-9]+\.[0-9]+$/)   # quote unless version number
+    {                                                
+    $value = "\"$value\"";                          
+    }
+
+  $_ = "${left}${value}${right}";
+  }
+
+s/\@\@/&&a/g;         # @@
+s/\@\\/&&b/g;         # @\
+s/\@</&&l/g;          # @<
+s/\@>/&&g/g;          # @>
+s/\@\{/&&c/g;         # @{
+s/\@\}/&&d/g;         # @}
+s/\@#/&&s/g;          # @#
+
+# Now remove all other @'s
+
+$_ = dequote($_);
+
+# Convert SGCAL markup
+
+s/#/ /g;                            # turn #   into a space
+s/\$~//g;                           # turn $~  into nothing
+s/__/_/g;                           # turn __  into _
+s/\$sm\{//g;                        # turn $sm{     into nothing
+s/\$sc\{([^\}]*?)\}/$1/g;           # turn $sc{xxx} into xxx
+s/\$st\{([^\}]*?)\}/$1/g;           # turn $st{xxx} into xxx
+s/\$si\{([^\}]*?)\}/$1/g;           # turn $si{xxx} into xxx
+s/\$tt\{([^\}]*?)\}/$1/g;           # turn $tt{xxx} into xxx
+
+s/\$it\{([^\}]*?)\}/$1/g;           # turn $it{xxx} into xxx
+
+s/\$bf\{([^\}]*?)\}/$1/g;           # turn $bf{xxx} into xxx
+s/\$rm\{([^\}]*?)\}/$1/g;           # turn $rm{xxx} into xxx
+s/\$cb\{([^\}]*?)\}/$1/g;           # turn $cb{xxx} into xxx
+
+# This is a fudge for some specific usages of $<; can't just do a global
+# is it occurs in things like $<variable name> as well.
+
+s/\[\$<\]/[]/g;                     # turn [$<]     into []
+s/&&b\$<\./&&b./g;                  # turn \$<.     into \.  (\ == &&b by now)
+s/(\d)\$<-/$1-/g;                   # turn 0$<-     into 0-
+
+# There is one case where the terminating } of an escape sequence is
+# in another paragraph - this follows $sm{ - it can be fixed by
+# removing any stray } in a paragraph that contains no { chars.
+
+s/\}//g if !/\{/;
+
+# Any remaining {} must be escaped to prevent Texinfo from complaining
+
+s/(\{|\})/\@$1/g;
+
+# Now to conversions that put {} into the file.
+# Change <<..>> from @var to just <...> as the caps that Texinfo
+# uses look far too shouty.
+
+s/\\\\([^\\]*?)\\\\/\@sc\{\L$1\}/g; # turn \\xxx\\  into @sc{xxx}
+s/\\\(([^)]*?)\)\\/\@file\{$1\}/g;  # turn \(xxx)\  into @file{xxx}
+s/\\\"([^\"]*?)\"\\/\@file\{$1\}/g; # turn \"xxx"\  into @file{xxx}
+
+s/\\\?([^?]*?)\?\\/$1/g;            # turn \?URL?\    into URL
+s/<<([^>]*?)>>/<$1>/g;              # turn <<xxx>>    into <xxx>
+s/\\\$([^\$]*?)\$\\/\$$1/g;         # turn \$xxx$\    into $xxx
+s/\\\-([^-]*?)\-\\/\-$1/g;          # turn \-xxx-\    into -xxx
+s/\\\*\*([^*]*?)\*\*\\/$1/g;        # turn \**xxx**\  into xxx
+s/\[\(([\w\/]*)\)\]//g;             # remove inline HTML
+
+s/\\\*([^*]*?)\*\\/\@dfn\{$1\}/g;     # turn \*xxx*\    into @dfn{xxx}
+s/\\%([^*]*?)%\\/\@dfn\{$1\}/g;       # turn \%xxx%\    into @dfn{xxx}
+s/:::([^:]*?)::/\@dfn\{:$1:\}/g;      # turn :::xxx::   into @dfn{:xxx:}
+s/::([^:]*?)::/\@dfn\{$1:\}/g;        # turn ::xxx::    into @dfn{xxx:}
+s/\\([^\\]*?)\\/\@dfn\{$1\}/g;        # turn \xxx\      into @dfn{xxx}
+s/\$\*\$/\*/g;                        # turn $*$        into *
+
+# Put back escaped SGCAL specials
+
+s/&&a/\@\@/g;
+s/&&b/\\/g;
+s/&&l/</g;
+s/&&g/>/g;
+s/&&c/\@{/g;
+s/&&rc/{/g;
+s/&&rd/}/g;
+s/&&d/\@}/g;
+s/&&s/#/g;
+
+# Remove any null flags ($$)
+
+s/\$\$//g;
+
+# If the paragraph starts with $c\b, change this into @center. Assume
+# we don't ever get two of these in a row.
+
+s/^\$c\b/\@center /;
+
+# If the paragraph starts with $e\b, stuff some tabs in there, as
+# Texinfo can't do this on its own (as far as I can see). They must
+# tabs; Texinfo treats them as different to spaces. Sigh.
+
+s/^\$e\b/\t\t\t\t\t\t\t/;
+
+# Handle $t. The Exim spec only ever has one tab per line. Er, not
+# quite true, but a good enough assumption. $t is always followed
+# by a non-word character.
+
+# The .tabs directive has stashed the value in the $tab variable.
+# Don't count Texinfo font chars.
+
+while (/(^|.+?\n)(.+?)\$t(\W.*\n)/)
+  {
+  $before = $` . $1;
+  $after = $';
+  $left = $2;
+  $right = $3;
+
+  $left =~ s/\s$//;
+  $right =~ s/^\s+//;
+
+  $plainleft = $left;
+  $plainleft =~ s/\@[a-z]+\{([^}]+?)\}/$1/g;
+  $plainleft =~ s/\@//g;
+
+  $_ = $before . $left . (" " x ($tab - length($plainleft))) . $right . $after;
+
+  # Fudge for the one case where there are two tabs
+
+  if ($tab2 != 0)
+    {
+    $temp = $tab;
+    $tab = $tab2;
+    $tab2 = $temp;
+    }
+  }
+
+# Return the new line (paragraph)
+
+$_;
+}
+
+
+
+##################################################
+#           Handle directive lines               #
+##################################################
+
+# Use get_next_line() instead of <> because this is called to process
+# stacked up subsection lines
+
+sub handle_directive {
+
+my($new_lastwasitem) = 0;
+
+# Chapter directives just require . => @; however, dequoting the
+# line thereafter will remove the first @, so just force it back
+# afterwards. If the chapter is is one describing a driver, set
+# the driver name.
+
+if (/\.chapter/)
+  {
+  tr/./@/;
+  push(@ONESECTION, "@" . &dequote("$_\n"));
+  $driver_name = (/The\s+(\S+)\s+(director|router|transport|authenticator)/)? $1 :
+    (/Generic options common to both directors and routers/)?
+      "director or router" :
+    (/[Gg]eneric\s+options for (\S+)s/)? $1 : "";
+  $driver_name = &dequote($driver_name);
+  }
+
+# Section directives just require . => @; however, dequoting the
+# line thereafter will remove the first @, so just force it back
+# afterwards. Remove any colons in section titles as they cause
+# Texinfo trouble. Also remove any \\ (small caps) markup, which
+# appears in a couple of cases.
+
+elsif (/\.section/)
+  {
+  tr/./@/;
+  s/://;
+  s"\\\\""g;
+  push(@ONESECTION, "@" . &dequote("$_\n"));
+
+  # Horrible magic fudge to cope with the fact that exim_lock has
+  # -v and -q options, just like the main program.
+
+  $driver_name = "exim_lock" if /Mailbox maintenance/;
+  
+  # Similar magic for exiqgrep, which also duplicates options
+  
+  $driver_name = "exiqgrep" if /Selective queue listing/;  
+  }
+
+# .newline must put @* on the end of the previous line, if any, except
+# inside a display, where it causes trouble.
+
+elsif (/\.newline/)
+  {
+  if (@ONESECTION > 0 && ! $indisplay)
+    {
+    $_ = pop(@ONESECTION);
+    s/(\n*)$/\@*$1/;
+    push(@ONESECTION, $_);
+    }
+  }
+
+# .blank turns into @sp, adding 1 if no argument
+
+elsif (/\.blank/)
+  {
+  s/\.blank\s+(\d+)/\@sp $1/;
+  s/\.blank/\@sp 1/;
+  push(@ONESECTION, $_);
+  }
+
+# .rule turns into a line of hyphens
+
+elsif (/\.rule/)
+  {
+  push(@ONESECTION, ("-" x ($in_itemize? 68 : 73)) . "\@*\n");
+  }
+
+# There's one explicit .tabset setting for two tab stops
+
+elsif (/\.tabset\s*/)
+  {
+  $rest = $';
+  ($first,$second) = $rest =~ /(\d+)em\s+(\d+)em/;
+  $tab = ($first * 7)/6;
+  $tab2 = $tab + ($second * 7)/6;
+  }
+
+# .tabs remembers the first (and only) tab setting
+
+elsif (/\.tabs\s*/)
+  {
+  $tab = ($' * 7)/6;
+  $tab2 = 0;
+  }
+
+# .tempindent is used only to align some of the expansion stuff nicely;
+# just ignore it. It is used in conjunction with .push/.pop.
+
+elsif (/\.(tempindent|push|pop)\s*/)
+  {
+  }
+
+# There are some instances of .if ~~sys.fancy in the source. Some of these
+# are two-part things, in which case we just keep the non-fancy. For diagrams,
+# however, they are in three parts:
+#
+# .if ~~sys.fancy
+# <aspic drawing stuff>
+# .elif ~~nothtml
+# <ascii art for txt and Texinfo>
+# .else
+# <HTML instructions for including a gif>
+# .fi
+
+elsif (/\.if \~\~sys\.fancy/)
+  {
+  while (&get_next_line())
+    { last if /\.else\b/ || /\.elif\s+\~\~nothtml/ || /\.fi\b/; }
+
+  if (/\.elif/)
+    {
+    $skip_else = 1;
+    }
+  }
+
+# There are occasional requirements to do things differently for
+# Texinfo/HTML and the PS/txt versions, and there are also some
+# HTML-specific things.
+
+elsif (/\.if\s+~~sgcal/ || /\.if\s+~~html/)
+  {
+  while (&get_next_line()) { last if /\.else\b/ || /\.fi\b/; }
+  }
+
+# We may also have Texinfo-specific bits
+
+elsif (/^\.if\s+~~texinfo/)
+  {
+  $skip_else = 1;
+  }
+
+# Ignore any other .if directives
+
+elsif (/\.if/) {}
+
+# Skip else part if flag set
+
+elsif (/\.else/ && $skip_else)
+  {
+  while (&get_next_line()) { last if /\.fi\b/; }
+  $skip_else = 0;
+  }
+
+# Ignore other .fi and .else as any .if directives are handled specially
+
+elsif (/\.fi/ || /\.else/) {}
+
+# Ignore .indent
+
+elsif (/\.indent/) {}
+
+# Plain .index goes to @cindex - the "concept" index. Also, there
+# are some calls to vindex and findex in the SGCAL source - treated
+# as synonymous with .index - which are split into the equivalent
+# indexes here.
+
+elsif (/\.(.?)index/)
+  {
+  $rest = $';
+  $letter = ($1 eq "")? "c" : $1;
+  tr/./@/;                           # .index -> @index
+  
+  $rest =~ s/\\\(//g;                # Remove markup
+  $rest =~ s/\)\\//g; 
+  $rest =~ s/\\%//g;
+  $rest =~ s/%\\//g;
+  $rest =~ s/\\\*//g;
+  $rest =~ s/\*\\//g;    
+  $rest =~ s/\\"//g;
+  $rest =~ s/"\\//g;
+  $rest =~ s/:://g;
+  $rest =~ s/\\-/-/g;
+  $rest =~ s/-\\//g;
+  $rest =~ s/~~//g;     
+  $rest =~ tr/\\//d;                 # Remove \
+   
+  $rest =~ s/\@\$/\$/g;              # @$  -> $
+  $rest =~ s/\@_/_/g;                # @_  -> _
+  $rest =~ s/\@\+/+/g;               # @+  -> +
+  $rest =~ s/\$\*\$/\*/g;            # $*$ -> *
+  $rest =~ s/\$([^\$]+)\$/\$$1/g;    # $x$ -> $x
+   
+  $rest =~ s/^\s+//;                 # Remove leading spaces
+  $rest =~ s/\s+$//;                 # Remove trailing spaces
+  $rest =~ s/\|\|/:/;                # || -> : 
+  push(@ONESECTION, "\@${letter}index $rest\n");
+
+  # Duplicate entries for things that were listed as "x see y"
+
+  if (defined $indirections{$rest})
+    {
+    push(@ONESECTION, "\@${letter}index $indirections{$rest}\n");
+    }
+  }
+
+# Various flavours of numberpars map to itemize and enumerate.
+# Haven't found a way of having a blank space 'bullet' yet, so
+# currently using minus.
+
+elsif (/\.numberpars/)
+  {
+  $rest = $';
+  $type = "enumerate";
+  $flag = "";
+
+  if    ($rest =~ /\$\./)  { $flag = " \@bullet"; $type = "itemize" }
+  elsif ($rest =~ /\" \"/) { $flag = " \@minus";  $type = "itemize"; }
+  elsif ($rest =~ /roman/) { $flag = " a"; $type = "enumerate"; }
+
+  push(@ONESECTION, "\n\@$type$flag\n\n\@item\n");
+  push(@ENDLIST, $type);
+  $in_itemize++;
+  }
+
+elsif (/\.nextp/)
+  {
+  push(@ONESECTION, "\n\@item\n");
+  }
+
+elsif (/\.endp/)
+  {
+  $endname = pop(@ENDLIST);
+  push(@ONESECTION, "\@end $endname\n\n");
+  $in_itemize--;
+  }
+
+# The normal .display (typewriter font) => @example, while the rm
+# form goes to @display (no change of font). For Texinfo we need a
+# blank line after @display.
+
+elsif (/\.display/)
+  {
+  $type = /rm/? "display" : "example";
+  $asis = 1 if /asis/;
+  $indisplay = 1;
+  push(@ONESECTION, "\@$type\n\n");
+  push(@ENDLIST, $type);
+  }
+
+elsif (/\.endd/)
+  {
+  $asis = 0;
+  $indisplay = 0;
+  $endname = pop(@ENDLIST);
+  push(@ONESECTION, "\@end $endname\n\n");
+  }
+
+elsif (/\.conf/)
+  {
+  ($option, $type, $default) =
+    /\.conf\s+(\S+)\s+("(?:[^"]|"")+"|\S+)\s+("(?:[^"]|"")+"|.*)/;
+
+  $option = &dequote($option);
+
+  # If $type ends with $**$ (turned into a dagger for PS version),
+  # replace with ", expanded". Remove any surrounding quotes.
+
+  $type =~ s/^"([^"]+)"/$1/;
+  $type =~ s/\$\*\*\$/, expanded/;
+
+  # Default may be quoted, and it may also have quotes that are required,
+  # if it is a string.
+
+  $default =~ s/^"(.*)"$/$1/;
+  $default =~ s/""/"/g;
+  $default = &handle_text($default);
+
+  push(@ONESECTION, "\nType: $type\@*\nDefault: $default\n\n");
+  }
+
+# Handle .startitems, .enditems, and .item
+
+elsif (/\.startitem/ || /\.enditem/) {}
+
+elsif (/\.item/)
+  {
+  $arg = $';
+  $arg =~ s/^\s*"//;
+  $arg =~ s/"\s*$//;
+  $arg = &dequote($arg);
+  $arg = &handle_text("\\**$arg**\\");
+
+  # If there are two .items in a row, we don't want to put in the
+  # separator line.
+
+#  push(@ONESECTION, "\n\@example\n");
+  push(@ONESECTION, "\n");
+  if (! $lastwasitem)
+    {
+    push(@ONESECTION, "_" x 75, "\n\n");
+    }
+#  push(@ONESECTION, "$arg\n\@end example\n\n");
+  push(@ONESECTION, "$arg\n\n");
+  $new_lastwasitem = 1;
+  }
+
+elsif (/\.option/)
+  {
+  chomp($arg = $');
+  $arg =~ s/^\s*//;
+  $arg = &dequote("-$arg");
+  $arg = &handle_text($arg);
+  }
+
+# Texinfo has no facility for emphasis bars.
+
+elsif (/\.em/) {}
+elsif (/\.nem/) {}
+
+# Just ignore any .(r)set directives pro tem (or maybe always!)
+
+elsif (/\.r?set/) {}
+
+# Ignore .space, .linelength, and .justify
+
+elsif (/\.space/ || /\.justify/ || /\.linelength/) {}
+
+# Found an SGCAL directive that isn't dealt with. Oh dear.
+# Turn the embarrassing characters into question marks and
+# output it in an emphasized way.
+
+else
+  {
+  tr/@{}/???/;
+  push(@ONESECTION, "\n\>>>>>>> $_\n") if ! /^\.( |$)/;
+  }
+
+$lastwasitem = $new_lastwasitem;
+}
+
+
+
+##################################################
+#             Flush a section                    #
+##################################################
+
+# $section_name is the name of the next section.
+# $current_section is the name of the one we have buffered up.
+# If it is unset, we are at the first section of a chapter.
+# $previous_node is the section we last flushed if it was a node.
+
+sub flush_section {
+
+# If there is no text in the section, omit it entirely. However, it
+# will have had a pointer set up at the start of the previous section.
+# Remember what to replace this with when the chapter gets flushed.
+
+my($skip) = 1;
+foreach $s (@ONESECTION)
+  {
+  if ($s !~ /^(\@cindex|\@section|\s*$)/) { $skip = 0; last }
+  }
+
+if ($skip)
+  {
+  pop @section_list;
+  $rewrite{$current_section} = $section_name;
+  @ONESECTION = ();
+  return;
+  }
+
+# There is data in the section: write it out to the chapter file
+
+if ($current_section)
+  {
+  printf ONECHAPTER ("\@node %s, %s, %s, %s\n",
+    &decomma($current_section), &decomma($section_name),
+    &decomma($previous_node), &decomma($current_up));
+  $previous_node = $current_section;
+  while(scalar(@ONESECTION))
+    { print ONECHAPTER shift(@ONESECTION); }
+  }
+else
+  {
+  while(scalar(@ONESECTION))
+    { push(@TOPSECTION, shift(@ONESECTION)); }
+  }
+}
+
+
+
+##################################################
+#          Handle a "subsection"                 #
+##################################################
+
+# A "subsection" is a set of options that must have their own
+# local menu. Do two passes; the first just collects the names
+# for the menu. This is called for .conf and .option items.
+
+sub handle_subsection{
+my($type) = $_[0];
+my($save_up) = $current_up;
+
+$current_up = $current_section? $current_section : $current_chapter;
+
+@sublist = ();
+@SUBBUFFER = ();
+
+while (<>)
+  {
+  last if /^\.end$type/;
+  push(@SUBBUFFER, $_);
+
+  # .conf takes the first non-space string as the name, but as there are
+  # duplicate confs in various parts of the spec, use the driver name to
+  # de-duplicate; .option takes the entire rest of arg as the name, but
+  # removes any sequence of ... because this disturbs TexInfo. Also, it
+  # turns @- into -.
+
+  if (/^\.$type\s+(\S+)(.*)/)
+    {
+    if ($type eq "conf")
+      {
+      $name = &handle_text($1);
+      $name .= " ($driver_name)" if ($driver_name ne "");
+      }
+    else
+      {
+      chomp($name = &handle_text("-$1$2"));
+      $name =~ s/\s*\.\.\.//g;
+
+      $name .= " ($driver_name)" if ($driver_name ne "");
+
+      # There seems to be a major problem in texinfo with the string "--".
+      # In the text it gets turned into a single hyphen. This happens if it
+      # is used as a menu item, but *not* as a node name. Exim has a command
+      # line option "--". With no special action, this appears in the menu
+      # as "-", but then the info software complains there is no node called
+      # "-". If we triple it in the menu it gets displayed OK, but building
+      # software complains about non-existent cross references etc.
+
+      # I have gone for the horrid kludge of turning it into "-<hyhen>"
+      # in the menus and nodes.
+
+      # Exim 4 has added --help, which has the same problem.
+
+      $name = "-<hyphen>" if ($name eq "--");
+      $name = "-<hyphen>help" if ($name eq "--help");
+      }
+    push(@sublist, $name);
+    }
+  }
+
+push (@ONESECTION, "\n\@sp 2\n\@menu\n");
+for ($i = 0; $i < scalar(@sublist); $i++)
+  {
+  $mitem = $sublist[$i];
+  $mitem =~ s/\@sc\{([^}]*)\}/\U$1/g;       # Get rid of small caps
+  $mitem =~ s/:/<colon>/g;                  # Get rid of colons
+  push (@ONESECTION, "* ${mitem}::\n");
+  }
+push (@ONESECTION, "\@end menu\n\n");
+
+$prevsub = $current_up;
+$processing_subsection = 1;
+while ($_ = shift(@SUBBUFFER))
+  {
+  if (/^\.$type\s+(\S+)/)
+    {
+    $name = shift @sublist;
+    $next = (scalar(@sublist))? $sublist[0] : "";
+    push @ONESECTION, sprintf("\@node %s, %s, %s, %s\n",
+      &decomma($name), &decomma($next), &decomma($prevsub),
+      &decomma($current_up));
+
+    if ($name eq "-<hyphen>")    # Fudge for Texinfo
+      {
+      push(@ONESECTION,
+          "\@findex $name\n",
+          "\@unnumberedsubsec --- option\n");
+      push(@ONESECTION,
+           "This option consists of two consecutive hyphens. It appears in\n",
+           "the menu as \"-<hyphen>\" because otherwise Texinfo gets\n",
+           "confused with its cross-referencing.\n");
+      }
+    elsif ($name eq "-<hyphen>help")    # Fudge for Texinfo
+      {
+      push(@ONESECTION,
+          "\@findex $name\n",
+          "\@unnumberedsubsec ---help option\n");
+      push(@ONESECTION,
+           "This option consists of \"help\" preceded by two consecutive\n" .
+           "hyphens. It appears in the menu as \"-<hyphen>help\" because\n" .
+           "otherwise Texinfo gets confused with its cross-referencing.\n");
+      }
+    else
+      {
+      push(@ONESECTION,
+          "\@findex $name\n",
+          "\@unnumberedsubsec $name option\n");
+      }
+
+    $prevsub = $name;
+    }
+
+  # Then handle as text or directive
+
+  if (substr($_, 0, 1) eq ".")
+    { handle_directive(); }
+  else
+    {
+    while($nextline = shift(@SUBBUFFER))
+      {
+      last if $nextline =~ /^(\.|\s*$)/;
+      $_ .= $nextline;
+      }
+    push(@ONESECTION, handle_text($_));
+    $_ = $nextline;
+    last if !defined($_);
+    redo;
+    }
+  }
+
+$processing_subsection = 0;
+$section_pending = 1;
+$current_up = $save_up;
+}
+
+
+
+
+##################################################
+#            Handle a single chapter             #
+##################################################
+
+sub handle_chapter{
+chop;
+($current_chapter) = /^\.chapter (.*)/;
+$current_chapter = &dequote($current_chapter);
+
+$current_chapter = $current_chapter;
+
+my($tmp) = $current_chapter;
+$tmp =~ s/\[\[\[\]\]\]/./;
+print STDERR "processing chapter: $tmp\n";
+
+# Remember the chapter name for the top-level menu
+
+push(@chapter_list, $current_chapter);
+
+# Open a temporary file to hold the chapter's text while collecting
+# all its sections for a chapter-level menu.
+
+$ONECHAPTER = "/tmp/ONECHAPTER.$$";
+open(ONECHAPTER, ">$ONECHAPTER") || die "Can't open $ONECHAPTER for writing";
+
+# Initialize for handling sections
+
+@section_list = ();
+%rewrite = ();
+@ONESECTION = ();
+@TOPSECTION = ();
+undef $current_section;
+undef $next_node;
+
+$processing_subsection = 0;
+
+$previous_node = $current_up = $current_chapter;
+$section_pending = 0;
+
+# Handle the .chapter directive as the first text of a section without
+# a section title.
+
+handle_directive();
+
+# Loop, handling each section. Assume they are sufficiently short that
+# we can buffer the text in store, in an array called ONESECTION, instead
+# of thrashing yet another file.
+
+while (<>)
+  {
+  last if /^\.chapter /;
+
+  # Handle a new section, preserving $_ (handle_text flattens it).
+  # It seems we cannot get a fullstop into a Texinfo node name; use a magic
+  # character string that gets turned back into a dot by the post-processing.
+
+  if (/^\.section\s+/)
+    {
+    $save = $_;
+    $section_name = $';
+    $section_name =~ s/(\s|\n)+$//;
+    $section_name =~ s/://;
+    $section_name = &handle_text($section_name);
+    flush_section();
+    push(@section_list, $section_name);
+    $current_section = $section_name;
+    $next_node = $section_name if !$next_node;
+    $section_pending = 0;
+    $_ = $save;
+    }
+
+  # The .startconf macro introduces a set of .conf's which must have
+  # their own local set of menus. Suspend processing the section while
+  # we sort out the menu and copy their data. This is all done in a
+  # subroutine that is shared with options.
+
+  elsif (/^\.startconf/)
+    {
+    handle_subsection("conf");
+    next;
+    }
+
+  elsif (/^\.startoption/)
+    {
+    handle_subsection("option");
+    next;
+    }
+
+  # Deal with the actual data lines; if there's a section pending
+  # start a new section on hitting some text. We hope this happens
+  # only once per chapter...
+
+  if (substr($_, 0, 1) eq ".")
+    {
+    handle_directive();
+    }
+  else
+    {
+    while($nextline = <>)
+      {
+      last if $nextline =~ /^(\.|\s*$)/;
+      $_ .= $nextline;
+      }
+    if ($section_pending && !/^\s*$/)
+      {
+      $section_name = (defined $current_section)?
+        "$current_section (continued)" :
+        "$current_chapter (continued)" ;
+      flush_section();
+      push(@section_list, $section_name);
+      $current_section = $section_name;
+      $next_node = $section_name if !$next_node;
+      $section_pending = 0;
+      }
+
+    push(@ONESECTION, handle_text($_));
+    $_ = $nextline;
+    last if !defined($_);
+    redo;
+    }
+  }
+
+# Flush any pending text, making its next field null.
+# and fudging section_name for the final section of the previous.
+
+$section_name = "";
+flush_section();
+
+# Set up section name as the start of the next chapter
+
+$section_name = "Concept Index" if (!$doing_filter);
+
+if (defined $_ && /^\.chapter (.*)/)
+  {
+  $section_name = $1;
+  $section_name = &dequote($section_name);
+  }
+$next_node = $section_name;
+
+# Write out the chapter to the CHAPTERS file, sticking the chapter
+# menu after the text that came before the first section heading. This
+# will always at least contain the chapter title.
+
+printf CHAPTERS ("\@node %s, %s, %s, Top\n",
+  &decomma($current_chapter), &decomma($next_node),
+  &decomma($previous_chapter));
+
+# The pre-section stuff; if we hit an @end menu line, it is the menu of
+# a "subsection" before the first section. In that case, we need to put
+# the chapter's menu one the end of it, and then resume with the rest of
+# the TOPSECTION data afterwards. We also need to thread together this
+# "subsection"s nodes because they are all at the same level under the
+# chapter.
+
+$in_menu = 0;
+while(scalar(@TOPSECTION))
+  {
+  $s = shift(@TOPSECTION);
+  if ($s =~ /^\@end menu/)
+    {
+    $in_menu = 1;
+    last;
+    }
+  print CHAPTERS $s;
+  }
+
+# Menu for sections
+
+undef $next_actual_section;
+undef $point_back;
+
+if (scalar(@section_list))
+  {
+  print CHAPTERS "\n\@sp 2\n\@menu\n" if ! $in_menu;
+  $next_actual_section = $section_list[0];
+  for ($i = 0; $i < scalar(@section_list); $i++)
+    {
+    $section_name = $section_list[$i];
+    $section_name =~ s/\@sc\{([^}]*)\}/\U$1/g;
+    print CHAPTERS "* ${section_name}::\n";
+    }
+  $in_menu = 1;
+  }
+print CHAPTERS "\@end menu\n\n" if $in_menu;
+
+# Remainder of topsection; we must arrange that the final @node in
+# it (which will have a blank "next" field) actually points on to
+# the next section, if any. If this happens, then the next section
+# must point back to the final @node.
+
+while(scalar(@TOPSECTION))
+  {
+  $s = shift(@TOPSECTION);
+  if ($next_actual_section && $s =~
+         /^\@node\s+([^,]+),\s*,\s*([^,]*),\s*(.*)/)
+    {
+    my($t1, $t2, $t3) = ($1, $2, $3);    # So can be decomma'd
+    printf CHAPTERS ("\@node %s, %s, %s, %s\n", &decomma($t1),
+      &decomma($next_actual_section), &decomma($t2), &decomma($t3));
+    $point_back = $1;
+    }
+  else { print CHAPTERS $s; }
+  }
+
+close(ONECHAPTER);
+open(ONECHAPTER, "$ONECHAPTER") || die "Can't open $ONECHAPTER for reading";
+
+# While copying the chapter data, check for node references to empty
+# sections that got omitted and correct them, and correct the prev pointer
+# in the first node if necessary.
+
+while ($buff = <ONECHAPTER>)
+  {
+  foreach $key (keys %rewrite)
+    {
+    $buff =~ s/$key/$rewrite{$key}/;
+    }
+  if ($point_back && $buff =~ /^\@node\s+([^,]+),\s*([^,]*),\s*([^,]*),\s*(.*)/)
+    {
+    my($t1, $t2, $t4) = ($1, $2, $4);   # so can be decomma'd
+    printf CHAPTERS ("\@node %s, %s, %s, %s\n", &decomma($t1),
+      &decomma($t2), &decomma($point_back), &decomma($t4));
+    undef $point_back;
+    }
+  else { print CHAPTERS $buff; }
+  }
+
+$previous_chapter = $current_chapter;
+
+close(ONECHAPTER);
+unlink($ONECHAPTER);
+}
+
+
+
+##################################################
+#                Main Program                    #
+##################################################
+
+# This is a two-pass algorithm. The first pass goes through and gets the
+# variable names for cross references. The second pass does the real work,
+# but we can't just read through doing the translation in one pass. We need
+# to know the list of chapters in order to build a top-level menu, and for
+# each chapter we need to know the sections in order to build a section
+# menu. Consequently, make use of temporary files to buffer things.
+
+# This script is used for the filter document and the overview as well;
+# flags tell it if it is doing one of them.
+
+$doing_filter = 0;
+$skip_else = 0;
+$in_itemize = 0;
+$lastwasitem = 0;
+
+$chapter_number = 0;
+$section_number = 0;
+
+if ($#ARGV >= 0 && $ARGV[0] eq "-filter")
+  {
+  $doing_filter = 1;
+  shift @ARGV;
+  }
+
+# First pass: Just fish out variable settings. Save the arguments so that
+# they can be reinstated for a second pass.
+
+print STDERR "Scanning for references\n";
+@save_argv = @ARGV;
+
+# Pick up any .set directives right at the very start
+
+while (<>)
+  {
+  last if ! /^\.set\s+(\S+)\s+(.+)$/;
+  $name = $1;
+  $value = $2;
+  $value =~ s/^\"?(.*?)\"?\s*$/$1/;
+  $references{$name} = $value;
+  }
+
+# Now skip everything before the first .chapter except for
+# .index lines that set up indirections. Save these so that
+# the relevant index entries can be duplicated.
+
+while (<>)
+  {
+  if (/^\.chapter\s+(.+)$/)
+    {
+    $chapter_number++;
+    $section_number = 0;
+    $current_chapter = $1;
+    $current_chapter = $current_chapter;
+    $current_section = "";
+    last;
+    }
+
+  if (/^\.index\s+([^\$]+)\s+\$it\{see\s+([^}]+)\}\s*$/)
+    {
+    $indirections{"$2"} = $1;
+    }
+  }
+
+# Do the business
+
+while (<>)
+  {
+  if (/^\.chapter\s+(.+)$/)
+    {
+    $current_chapter = $1;
+    $current_chapter = &dequote($current_chapter);
+    $current_section = "";
+    }
+  elsif (/^\.section\s+(.+)$/)
+    {
+    $current_section = $1;
+    $current_section = &dequote($current_section);
+    $current_section =~ s/://;
+    }
+  elsif (/^\.r?set\s+(\S+)\s+(.+)$/ && $1 ne "runningfoot")
+    {
+    $name = $1;
+    $value = $2;
+
+    # Only set the first time. This handles a few special cases in part2
+    # which is included in the filter text as well.
+
+    if (!exists($references{$name}))
+      {
+      $value =~ s/^\"?(.*?)\"?\s*$/$1/;
+      $value =~ s/~~chapter\./~~chapter****/;
+      $value =~ s/~~chapter/$current_chapter/;
+      $value =~ s/~~section/$current_section/;
+      $references{$name} = $value;
+      }
+    }
+  }
+
+$final_chapter = defined($current_chapter)? $current_chapter : "";
+
+# Reinstate ARGV with the list of files and proceed to the main pass
+
+@ARGV = @save_argv;
+
+# $asis is set true when processing .display asis blocks, to stop
+# characters getting interpreted.
+
+$asis = 0;
+
+# $indisplay is set true while processing .display blocks, to stop
+# .newlines being handled therein (adding @* wrecks alignment)
+
+$indisplay = 0;
+
+# $tab is set to the value of the tab stop - only one stop is ever used
+# in the Exim source.
+
+$tab = 0;
+
+# Current driver name, for disambiguating nodes
+
+$driver_name = "";
+
+# $section_pending is set if a new section is to be started on hitting
+# any data lines.
+
+$section_pending = 0;
+
+# Open a file to buffer up the entire set of chapters
+
+$CHAPTERS = "/tmp/CHAPTERS.$$";
+open(CHAPTERS, ">$CHAPTERS") || die "Can't open $CHAPTERS for writing";
+
+# Skip everything before the first .chapter
+
+while (<>) { last if /^\.chapter /; }
+
+# Loop, handling each chapter
+
+$current_up = "";
+$previous_chapter = "Top";
+$previous_node = "Top";
+
+$chapter_number = 0;
+$section_number = 0;
+
+while (defined ($_) && /^\.chapter /)
+  {
+  handle_chapter();
+  }
+
+# Output the stuff at the start of the file
+
+print "\\input texinfo\n";
+
+print "\@set{wmYear} 2003\n";
+print "\@set{wmAuthor} Philip Hazel\n";
+print "\@set{wmAuthor_email} <ph10\@\@cus.cam.ac.uk>\n";
+print "\@set{COPYRIGHT1} Copyright \@copyright{} \@value{wmYear} University of Cambridge\n";
+
+print "\@c %**start of header\n";
+
+if (!$doing_filter)
+  {
+  print "\@setfilename spec.info\n";
+  print "\@settitle Exim Specification\n";
+  }
+else
+  {
+  print "\@setfilename filter.info\n";
+  print "\@settitle Exim Filter Specification\n";
+  }
+
+print "\@paragraphindent 0\n";
+print "\@c %**end of header\n\n";
+
+
+print "\@titlepage\n";
+print "\@title The Exim Mail Transfer Agent\n";
+print "\@author \@value{wmAuthor}\n";
+
+print "\@page\n";
+print "\@vskip 0pt plus 1filll\n";
+
+print "Permission is granted to make and distribute verbatim copies of this manual provided the\n";
+print "copyright notice and this permission notice are preserved on all copies.\n";
+
+print "\@sp2\n";
+print "\@value{COPYRIGHT1}\@*\n";
+
+print "\@end titlepage\n\n";
+
+# Output the top-level node and its introductory blurb
+
+print "\@node       Top,       $chapter_list[0], (dir), (dir)\n";
+print "\@top\n";
+
+if (!$doing_filter)
+{
+print <<End;
+The Exim Mail Transfer Agent\@*
+****************************
+
+The specification of the Exim Mail Transfer Agent is converted mechanically
+into Texinfo format from its original marked-up source. Some typographic
+representations are changed, chapters and sections cannot be numbered, and
+Texinfo lacks the ability to mark updated parts of the specification with
+change bars.
+
+Because the chapters and sections are unnumbered, cross references are set to
+their names. This makes the English a bit odd, with phrases like \`see chapter
+\"Retry configuration\"\' but it seemed very cumbersome to change this to \`see
+the chapter entitled \"Retry configuration\"\' each time.
+
+Each chapter, section, and configuration option has been placed in a separate
+Texinfo node. Texinfo doesn\'t allow commas, colons, or apostrophes in node
+names, which is a rather nasty restriction. I have arranged not to use colons
+or apostrophes in section titles, but cannot bring myself to omit them from
+titles such as \"The foo, bar and baz commands\". For the corresponding node
+names I have just used multiple occurrences of \"and\", though it looks very
+ugly.
+
+If a chapter or section continues after a list of configuration options that is
+not in a new section, a new node is started, using the chapter\'s or section\'s
+name plus \`(continued)\'. The \`Up\' operation from a section or configuration
+option returns to the start of the current chapter; the \`Up\' operation at a
+chapter start returns to the top of the document; the \`Up\' in a list of
+configuration options within a section returns to the top of that section.
+
+A number of drivers have options with the same name, so they have been
+disambiguated by adding the name of the driver to its option names in order to
+create node names. Thus, for example, the specification of the \`command\'
+options of the \`lmtp\' and \`pipe\' transports are in nodes called \`command
+(lmtp)\' and \`command (pipe)\', respectively.
+
+End
+}
+
+else
+{
+print <<End;
+Filtering with the Exim Mail Transfer Agent\@*
+*******************************************
+
+The specifications of the Exim Mail Transfer Agent\'s filtering facility is
+converted mechanically into Texinfo format from its original marked-up source.
+Some typographic representations are changed, chapters and sections cannot be
+numbered, and Texinfo lacks the ability to mark updated parts of the
+specification with change bars.
+
+Because the chapters and sections are unnumbered, cross references are set to
+their names. This makes the English a bit odd, with phrases like \`see section
+\"Multiple personal mailboxes\"\' but it seemed very cumbersome to change this to
+\`see the section entitled \"Multiple personal mailboxes\"\' each time.
+
+End
+}
+
+# Output the top-level menu
+
+print "\@menu\n";
+
+while (scalar(@chapter_list))
+  {
+  $name = &decomma(shift(@chapter_list));
+  print "* ${name}::\n";
+  }
+print "* Concept Index::\n" if (!$doing_filter);
+print "\@end menu\n\n";
+
+# Copy the chapters, then delete the temporary file
+
+close(CHAPTERS);
+open(CHAPTERS, "$CHAPTERS") || die "Can't open $CHAPTERS for reading";
+print $buff while($buff = <CHAPTERS>);
+close(CHAPTERS);
+unlink($CHAPTERS);
+
+# Output the finishing off stuff
+
+if (!$doing_filter)
+  {
+  print "\@node Concept Index, , $final_chapter, Top\n";
+  print "\@chapter Concept Index\n\@printindex cp\n";
+  print "\@chapter Function Index\n\@printindex fn\n";
+  }
+print "\@contents\n";
+print "\@bye\n";
+
+# End
diff --git a/doc/doc-src/FAQ.src b/doc/doc-src/FAQ.src
new file mode 100644 (file)
index 0000000..9ad5cf9
--- /dev/null
@@ -0,0 +1,7015 @@
+## $Cambridge: exim/doc/doc-src/FAQ.src,v 1.1 2004/10/07 15:04:35 ph10 Exp $
+##
+## This file is processed by Perl scripts to produce an ASCII and an HTML
+## version. Lines starting with ## are omitted. The markup used with paragraphs
+## is as follows:
+##
+## Markup       User for           HTML            Text
+## ------------------------------------------------------
+##  \...\       option          fixed-pitch     "quoted"
+## \$...$\      variable         $italic         $plain
+## \*...*\      titles, quotes    italic        "quoted"
+## \(...)\      file name         italic          plain
+## \[...]\      replaceable      <italic>        <plain>
+## \?...?\      URL                 URL           plain
+## \^...^\      Unix command      italic          plain
+## \%...%\      Exim driver        bold         "quoted"
+## \^^.^^\      C function         bold           plain
+## ::...::      header name       italic:         plain:
+## //...//      domain            italic          plain
+## \/.../\      local part        italic          plain
+## \"..."\      literal         fixed-pitch     "quoted"
+## \\...\\      SMTP, build     small caps        caps
+## \**...**\    warn, item        bold            plain
+## \-...-\      cmd option       -italic         -plain
+## \#           hard space        &nbsp;          space
+##
+## ``...''      quoted string  &#147;...&#148;    "..."
+##
+## @\ is used when a real backslash is required
+##
+## In addition, sequences of not blank lines that start with ==> are displayed
+## in fixed-pitch with no further interpretation. A line containing only [[br]]
+## is removed from the text version, but turned into <br> in the HTML version.
+##
+## The starts of sections and of questions and answers are automatically
+## detected by the scripts.
+##
+##
+THE EXIM FAQ
+------------
+
+This is the FAQ for the Exim Mail Transfer Agent. Many thanks to the many
+people who provided the original information. This file would be amazingly
+cluttered if I tried to list them all. Suggestions for corrections,
+improvements, and additions are always welcome.
+
+This version of the FAQ applies to Exim 4.00 and later releases. It has been
+extensively revised, and material that was relevant only to earlier releases
+has been removed. As this caused some whole sections to disappear, I've taken
+the opportunity to re-arrange the sections and renumber everything except the
+configuration samples.
+
+References of the form Cnnn, Fnnn, Lnnn, and Snnn are to the sample
+configuration, filter, \^^local_scan()^^\, and ``useful script'' files. These
+are hyperlinked from the HTML version of this FAQ. They can also be found in
+the separately distributed directory called \(config.samples)\. The primary
+location is
+
+\?ftp://ftp.csx.cam.ac.uk/pub/software/email/exim/exim4/config.samples.tar.gz?\
+\?ftp://ftp.csx.cam.ac.uk/pub/software/email/exim/exim4/config.samples.tar.bz2?\
+
+There are brief descriptions of these files at the end of this document.
+
+Philip Hazel
+Last update: 31-March-2004
+
+
+The FAQ is divided into the following sections:
+
+  0. General Debugging
+  1. Building and Installing
+  2. Routing in general
+  3. Routing to remote hosts
+  4. Routing for local delivery
+  5. Filtering
+  6. Delivery
+  7. Policy controls
+  8. Rewriting addresses
+  9. Headers
+ 10. Performance
+ 11. Majordomo
+ 12. Fetchmail
+ 13. Perl
+ 14. Dial-up and ISDN
+ 15. UUCP
+ 16. Modifying message bodies
+ 17. Encryption (TLS/SSL)
+ 20. Millennium
+ 50. Miscellaneous
+ 91. Mac OS X
+ 92. FreeBSD
+ 93. HP-UX
+ 94. BSDI
+ 95. IRIX
+ 96. Linux
+ 97. Sun sytems
+ 98. Configuration cookbook
+ 99. List of sample configurations
+
+
+
+0. GENERAL DEBUGGING
+
+Q0001: Exim is crashing. What is wrong?
+
+A0001: Exim should never crash. The author is always keen to know about
+       crashes, so that they can be diagnosed and fixed. However, before you
+       start sending me email, please check that you are running the latest
+       release of Exim, in case the problem has already been fixed. The
+       techniques described below can also be useful in trying to pin down
+       exactly which circumstances caused the crash and what Exim was trying to
+       do at the time. If the crash is reproducable (by a particular message,
+       say) keep a copy of that message.
+
+
+Q0002: Exim is not working. What is wrong? How can I check what it is doing?
+
+A0002: Exactly how is it not working? Check the more specific questions in the
+       other sections of this FAQ. Some general techniques for debugging are:
+
+       (1) Look for information in Exim's log files. These are in the \(log)\
+           directory in Exim's spool directory, unless you have configured a
+           different path for them. Serious operational problems are reported
+           in paniclog.
+
+       (2) If the problem involves the delivery of one or more messages, try
+           forcing a delivery with the \-M-\ option and also set the \-d-\
+           option, to cause Exim to output debugging information. For example:
+
+==>          exim -d -M 0z6CXU-0005RR-00
+
+           The output is written to the standard error stream. You need to have
+           admin privileges to use \-M-\ and \-d-\.
+
+       (3) If the problem involves incoming SMTP mail, try using the \-bh-\
+           option to simulate an incoming connection from a specific host,
+           for example:
+
+==>          exim -bh 10.9.8.7
+
+           This goes through the motions of an SMTP session, without actually
+           accepting a message. Information about various policy checks is
+           output. You will need to know how to pretend to be an SMTP client.
+
+       (4) If the problem involves lack of recognition or incorrect handling
+           of local addresses, try using the \-bt-\ option with debugging turned
+           on, to see how Exim is handling the address. For example,
+
+==>          exim -d -bt z6abc
+
+           shows you how it would handle the local part \"z6abc"\.
+
+
+Q0003: What does the error \*Child process of address_pipe transport returned
+       69 from command xxx*\ mean?
+
+A0003: It means that when a transport called \%address_pipe%\ was run to pass an
+       email message by means of a pipe to another process running the command
+       xxx, the return code from that command was 69, which indicates some kind
+       of error (the success return code is 0).
+
+       The most common meaning of exit code 69 is ``unavailable'', and this often
+       means that when Exim tried to run the command \(xxx)\, it failed. One
+       cause of this might be incorrect permissions on the file containing the
+       command. See also Q0026.
+
+
+Q0004: My virtual domain setup isn't working. How can I debug it?
+
+A0004: You can use an exim command with \-d-\ to get it to show you how it is
+       processing addresses. You don't actually need to send a message; use the
+       \-bt-\ option like this:
+
+==>      exim -d -bt localpart@virtualhost
+
+       This will show you which routers it is using. If the problem appears
+       to be with the expansion of an option setting, you can use the
+       \debug_print\ option on a router to get Exim to output the expanded
+       string values as it goes along.
+
+
+Q0005: Why is Exim not rejecting incoming messages addressed to non-existent
+       users at SMTP time?
+
+A0005: This is controlled by the ACL that is run for each incoming RCPT
+       command. It is defined by the \acl_smtp_rcpt\ option. You can check this
+       part of your configuration by using the \-bh-\ option to run a simulated
+       SMTP session, during which Exim will tell you what things it is
+       checking.
+
+
+Q0006: I've put an entry for \"*.my.domain"\ in a DBM lookup file, but it isn't
+       getting recognized.
+
+A0006: You need to request ``partial matching'' by setting the search type to
+       \partial-dbm\ in order for this to work.
+
+
+Q0007: I've put the entry \"*@domain.com"\ in a lookup database, but it isn't
+       working. The expansion I'm using is:
+
+==>      ${lookup{${lc:$sender_address}}dbm{/the/file} ...
+
+A0007: As no sender address will ever be //*@domain.com// this will indeed have
+       no effect as it stands. You need to tell Exim that you want it to look
+       for defaults after the normal lookup has failed. In this case, change the
+       search type from \"dbm"\ to \"dbm*@"\. See the section on \*Default values in
+       single-key lookups*\ in the chapter entitled \*File and database
+       lookups*\ in the Exim manual.
+
+
+Q0008: If I run \"./exim -d -bt user@domain"\ all seems well, but when I send
+       a message from my User Agent, it does not arrive at its destination.
+
+A0008: Try sending a message directly to Exim by typing this:
+
+==>      exim -v user@domain
+         <some message, could be empty>
+         .
+
+       If the message gets delivered to a remote host, but never arrives at its
+       final destination, then the problem is at the remote host. If, however,
+       the message gets through correctly, then the problem may be between your
+       User Agent and Exim. Try setting Exim's \log_selector\ option to include
+       \"+arguments"\, to see with which arguments the UA is calling Exim.
+
+
+Q0009: What does \*no immediate delivery: too many messages received in one SMTP
+       connection*\ mean?
+
+A0009: An SMTP client may send any number of messages down a single SMTP
+       connection to a server. Initially, an Exim server starts up a delivery
+       process as soon as a message is received. However, in order not to start
+       up too many processes when lots of messages are arriving (typically
+       after a period of downtime), it stops doing immediate delivery after a
+       certain number of messages have arrived down the same connection. The
+       threshold is set by \smtp_accept_queue_per_connection\, and the default
+       value is 10. On large systems, the value should be increased. If you are
+       running a dial-in host and expecting to get all your mail down a single
+       SMTP connection, then you can disable the limit altogether by setting
+       the value to zero.
+
+
+Q0010: Exim puts \*for \[address]\*\ in the ::Received:: headers of some, but not all,
+       messages. Is this a bug?
+
+A0010: No. It is deliberate. Exim inserts a ``for'' phrase only if the incoming
+       message has precisely one recipient. If there is more than one
+       recipient, nothing is inserted. The reason for this is that not all
+       recipients appear in the ::To:: or ::Cc:: headers, and it is considered a
+       breach of privacy to expose such recipients to the others. A common
+       case is when a message has come from a mailing list.
+
+
+Q0011: Instead of \^exim_dbmbuild^\, I'm using a homegrown program to build DBM
+       (or cdb) files, but Exim doesn't seem to be able to use them.
+
+A0011: Exim expects there to be a binary zero value on the end of each key used
+       in a DBM file if you use the \"dbm"\ lookup type, but not for the \"dbmnz"\
+       lookup type or for the keys of a cdb file. Check that you haven't
+       slipped up in this regard.
+
+
+Q0012: Exim is unable to route to any remote domains. It doesn't seen to be
+       able to access the DNS.
+
+A0012: Try running \"exim -d+resolver -bt \[remote address]\"\. The \-d-\
+       options turns on debugging output, and the addition of \"+resolver"\
+       will make it show the resolver queries it is building and the results of
+       its DNS queries. If it appears unable to contact any name servers, check
+       the contents and permissions of \(/etc/resolv.conf)\.
+
+
+Q0013: What does the error message \*transport system_aliases: cannot find
+       transport driver "redirect" in line 92*\ mean?
+
+A0013: \%redirect%\ is a router, not a transport. You have put a configuration
+       for a router into the transports section of the configuration file.
+
+
+Q0014: Exim is timing out after receiving and responding to the DATA command
+       from one particular host, and yet the client host also claims to be
+       timing out. This seems to affect only certain messages.
+
+A0014: This kind of problem can have many different causes.
+
+       (1) This problem has been seen with a network that was dropping all
+       packets over a certain size, which mean that the first part of the SMTP
+       transaction worked, but when the body of a large message started
+       flowing, the main data bits never got through the network. See also
+       Q0017.
+
+       (2) This can also happen if a host has a broken TCP stack and won't
+       reassemble fragmented datagrams.
+
+       (3) A very few ISDN lines have been seen which failed when certain data
+       patterns were sent through them, and replacing the routers at both end
+       of the link did not fix things. One of them was triggered by more than 4
+       X's in a row in the data.
+
+
+Q0015: What does the message \*Socket bind() to port 25 for address (any)
+       failed: address already in use*\ mean?
+
+A0015: You are trying to run an Exim daemon when there is one already running -
+       or maybe some other MTA is running, or perhaps you have an SMTP line in
+       \(/etc/inetd.conf)\ which is causing \(inetd)\ to listen on port 25.
+
+
+Q0016: I've set \"verify = header_syntax"\ in my ACL, but this causes Exim to
+       complain about header lines like \"To: Work: Jim <jims@email>,
+       Home: Bob <bobs@email>"\ which look all right to me. Is this a bug?
+
+A0016: No. Header lines such as ::From::, ::To::, etc., which contain addresses, are
+       structured, and have to be in a specific format which is defined in RFC
+       2822. Unquoted colons are not allowed in the ``phrase'' part of an email
+       address (they are OK in other headers such as ::Subject::). The correct
+       form for that header is
+
+==>      To: "Work: Jim" <jims@email>, "Home: Bob" <bobs@email>
+
+       You will sometimes see unquoted colons in ::To:: and ::Cc:: headers, but only
+       in connection with name lists (called ``groups''), for example:
+
+==>      To: My friends: X <x@y.x>, Y <y@w.z>;,
+             My enemies: A <a@b.c>, B <b@c.d>;
+
+       Each list must be terminated by a semicolon, as shown.
+
+
+Q0017: Whenever Exim tries to deliver a specific message to a particular
+       server, it fails, giving the error \*Remote end closed connection after
+       data*\ or \*Broken pipe*\ or a timeout. What's going on?
+
+A0017: \*Broken pipe*\ is the error you get on some OS when the remote host just
+       drops the connection. The alternative is \*connection reset by peer*\.
+       There are many potential causes. Here are some of them (see also Q0068):
+
+       (1) There are some firewalls that fall over on binary zero characters
+       in email. Have a look, e.g. with \"hexdump -c mymail | tail"\ to see if
+       your mail contains any binary zero characters.
+
+       (2) There are broken SMTP servers around that just drop the connection
+       after the data has been sent if they don't like the message for some
+       reason (e.g. it is too big) instead of sending a 5xx error code. Have
+       you tried sending a small message to the same address?
+
+       It has been reported that some releases of Novell servers running NIMS
+       are unable to handle lines longer than 1024 characters, and just close
+       the connection. This is an example of this behaviour.
+
+       (3) If the problem occurs right at the start of the mail, then it could
+       be a network problem with mishandling of large packets. Many emails are
+       small and thus appear to propagate correctly, but big emails will
+       generate big IP datagrams.
+
+       There have been problems when something in the middle of the network
+       mishandles large packets due to IP tunnelling. In a tunnelled link, your
+       IP datagrams gets wrapped in a larger datagram and sent over a network.
+       This is how virtual private networks (VPNs), and some ISP transit
+       circuits work. Since the datagrams going over the tunnel require a
+       larger packet size, the tunnel needs a bigger maximum transfer unit
+       (MTU) in the network handling the tunnelled packets. However, MTUs
+       are often fixed, so the tunnel will try to fragment the packets.
+
+       If the systems outside the tunnel are using path MTU discovery, (most
+       Sun Sparc Solaris machines do by default), and set the DF (don't
+       fragment) bit because they don't send packets larger than their \(local)\
+       MTU, then ICMP control messages will be sent by the routers at the
+       ends of the tunnel to tell them to reduce their MTU, since the tunnel
+       can't fragment the data, and has to throw it away. If this mechanism
+       stops working, e.g. a firewall blocks ICMP, then your host never
+       knows it has hit the maximum path MTU, but it has received no ACK on
+       the packet either, so it continues to resend the same packet and the
+       connection stalls, eventually timing out.
+
+       You can test the link using pings of large packets and see what works:
+
+==>     ping -s host 2048
+
+       Try reducing the MTU on the sending host:
+
+==>     ifconfig le0 mtu 1300
+
+       Alternatively, you can reduce the size of the buffer Exim uses for SMTP
+       output by putting something like
+
+==>      DELIVER_OUT_BUFFER_SIZE=512
+
+       in your \(Local/Makefile)\ and rebuilding Exim (the default is 8192).
+       While this should not in principle have any effect on the size of
+       packets sent, in practice it does seem to have an effect on some OS.
+
+       You can also try disabling path MTU discovery on the sending host. On
+       Linux, try:
+
+==>      echo 1 >/proc/sys/net/ipv4/ip_no_pmtu_disc
+
+       For a general discussion and information about other operating systems, see
+       \?http://www.netheaven.com/pmtu.html?\. If disabling path MTU discovery
+       fixes the problem, try to find the broken or misconfigured
+       router/firewall that swallows the ICMP-unreachable packets. Increasing
+       timeouts on the receiving host will not work around the problem.
+
+
+Q0018: Why do messages not get delivered down the same connection when I do
+       something like: \"exim -v -R @aol.com"\? For other domains, I do this and
+       I see the appropriate \*waiting for passed connections to get used*\
+       messages.
+
+A0018: Recall that Exim does not keep separate queues for each domain, but
+       operates in a distributed fashion. Messages get into its `waiting for
+       host x' hints database only when a delivery has been tried, and has had
+       a temporary error. Here are some possibilities:
+
+       (1) The messages to \(aol.com)\ got put in your queue, but no previous
+       delivery attempt occured before you did the \-R-\. This might have been
+       because of your settings of \queue_only_load\, \smtp_accept_queue\, or any
+       other option that caused no immediate delivery attempt on arrival. If
+       this is the case, you can try using \-qqR-\ instead of \-R-\.
+
+       (2) You have set \connection_max_messages\ on the smtp transport, and
+       that limit was reached. This would show as a sequence of messages
+       down one connection, then another sequence down a new connection, etc.
+
+       (3) Exim tried to pass on the SMTP connection to another message, but
+       that message was in the process of being delivered to \(aol.com)\ by some
+       other process (typically, a normal queue runner). This will break the
+       sequence, though the other delivery should pass its connection on to
+       other messages if there are any.
+
+       (4) The folk at \(aol.com)\ changed the MX records so the host names have
+       changed - or a new host has been added. I don't know how likely this is.
+
+       (5) Exim is not performing as it should in this regard, for some reason.
+       Next time you have mail queued up for \(aol.com)\, try running
+
+==>      exim_dumpdb /var/spool/exim wait-remote_smtp
+
+       to see if those messages are listed among those waiting for the relevant
+       \(aol.com)\ hosts.
+
+
+Q0019: There seems to be a problem in the string expansion code: it doesn't
+       recognize references to headers such as \"${h_to}"\.
+
+A0019: The only valid syntax for header references is (for example) \"$h_to:"\
+       because header names are permitted by RFC 2822 to contain a very wide
+       range of characters. A colon (or white space) is required as the
+       terminator.
+
+
+Q0020: Why do connections to my machine's SMTP port take a long time to respond
+       with the banner, when connections to other ports respond instantly? The
+       delay is sometimes as long as 30 seconds.
+
+A0020: These kinds of delay are usually caused by some kind of network problem
+       that affects outgoing calls made by Exim at the start of an incoming
+       connection. Configuration options that cause outgoing calls are:
+
+       (1) \rfc1413_hosts\ and \rfc1413_query_timeout\ (for \*ident*\ calls).
+           Firewalls sometimes block ident connections so that they time out,
+           instead of refusing them immediately. This can cause this problem.
+           See Q5023 for a discussion of the usefulness of \*ident*\.
+
+       (2) The \host_lookup\ option, the \host_reject_connection\ option, or a
+           condition in the ACL that runs at connection time requires the
+           remote host's name to be looked up from its IP address. Sometimes
+           these DNS lookups time out. You can get this effect with ACL
+           statements like this:
+
+==>          deny  hosts = *.x.example
+
+           If at all possible, you should use IP addresses instead of host
+           names in blocking lists in order to to avoid this problem.
+
+       You can use the \-bh-\ option to get more information about what is
+       happening at the start of a connection. However, note that the \-bh-\
+       option does not provide a complete simulation. In particular, no
+       \*ident*\ checks are done, so it won't show up a delay problem that is
+       related to (1) above.
+
+
+Q0021: What does \*failed to create child process to send failure message*\ mean?
+       This is a busy mail server with \smtp_accept_max\ set to 500, but this
+       problem started to occur at about 300 incoming connections.
+
+A0021: Some message delivery failed, and when Exim wanted to send a bounce
+       message, it was unable to create a process in which to do so. Probably
+       the limit on the maximum number of simultaneously active processes has
+       been reached. Most OS have some means of increasing this limit, and in
+       some operating systems there is also a limit per uid which can be
+       varied.
+
+
+Q0022: What does \*No transport set by system filter*\ in a log line mean?
+
+A0022: Your system filter contains a \"pipe"\ or \"save"\ or \"mail"\ command,
+       but you have not set the corresponding option which specifies which
+       transport is to be used. You need to set whichever of
+       \system_filter_pipe_transport\, \system_filter_file_transport\ or
+       \system_filter_reply_transport\ is relevant.
+
+
+Q0023: Why is Exim refusing to relay, saying \*failed to find host name from IP
+       address*\ when I have the sender's IP address in an ACL condition? My
+       configuration contains this ACL statement:
+
+==>      accept hosts = lsearch;/etc/mail/relaydomains:192.168.96.0/24
+
+A0023: When checking a host list, the items are tested in left-to-right
+       order. The first item in your list is a lookup on the incoming host's
+       name, so Exim has to determine the name from the incoming IP address in
+       order to perform the test. If it can't find the host name, it can't do
+       the check, so it gives up. You would have discovered what was going
+       on if you had run a test such as
+
+==>      exim -bh 192.168.96.131
+
+       The solution is to put all explicit IP addresses first in the list.
+       Alternatively, you can split the ACL statement into two like this:
+
+==>      accept hosts = lsearch;/etc/mail/relaydomains
+         accept hosts = 192.168.96.0/24
+
+       If the host lookup fails, the first \"accept"\ fails, but then the
+       second one is considered.
+
+
+Q0024: When I run \"exim -bd -q10m"\ I get \*PANIC LOG: exec of exim -q failed*\.
+
+A0024: This probably means that Exim doesn't know its own path so it can't
+       re-exec itself to do the first queue run. Check the output of
+
+==>      exim -bP exim_path
+
+
+Q0025: I can't seem to get a pipe command to run when I include a \"${if"\
+       expansion in it. This fails:
+
+==>      command = perl -T /usr/local/rt/bin/rtmux.pl \
+                     rt-mailgate helpdesk \
+                     ${if eq {$local_part}{rt} {correspond}{action}}
+
+A0025: You need some internal quoting in there. Exim expands each individual
+       argument separately. Because you have (necessarily) got spaces in your
+       \"${if"\ item, you have to quote that argument. Try
+
+==>      command = perl -T /usr/local/rt/bin/rtmux.pl \
+                     rt-mailgate helpdesk \
+                     "${if eq {$local_part}{rt} {correspond}{action}}"
+
+       \**Warning:**\ If command starts with an item that requires quoting,
+       you cannot just put it in quotes, because a leading quote means that the
+       entire option setting is being quoted. What you have to do is to quote
+       the entire value, and use internally escaped quotes for the ones you
+       really want. For example:
+
+==>      command = "\"${if ....}\" arg1 arg2"
+
+       Any backslashes in the expansion items will have to be doubled to stop
+       them being interpreted by the string reader.
+
+
+Q0026: I'm trying to get Exim to connect an alias to a pipe, but it always
+       gives error code 69, with the comment \*(could mean service or program
+       unavailable)*\.
+
+A0026: If your alias entry looks like this:
+
+==>      alias:  |"/some/command some parameters"
+
+       change it to look like this:
+
+==>      alias:  "|/some/command some parameters"
+
+
+Q0027: What does the error \*Spool file is locked*\ mean?
+
+A0027: This is not an error. All it means is that when an Exim delivery
+       process (probably started by a queue runner process) looked at a message
+       in order to start delivering it, it found that another Exim process was
+       already busy delivering it. On a busy system this is quite a common
+       occurrence. If you set \"-skip_delivery"\ in the \log_selector\ option,
+       these messages are omitted from the log.
+
+       The only time when this message might indicate a problem is if it is
+       repeated for the same message for a very long time. That would suggest
+       that the process that is delivering the message has somehow got stuck.
+
+
+Q0028: Exim is reporting IP addresses as 0.0.0.0 or 255.255.255.255 instead of
+       their correct values. What's going on?
+
+A0028: You are using a version of Exim built with gcc on an IRIX box.
+       See Q9502.
+
+
+Q0029: I can't seem to figure out why PAM support doesn't work correctly.
+
+A0029: There is a problem using PAM with shadow passwords when the calling
+       program is not running as \/root/\. Exim is normally running as the
+       Exim user when authenticating a remote host. See this posting for one
+       way round the problem:
+
+       \?http://www.exim.org/mailman/htdig/exim-users/Week-of-Mon-20010917/030371.html?\
+
+       Another solution can be found at \?http://www.e-admin.de/pam_exim/?\.
+
+       PAM 0.72 allows authorization as non-\/root/\, using setuid helper programs.
+       Furthermore, in \(/etc/pam.d/exim)\ you can explicitelly specify that
+       this authorization (using setuid helpers) is only permitted for certain
+       users and groups.
+
+
+Q0030: I'm trying to use a query-style lookup for hosts that are allowed to
+       relay, but it is giving really weird errors.
+
+A0030: Does your query contain a colon character? Remember that host lists are
+       colon-separated, so you need to double any colons in the query. This
+       applies even if the query is defined as a macro.
+
+
+Q0031: Exim is rejecting connections from hosts that have more than one IP
+       address, for no apparent reason.
+
+A0031: You are using Solaris 7 or earlier, and have \"nis dns files"\ in
+       \(/etc/nsswitch.conf)\. Change this to \"dns nis files"\ to avoid hitting Sun
+       bug 1154236 (a bad interaction between NIS and the DNS).
+
+
+Q0032: Exim is failing to find the MySQL library, even though is it present
+       within \\LD_LIBRARY_PATH\\. I'm getting this error:
+
+==>      /usr/local/bin/exim: fatal: libmysqlclient.so.6: open failed:
+         No such file or directory
+
+A0032: Exim is suid, and \\LD_LIBRARY_PATH\\ is ignored for suid binaries on a
+       Solaris (and other?) systems. What you should be doing is adding
+       \"-R/local/lib/mysql"\ to the same place in the compilation that you added
+       \"-L/local/lib/mysql"\. This tells the binary where to look without
+       needing a path variable.
+
+
+Q0033: What does the error \*lookup of host "xx.xx.xx" failed in yyy router*\
+       mean?
+
+A0033: You configured a \%manualroute%\ router to send the message to xx.xx.xx. When
+       it tried to look up the IP address for that host, the lookup failed
+       with a permanent error. As this is a manual routing, this is a
+       considered to be a serious error which the postmaster needs to know
+       about (maybe you have a typo in your file), and there is little point
+       in keeping on trying. So it freezes the message.
+
+       (1) Don't set up routes to non-existent hosts.
+
+       (2) If you must set up routes to non-existent hosts, and don't want
+       freezing, set the \host_find_failed\ option on the router to do something
+       other than freeze.
+
+
+Q0034: Exim works fine on one host, but when I copied the binary to another
+       identical host, it stopped working (it could not resolve DNS names).
+
+A0034: Is the new host running exactly the same operating system? Most
+       importantly, are the versions of the dynamically loaded libraries
+       (files with names like \(libsocket.so.1)\) the same on both systems? If not,
+       that is probably the cause of the problem. Either arrange for the
+       libraries to be the same, or rebuild Exim from source on the new host.
+
+
+Q0035: I set a \"hosts"\ condition in an ACL to do a lookup in a file of IP
+       addresses, but it doesn't work.
+
+A0035: Did you remember to put \"net-"\ at the start of the the search type? If
+       you set something like this:
+
+==>      accept hosts = lsearch;/some/file
+
+       Exim searches the file for the host name, not the IP address. You need
+       to set
+
+==>      accept hosts = net-lsearch;/some/file
+
+       to make it use the IP address as the key to the lookup.
+
+
+Q0036: Why do I get the error \*Permission denied: creating lock file hitching
+       post*\ when Exim tries to do a local delivery?
+
+A0036: Your configuration specifies that local mailboxes are all held in
+       single directory, via configuration lines like these (taken from the
+       default configuration):
+
+==>      local_delivery:
+           driver = appendfile
+           file = /var/mail/$local_part
+
+       and the permissions on the directory probably look like this:
+
+==>      drwxrwxr-x   3 root     mail         512 Jul  9 13:48 /var/mail/
+
+       Using the default configuration, Exim runs as the local user when doing
+       a local delivery, and it uses a lock file to prevent any other process
+       from updating the mailbox while it is writing to it. With those
+       permissions the delivery process, running as the user, is unable to
+       create a lock file in the \(/var/mail(\ directory. There are two solutions
+       to this problem:
+
+       (1) Set the \"write"\ and \"sticky bit"\ permissions on the directory, so
+           that it looks like this:
+
+==>          drwxrwxrwt   3 root     mail         512 Jul  9 13:48 /var/mail/
+
+           The \"w"\ allows any user to create new files in the directory, but
+           the \"t"\ bit means that only the creator of a file is able to remove
+           it. This is the same setting as is normally used with the \(/tmp)\
+           directory.
+
+       (2) Arrange to run the local_delivery transport under a specific group
+           by changing the configuration to read
+
+==>          local_delivery:
+               driver = appendfile
+               file = /var/mail/${local_part}
+               group = mail
+
+           The delivery process still runs under the user's uid, but with the
+           group set to \"mail"\. The group permission on the directory allows
+           the process to create and remove the lock file.
+
+           The choice between (1) and (2) is up to the administrator. If the
+           second solution is used, users can empty their mailboxes by updating
+           them, but cannot delete them.
+
+       If your problem involves mail to \/root/\, see also Q0507.
+
+
+Q0037: I am experiencing mailbox locking problems with Sun's \"mailtool"\ used
+       over a network.
+
+A0037: See Q9705 in the Sun-specific section below.
+
+
+Q0038: What does the error message \*error in forward file (filtering not
+       enabled): missing or malformed local part*\ mean?
+
+A0038: If you are trying to use an Exim filter, you have forgotten to enable
+       the facility, which is disabled by default. In the \%redirect%\ router
+       (in the Exim run time configuration file) you need to set
+
+==>      allow_filter = true
+
+       to allow a \(.forward)\ file to be used as an Exim filter. If you are not
+       trying to use an Exim filter, then you have put a malformed address in
+       the \(.forward)\ file.
+
+
+Q0039: I have installed Exim, but now I can't mail to \/root/\ any more. Why is
+       this?
+
+A0039: Most people set up \/root/\ as an alias for the manager of the host. If
+       you haven't done this, Exim will attempt to deliver to \/root/\ as if it
+       were a normal user. This isn't really a good idea because the delivery
+       process would run as \/root/\. Exim has a trigger guard in the option
+
+==>      never_users = root
+
+       in the default configuration file. This prevents it from running as \/root/\
+       when doing any deliveries. If you really want to run local deliveries as
+       \/root/\, remove this line, but it would be better to create an alias for
+       \/root/\ instead.
+
+
+Q0040: How can I stop undeliverable bounce messages (e.g. to routeable, but
+       undeliverable, spammer senders) from clogging up the queue for days?
+
+A0040: If at all possible, you should try to avoid getting into this situation
+       in the first place, for example, by verifying recipients so that you
+       do not accept undeliverable messages that lead to these bounces.
+       You can, however, configure Exim to discard failing bounce messages
+       early. Just set \ignore_bounce_errors_after\ to specify a (short) time
+       to keep them for.
+
+
+Q0041: What does the message \*unable to set gid=ddd or uid=ddd (euid=ddd):
+       local delivery to ... transport=ttt*\ mean?
+
+A0041: Have you remembered to make Exim setuid \/root/\? It needs root privilege if
+       it is to do any local deliveries, because it does them ``as the user''.
+       Note also that the partition from which Exim is running (where the
+       binary is installed) must not have the \nosuid\ mount option set. You
+       can check this by looking at its \(/etc/fstab)\ entry (or \(/etc/vfstab)\,
+       depending on your OS).
+
+
+Q0042: My ISP's mail server is rejecting bounce messages from Exim, complaining
+       that they have no sender. The SMTP trace does indeed show that the
+       sender address is \"<>"\. Why is the Sender on the bounce message empty?
+
+A0042: Because the RFCs say it must be. Your ISP is at fault. Send them this
+       extract from RFC 2821 section 6.1 (\*Reliable Delivery and Replies by
+       Email*\):
+
+         If there is a delivery failure after acceptance of a message, the
+         receiver-SMTP MUST formulate and mail a notification message.  This
+         notification MUST be sent using a null (\"<>"\) reverse path in the
+         envelope.  The recipient of this notification MUST be the address
+         from the envelope return path (or the ::Return-Path:: header line).
+         However, if this address is null (\"<>"\), the receiver-SMTP MUST NOT
+         send a notification.
+
+       The reason that bounce messages have no sender is so that they
+       themselves cannot provoke further bounces, as this could lead to a
+       unending exchange of undeliverable messages.
+
+
+Q0043: What does the error \*Unable to get interface configuration: 22 Invalid
+       argument*\ mean?
+
+A0043: This is an error that occurs when Exim is trying to find out the all the
+       IP addresses on all of the local host's interfaces. If you have lots of
+       virtual interfaces, this can occur if there are more than around 250 of
+       them. The solution is to set the option \local_interfaces\ to list just
+       those IP addresses that you want to use for making and receiving SMTP
+       connections.
+
+
+Q0044: What does the error \*Failed to create spool file*\ mean?
+
+A0044: Exim has been unable to create a file in its spool area in which to
+       store an incoming message. This is most likely to be either a
+       permissions problem in the file hierarchy, or a problem with the uid
+       under which Exim is running, though it could be something more drastic
+       such as your disk being full.
+
+       If you are running Exim with an alternate configuration file using a
+       command such as \"exim -C altconfig..."\, remember that the use of -C
+       takes away Exim's root privilege.
+
+       Check that you have defined the spool directory correctly by running
+
+==>      exim -bP spool_directory
+
+       and examining the output. Check the mode of this directory. It should
+       look like this, assuming you are running Exim as user \/exim/\:
+
+==>      drwxr-x---   6 exim  exim      512 Jul 16 12:29 /var/spool/exim
+
+       If there are any subdirectories already in existence, they should have
+       the same permissions, owner, and group. Check also that you haven't got
+       incorrect permissions on superior directories (for example, \(/var/spool)\).
+       Check that you have set up the Exim binary to be setuid \/root/\. It should
+       look like this:
+
+==>      -rwsr-xr-x   1 root     xxx       502780 Jul 16 14:16 exim
+
+       Note that it is not just the owner that must be \/root/\, but also the third
+       permission must be \"s"\ rather than \"x"\.
+
+
+Q0045: I see entries in the log that mention two different IP addresses for the
+       same connection. Why is this? For example:
+
+==>      H=tip-mp8-ncs-13.stanford.edu ([36.173.0.189]) [36.173.0.156]
+
+A0045: The actual IP address from which the call came is the final one.
+       Whenever there's something in parentheses in a host name, it is what the
+       host quoted as the domain part of an SMTP HELO or EHLO command. So in
+       this case, the client, despite being 36.173.0.156, issued the command
+
+==>      EHLO [36.173.0.189]
+
+       when it sent your server the message. This is, of course, very
+       misleading.
+
+
+Q0046: A short time after I start Exim I see a defunct zombie process. What
+       is causing this?
+
+A0046: Your system must be lightly loaded as far as mail is concerned. The
+       daemon sets off a queue runner process when it is started, but it only
+       tidies up completed child processes when it wakes up for some other
+       reason. When there's nothing much going on, you occasionally see
+       defunct processes like this waiting to be dealt with. This is
+       perfectly normal.
+
+
+Q0047: On a reboot, or a restart of the mail system, I see the message \*Mailer
+       daemons: exim abandoned: unknown, malformed, or incomplete option
+       -bz sendmail*\. What does this mean?
+
+A0047: \-bz-\ is a Sendmail option requesting it to create a `configuration freeze
+       file'. Exim has no such concept and so does not support the option. You
+       probably have a line like
+
+==>      /usr/lib/sendmail -bz
+
+       in some start-up script (e.g. \(/etc/init.d/mail)\) immedately before
+
+==>      /usr/lib/sendmail -bd -q15m
+
+       The first of these lines should be commented out.
+
+
+Q0048: Whenever exim restarts it takes up to 3-5 minutes to start responding on
+       the SMTP port. Why is this?
+
+A0048: Something else is hanging onto port 25 and not releasing it. One place
+       to look is \(/etc/inetd.conf)\ in case for any reason an SMTP stream is
+       configured there.
+
+
+Q0049: What does the log message \*no immediate delivery: more than 10 messages
+       received in one connection*\ mean?
+
+A0049: A remote MTA sent a number of messages in a single SMTP session. Exim
+       limits the number of immediate delivery processes it creates as a
+       result of a single SMTP connection, in order to avoid creating a zillion
+       processes on systems that can have many incoming connections. If you are
+       dialing in to collect mail from your ISP, you should probably set
+       \smtp_accept_queue_per_connection\ to some number larger than 10, or
+       arrange to start a queue runner for local delivery (using \-ql-\)
+       immediately after collecting the mail.
+
+
+Q0050: I am getting complaints from a customer who uses my Exim server for
+       relaying that they are being blocked with a \*Too many connections*\
+       error.
+
+A0050: See \smtp_accept_max\, \smep_accept_max_per_host\ and \smtp_accept_reserve\.
+
+
+Q0051: When I try \"exim -bf"\ to test a system filter, I received the following
+       error message: \*Filter error: unavailable filtering command "fail" near
+       line 8 of filter file*\.
+
+A0051: Use the \-bF-\ option to test system filters. This gives you access to the
+       freeze and fail actions.
+
+
+Q0052: What does \*ridiculously long message header*\ in an error report mean?
+
+A0052: There has to be some limit to the length of a message's header lines,
+       because otherwise a malefactor could open an SMTP channel to your host,
+       start a message, and then just send characters continuously until your
+       host ran out of memory. (Exim stores all the header lines in main
+       memory while processing a message). For this reason a limit is imposed
+       on the total amount of memory that can be used for header lines. The
+       default is 1MB, but this can be changed by setting \\HEADER_MAXSIZE\\ in
+       \(Local/Makefile)\ before building Exim. Exceeding the limit provokes
+       the ``ridiculous'' error message.
+
+
+Q0053: Exim on my host responds to a connection with \"220 *****..."\ and
+       won't understand \\EHLO\\ commands.
+
+A0053: This is the sign of a Cisco Pix ``Mailguard'' sitting in front of your
+       MTA. Pix breaks ESMTP and only does SMTP. It is a nuisance when you have
+       a secure MTA running on your box. Something like ``no fixup protocol
+       smtp 25'' in the Pix configuration is needed. It may be possible to do
+       this by logging into the Pix (using \^telnet^\ or \^ssh^\) and typing
+       \"no fixup smtp"\ to its console. (You may need to use other commands
+       before or after to set up configuration mode and to activate a changed
+       configuration. Consult your Pix documentation or expert.) See also
+       Q0078.
+
+
+Q0054: I'm getting an Exim configuration error \*unknown rewrite flag
+       character (m) in line 386*\ but I haven't used any flags on my rewriting
+       rules.
+
+A0054: You have probably forgotten to quote a replacement string that contains
+       white space.
+
+
+Q0055: What does the error \*Failed to open wait-remote_smtp database: Invalid
+       argument*\ mean?
+
+A0055: This is something that happens if you have existing DBM hints files when
+       you install a new version of Exim that is compiled to use a different or
+       upgraded DBM library. The simplest thing to try is
+
+==>      rm /var/spool/exim/db/*
+
+       This removes all the hints files. Exim will start afresh and build new
+       ones. If the symptom recurs, it suggests there is some problem with your
+       DBM library.
+
+
+Q0056: We are using Exim to send mail from our web server. However, whenever a
+       user sends an email it gets sent with the return path (envelope sender)
+       //apache@server_name.com// because the PHP script is running as
+       \/apache/\.
+
+A0056: You need to include \/apache/\ in the \trusted_users\ configuration option.
+       Only trusted users are permitted to specify senders when mail is passed
+       to Exim via the command line.
+
+
+Q0057: We've got people complaining about attachments that don't show up
+       as attachments, but are included in the body of the message.
+
+A0057: These symptoms can be seen when some software passes a CRLF line
+       terminated message via the command line to an MTA that expects lines to
+       be terminated by LF only, and so preserves the CRs as data. If you can
+       identify the software that is doing this, try setting the \-dropcr-\
+       option on the command it uses to call Exim. Alternatively, you can set
+       \drop_cr\ in the configuration file, but then that will apply to all
+       input.
+
+
+Q0058: What does the error \*failed to open DB file \(/var/spool/exim/db/retry)\:
+       File exists*\ mean?
+
+A0058: This error is most often caused when a hints file that was written with
+       one version of the Berkeley DB library is read by another version.
+       Sometimes this can happen if you change from a binary version of Exim to
+       a locally compiled version. Or it can happen if you compile and install
+       a new version of Exim after changing Berkeley DB versions. You can find
+       out which version your Exim is using by running:
+
+==>      ldd /usr/sbin/exim
+
+       The solution to the problem is to delete all the files in the
+       \(/var/spool/exim/db)\ directory, and let Exim recreate them.
+
+
+Q0059: When my Outlook Express 6.0 client sends a STARTTLS command to begin a
+       TLS session, Exim doesn't seem to receive it. The Outlook log shows
+       this:
+
+==>      SMTP: 14:19:27 [tx] STARTTLS
+         SMTP: 14:19:27 [rx] 500 Unsupported command.
+
+        but the Exim debugging output shows this:
+
+==>       SMTP<< EHLO xxxx
+          SMTP>> 250-yyyy Hello xxxx [nnn.nnn.nnn.nnn]
+          250-SIZE 52428800
+          250-PIPELINING
+          250-AUTH CRAM-MD5 PLAIN LOGIN
+          250-STARTTLS
+          250 HELP
+          SMTP<< QUIT
+
+A0059: Turn off scanning of outgoing email in Norton Antivirus. If you aren't
+       running Norton Antivirus, see if you are running some other kind of SMTP
+       proxying, either on the client or on a firewall between the client and
+       server. ``Unsupported command'' is not an Exim message.
+
+
+Q0060: Why am I getting the error \*failed to expand \"/data/lists/lists/${lc"\
+       for require_files: \"${lc"\ is not a known operator*\ for this setting:
+
+==>      require_files = MAILMAN_HOME/lists/${lc:$local_part}/config.db
+
+A0060: The value of \"require_files"\ is a \*list*\ in which each item is
+       separately expanded. You need either to double the colon, or switch to
+       a different list separator.
+
+
+Q0061: What does the error \*Too many ``Received'' headers - suspected mail
+       loop*\ mean?
+
+A0061: Whenever a message passes through an MTA, a ::Received:: header gets
+       added. Exim counts the number of these headers in incoming messages. If
+       there are more than the value of \received_headers_max\ (default 30),
+       Exim assumes there is some kind of mail routing loop occurring. For
+       example, host A passes the message to host B, which immediately passes
+       it back to host A. Check the ::Received:: headers and the mail logs to
+       determine exactly what is going on.
+
+       One common cause of this problem is users with accounts on both systems
+       who set up each one to forward to the other, thinking that will cause
+       copies of all messages to be delivered on both of them.
+
+
+Q0062: When I try to start an Exim daemon it crashes. I ran a debugger and
+       discovered that the crash is happening in the function \^^getservbyname()^^\.
+       What's going on?
+
+A0062: What have you got in the file \(/etc/nsswitch.conf)\? If it contains this
+       line:
+
+==>      services:       db files
+
+       try removing the \"db"\. (Your system is trying to look in some kind of
+       database before searching the file \(/etc/services)\.)
+
+
+Q0063: When I try to start an Exim daemon, nothing happens. There is no
+       process, and nothing is written to the Exim log.
+
+A0063: Check to see if anything is written to \(syslog)\. This problem can be
+       caused by a permission problem that stops Exim from writing to its log
+       files, especially if you've specified that they should be written
+       somewhere other than under Exim's spool directory. You could also try
+       running the daemon with debugging turned on.
+
+
+Q0064: When I run \"exim -d test@domain"\ it delivers fine, but when I send a
+       message from the \^mail^\ command, I get \*User unknown*\ and the mail
+       is saved in \(dead.letter)\.
+
+A0064: It looks as if Exim isn't being called by \^mail^\; instead it is
+       calling some other program (probably Sendmail). Try running the command
+
+==>      /usr/sbin/sendmail -bV
+
+       (If you get \*No such file or directory*\ or \*Command not found*\ you
+       are running Solaris or IRIX. Try again with \(/usr/lib/sendmail)\.) The
+       output should be something like this:
+
+==>      Exim version 4.05 #1 built 13-Jun-2002 10:27:15
+         Copyright (c) University of Cambridge 2002
+
+       If you don't see this, your Exim installation isn't fully operational.
+       If you are running FreeBSD, see Q9201. For other systems, see Q0114.
+
+
+Q0065: When (as \/root/\) I use -C to run Exim with an alternate configuration
+       file, it gives an error about being unable to create a spool file when
+       trying to run an \%autoreply%\ transport. Why is this?
+
+A0065: When Exim is called with -C, it passes on -C to any instances of itself
+       that it calls (so that the whole sequence uses the same config file). If
+       it's running as \/exim/\ when it does this, all is well. However, if it
+       happens as a consequence of a non-privileged user running \%autoreply%\,
+       the called Exim gives up its root privilege. Then it can't write to the
+       spool.
+
+       This means that you can't use -C (even as \/root/\) to run an instance of
+       Exim that is going to try to run \%autoreply%\ from a process that is
+       neither \/root/\ nor \/exim/\. Because of the architecture of Exim (using
+       re-execs to regain privilege), there isn't any way round this
+       restriction. Therefore, the only way you can make this scenario work is
+       to run the \%autoreply%\ transport as \/exim/\ (that is, the user that
+       owns the Exim spool files). This may be satisfactory for autoreplies
+       that are essentially system-generated, but of course is no good for
+       autoreplies from unprivileged users, where you want the \%autoreply%\
+       transport to be run as the user. To get that to work with an alternate
+       configuration, you'll have to use two Exim binaries, with different
+       configuration file names in each. See S001 for a script that patches
+       the configuration name in an Exim binary.
+
+
+Q0066: What does the message \*unable to set gid=xxx or uid=xxx*\ mean?
+
+A0066: This message is given when an Exim process is unable to change uid or
+       gid when it needs to, because it does not have root privilege. This is a
+       serious problem that prevents Exim from carrying on with what it is
+       doing. The two most common situations where Exim needs to change uid/gid
+       are doing local deliveries and processing users' filter files. There are
+       two common causes of this error:
+
+       (1) You have forgotten to make the exim binary setuid to \/root/\. This
+           means that it can never change uid/gid in any situation. Also, the
+           setuid binary must reside on a disk partition that does not have the
+           \"nosuid"\ mount option set.
+
+       (2) The exim binary is setuid, but you have configured Exim so that,
+           while trying to verify an address at SMTP time, it runs a router
+           that needs to change uid/gid. Because Exim runs as \/exim/\ and not
+           \/root/\ while receiving messages, the router is unable to change
+           uid and therefore it cannot operate. The usual example of this is a
+           \%redirect%\ router for users' filter files.
+
+           Setting the \user\ or \check_local_user\ options on a \redirect\
+           router causes this to happen (except in the special case when the
+           redirection list is provided by the \data\ option and does not
+           contain \":include:"\).
+
+           The solution is to set \no_verify\ on the router that is causing the
+           problem. This means that it is skipped when an address is being
+           verified. In ``normal'' configurations where the router is indeed
+           handling users' filter files, this is quite acceptable, because you
+           do not usually need to process a filter file in order to verify that
+           the local part is valid. See, for example, the \%userforward%\
+           router in the default configuration.
+
+
+Q0067: What does the error \*too many unrecognized commands*\ mean?
+
+A0067: There have been instances of network abuse involving mail sent out by
+       web servers. In most cases, unrecognizable commands are sent as part of
+       the SMTP session. A real MTA never sends out such invalid commands. Exim
+       allows a few unrecognized commands in a session to permit humans who are
+       testing to make a few typos (it responds with a 5xx error). However, if
+       Exim receives too many such commands, it assumes that it is dealing with
+       an abuse of some kind, and so it drops the connection.
+
+
+Q0068: Exim times out when trying to connect to some hosts, though those hosts
+       are known to be up and running. What's the problem?
+
+A0068: There could be a number of reasons for this (see also Q0017). The
+       obvious one is that there is a networking problem between the hosts.
+       If you can ping between the hosts or connect in other ways, the problem
+       might be caused by ECN (Explicit Congestion Notification) being enabled
+       in your kernel. ECN uses TCP flags originally assigned to TOS - it's a
+       "new" invention, and some hosts and routers are known to be confused if
+       a client uses it. If you are running Linux, you can turn ECN off by
+       running this command:
+
+==>      /bin/echo "0" > /proc/sys/net/ipv4/tcp_ecn
+
+       This has also been reported to cure web connection problems from Mozilla
+       and Netscape browsers in Linux when there were no problems with Windows
+       Netscape browsers.
+
+
+Q0069: What does the error \*SMTP data timeout (message abandoned) on connection
+       from...*\ mean?
+
+A0069: It means that there was a timeout while Exim was reading the contents of
+       a message on an incoming SMTP connection. That is, it had successfully
+       accepted a MAIL command, one or more RCPT commands, and a DATA command,
+       and was in the process of reading the data itself. The length of timeout
+       is controlled by the \smtp_receive_timeout\ option.
+
+       If you get this error regularly, the cause may be incorrect handling of
+       large packets by a router or firewall. The maximum size of a packet is
+       restricted on some links; routers should split packets that are larger.
+       There is a feature called ``path MTU discovery'' that enables a sender
+       to discover the maximum packet size over an entire path (multiple
+       Internet links). This can be broken by misconfigured firewalls and
+       routers. There is a good explanation at \?http://www.netheaven.com/pmtu.html?\.
+       Reducing the MTU on your local network can sometimes work round this
+       problem. See Q0017 (3) for further discussion.
+
+
+Q0070: What does the error \*SMTP command timeout on connection from...*\ mean?
+
+A0070: Exim was expecting to read an SMTP command from the client, but no
+       command was read within the \smtp_receive_timeout\ time limit.
+
+
+Q0071: What does the error \*failed to open DB file \(/var/spool/exim//db/retry)\:
+       Illegal argument*\ mean?
+
+A0071: See Q0058. The cause of this error is usually the same.
+
+
+Q0072: Exim will deliver to normal aliases, and aliases that are pipes or
+       files, but it objects to aliases that involve \":include:"\ items,
+       complaining that it can't change gid or uid. Why is this?
+
+A0072: See Q0066 for a general answer. The problem happens during verification
+       of an incoming SMTP message, not during delivery itself. In this
+       particular case, you must have set up your aliasing router with a \user\
+       setting. This causes Exim to change uid/gid when reading \":include:"\
+       files. If you do not need the detailed verification provided by the
+       router, the easy solution is to set \no_verify\ so that the router isn't
+       used during verification.
+
+       Otherwise, if you set \user\ on the router in order to provide a user
+       for delivery to pipes or files, one solution is to put the \user\
+       setting on the transports instead of on the router. You may need to
+       create some special transports just for this router. The alternative is
+       to supply two different routers, one with \user\ and \no_verify\, and
+       the with \verify_only\ but no \user\ setting.
+
+
+Q0073: I'm seeing log file corruption, with parts of log lines getting mangled
+       by other log entries.
+
+A0073: The only time this has been seen is when several servers were writing to
+       the same log files over NFS. Exim assumes that its log file is on local
+       disk, and using NFS, especially for more than one server, will not work.
+
+
+Q0074: What does the error message \*remote delivery process count got out of
+       step*\ mean?
+
+A0074: Exim uses subprocesses for remote deliveries; this error means that the
+       master process expected to have a child process running, but found there
+       were none. Prior to release 4.11, this error could be caused by running
+       Exim under \^strace^\ on a Linux system, because stracing causes
+       children to be ``stolen'' such that a parent that tries to wait for
+       ``any of my children'' is told that it has none. Current releases of
+       Exim have code to get round this problem.
+
+
+Q0075: I'm using LDAP, and some email addresses that contain special characters
+       are causing parsing errors in my LDAP lookups.
+
+A0075: You should be using \"${quote_ldap:$local_part}"\ instead of just
+       \"$local_part"\ in your lookups.
+
+
+Q0076: I've configured Exim to use \^syslog^\ for its logs, with the main and
+       reject logs sent to different files, but whenever a message is rejected,
+       I get one message on the reject log and two messages on the main log.
+
+A0076: You are probably putting your reject items into the main log as well;
+       remember \^syslog^\ levels are inclusive (for example, \"mail.info"\
+       includes all higher levels, so a \"mail.notice"\ message will be caught
+       by a \"mail.info"\ descriptor).
+       Test this by running the command:
+
+==>     logger -p mail.notice test
+
+       and seeing which logs it goes into.
+
+
+Q0077: I've installed Exim and it is delivering mail just fine. However, when I
+       try to read mail from my PC I get \*connection rejected*\ or \*unable to
+       connect*\.
+
+A0077: See Q5021.
+
+
+Q0078: Exim is logging the unknown SMTP command \"XXXX"\ from my client hosts,
+       and they are unable to authenticate.
+
+A0078: This is a sign of a Cisco PIX firewall getting in the way. It does not
+       support ESMTP, and turns EHLO commands into XXXX. You should configure
+       the Pix to leave SMTP alone; see Q0053 for how to do this.
+
+
+Q0079: Our new PIX firewall is causing problems with incoming mail. How can
+       this be fixed?
+
+A0079: See Q0053 and Q0078. If some messages get through and others do not,
+       see also Q0017.
+
+
+Q0080: Am I to understand that the database lookups must only return one value?
+       They can not return a list of values? The documentation seems to
+       indicate that it's possible to return a list.
+
+A0080: Lookups can be used in two different situations, and what they return is
+       different in the two cases. (Be thankful Exim 3 is gone; there was yet
+       another case!)
+
+       (1) You can use a lookup in any expanded string. The syntax is
+
+==>          ${lookup ..... }
+
+           In this case, whatever is looked up replaces the expansion item. It
+           may be one value or a list of values. Whether a single value or a
+           list is acceptable or not depends on where you are using the string
+           expansion. If it is for an option that expects just one value, then
+           only one value is allowed (for example).
+
+       (2) You can make use of the lookup mechanism to test whether something
+           (typically a host name or IP address) is in a list. For example,
+
+==>          hosts = a : b : c
+
+           in an ACL tests whether the calling host's name matches ``a'', or
+           ``b'', or ``c''. Now, suppose you want to keep the list of names in
+           a database, or cdb file, or NIS map, or...  By writing
+
+==>           hosts = pgsql;select ....
+
+           you are saying to Exim: ``Run this lookup; if it succeeds, behave as
+           if the host is in the list; if it fails, the host is not in the
+           list.'' You are using the indexing mechanism of the database as a
+           fast way of checking a list. A simpler example is
+
+==>           hosts = lsearch;/some/file
+
+           where the file contains the list of hosts to be searched.
+
+       The complication happens when a list is first expanded before being
+       interpreted as a list. This happens in a lot of cases. You can therefore
+       write either of these:
+
+==>       hosts = cdb;/some/file
+          hosts = ${lookup{something}cdb{/some/file}}
+
+       but they have different meanings. The first means ``see if the host name
+       is in the list in this file''. The second means ``run this lookup and
+       use the result of the lookup as a list of host items to check''. In the
+       second case, the list could contain multiple values (colon separated),
+       and one of those values could even be ``cdb;/some/file''.
+
+       Flexibility does lead to complexity, I'm afraid.
+
+
+Q0081: What does \*error in redirect data: included file xxxx is too big*\
+       mean?
+
+A0081: You are trying to include a very large file in a redirection list, using
+       the \":include:"\ feature. Exim has a built-in limit on the size, as a
+       safety precaution. The default is 1 megabyte. If you want to increase
+       this, you have to rebuild Exim. In your \(Local/Makefile)\, put
+
+==>      MAX_INCLUDE_SIZE = whatever
+
+       and then rebuild Exim. The value is a number of bytes, but you can give
+       it as a parenthesized arithmetic expression such as \"(3*1024*1024)"\.
+       However, an included file of more than a megabyte is likely to be quite
+       inefficient. How many addresses does yours contain? You get the best
+       performance out of Exim if you arrange to send mailing list messages
+       with no more than about 100 recipients (in order to get parallelism in
+       the routing).
+
+
+Q0082: What does \*relocation error: /lib/libnss_dns.so.2: symbol
+       __libc_res_nquery, version GLIBC_PRIVATE not defined in file
+       libresolv.so.2 with link time reference*\ mean?
+
+A0082: You have updated \^glibc^\ while an Exim daemon is running. Stop and
+       restart the daemon.
+
+
+Q0083: Netscape on Unix is sending messages containing an unqualified user name
+       in the ::Sender:: header line, which Exim is rejecting because I have
+       set \"verify = header_syntax"\. How can I fix this?
+
+A0083: The only thing you can do in Exim is to set the
+       \sender_unqualified_hosts\ option to allow unqualified sender addresses
+       form the relevant hosts; of course, this applies to all sender
+       addresses, not just the ::Sender:: header line.
+
+       Alternatively, you can configure Netscape not to include the header line
+       in the first place. Add the following line to the
+       \($HOME/.netscape/preferences.js)\ and \($HOME/.netscape/liprefs.js)\
+       files:
+
+==>      user_pref("mail.suppress_sender_header", true);
+
+       Netscape \*must*\ be shutdown while doing this.
+
+
+Q0084: I want to set up an alias that pipes a message to \^gpg^\ and then pipes
+       the result to \^mailx^\ to resubmit the message, but when I use my
+       tested command in an alias file, I get an error from \^gpg^\.
+
+A0084: Probably you are using a shell command with two pipe symbols in it. An
+       alias like this:
+
+==>      gpg-xxx: "|gpg <options> | mailx <options"
+
+       does not work, because Exim does not run pipes under a shell by default.
+       You must call a shell explicitly if you want to make use of the shell's
+       features for double-piping, either by piping to \"/bin/sh"\ with a
+       suitable \"-c"\ option, or by piping to a shell script.
+
+
+Q0085: I see a lot of \*rejected EHLO ... syntactically invalid argument(s)*\.
+       I know it's because of the underscore in the host name, but is there a
+       switch to allow Exim to accept mail from such hosts?
+
+A0085: Yes. Add this to your configuration:
+
+==>      helo_allow_chars = _
+
+       For more seriously malformed host names, see \helo_accept_junk_hosts\.
+       See also Q0732.
+
+
+Q0086: What does \*SMTP protocol violation: synchronization error (next input
+       sent too soon)*\ mean?
+
+A0086: SMTP is a ``lock-step'' protocol, which means that, at certain points in
+       the protocol, the client must wait for the server to respond before
+       sending more data. Exim checks for correct behaviour, and issues this
+       error if the client sends data too soon. This protects against
+       malefactious clients who send a bunch of SMTP commands (usually to
+       transmit spam) without waiting for any replies.
+
+       This error is also provoked if the client is trying to start up a TLS
+       session immediately on connection, without using the STARTTLS command.
+       See Q1707 for a discussion of this case.
+
+
+Q0087: What does \*rejected after DATA: malformed address: xx@yy may not follow
+       <xx@yy> : failing address in "from" header*\ mean? (I've obscured the
+       real email addresses.)
+
+A0087: Your DATA ACL contains
+
+==>      verify = header_syntax
+
+       and an incoming message contained the line
+
+==>      From: xx@yy <xx@yy>
+
+       This is syntactically invalid. The contents of an address in a header
+       line are either just the address, or a ``phrase'' followed by an address
+       in angle brackets. In the latter case, the ``phrase'' must be quoted if
+       it contains special characters such as @. The following are valid
+       versions of the bad header:
+
+==>      From: xx@yy
+         From: "xx@yy" <xx@yy>
+
+       though why on earth anything generates this kind of redundant nonsense I
+       can't think.
+
+
+Q0088: The Windows mailer SENDFILE.EXE sometimes hangs while trying to send a
+       message to Exim 4, and eventually times out. It worked flawlessly with
+       Exim 3. What has changed?
+
+A0088: Exim 4 sets an obscure TCP/IP parameter called TCP_NODELAY. This
+       disables the "Nagle algorithm" for the TCP/IP transmission. The Nagle
+       algorithm can improve network performance in interactive situations such
+       as a human typing at a keyboard, by buffering up outgoing data until the
+       previous packet has been acknowledged, and thereby reducing the number
+       of packets used. This is not relevant for mail transmission, which
+       mostly consists of quite large blocks of data; setting TCP_NODELAY
+       should improve performance. However, it seems that some Windows clients
+       do not function correctly if the server turns off the Nagle algorithm.
+       If you are using Exim 4.23 or later, you can set
+
+==>      tcp_nodelay = false
+
+       This stops Exim setting TCP_NODELAY on the sockets created by the
+       listening daemon.
+
+
+Q0089: What does the error \*kernel: application bug: exim(12099) has SIGCHLD
+       set to SIG_IGN but calls wait()*\ mean?
+
+A0089: This was a bad interaction between a relatively recent change to the
+       Linux kernel and some ``belt and braces'' programming in Exim. The
+       following explanation is taken from Exim's change log:
+
+       When Exim is receiving multiple messages on a single connection, and
+       spinning off delivery processess, it sets the SIGCHLD signal handling to
+       SIG_IGN, because it doesn't want to wait for these processes. However,
+       because on some OS this didn't work, it also has a paranoid call to
+       \^waitpid()^\ in the loop to reap any children that have finished. Some
+       versions of Linux now complain (to the system log) about this
+       ``illogical'' call to \^waitpid()^\. I have therefore put it inside a
+       conditional compilation, and arranged for it to be omitted for Linux.
+
+       I am pretty sure I caught all the places in Exim where this happened.
+       However, there are still occasional reports of this error. I have not
+       heard of any resolutions, but my current belief is that they are caused
+       by something that Exim calls falling foul of the same check. There was
+       at one time a suspicion that the IPv6 stack was involved.
+
+
+Q0090: I can't seem to get a pipe command to run when I include a \"${lookup"\
+       expansion in it.
+
+A0090: See Q0025.
+
+
+Q0091: Why is Exim giving the error \*Failed to send message from address_reply
+       transport*\ when I run it using -C to specify an alternate
+       configuration?
+
+A0091: See Q0065.
+
+
+
+1. BUILDING AND INSTALLING
+
+Q0101: I'm having a problem with an Exim RPM.
+
+A0101: Normally the thing to do if you have a problem with an RPM package is
+       to contact the person who built the package first, not the person who
+       made the software that's in the package.  You can usually find out who
+       made a package using the following command:
+
+==>      rpm --query --package --queryformat '%{PACKAGER}\n' <rpm-package-file>
+
+       where \[rpm-package-file]\ is the actual file, e.g. \(exim-3.03-2.i386.rpm)\.
+       Or, if the package is installed on your system:
+
+==>      rpm --query --queryformat '%{PACKAGER}\n' <package-name>
+
+       where \[package-name]\ is the name component of the package, e.g. \"exim"\.
+       If the packager is unable or unwilling to help, only then should you
+       contact the actual author or associated mailing list of the software.
+
+       If you discover through the querying process that you can't tell who
+       the person (or company or group) is who built the package, or that they
+       no longer exist at the given address, then you should reconsider
+       whether you want a package from an unknown source on your system.
+
+       If you discover through the querying process that you yourself are the
+       person who built the package, then you should either (a) contact the
+       author or associated mailing list, or (b) reconsider whether you ought
+       to be building and distributing RPM packages of software you don't
+       understand.
+
+       Similar rules of thumb govern other binary package formats, including
+       debs, tarballs, and POSIX packages.
+
+
+Q0102: I can't get Exim to compile with Berkeley DB version 2.x or 3.x.
+
+A0102: Have you set \"USE_DB=yes\" in \(Local/Makefile)\? This causes Exim to use the
+       native interface to the DBM library instead of the compatibility
+       interface, which needs a header called \(ndbm.h)\ that may not exist on your
+       system.
+
+
+Q0103: I'm getting an \*undefined symbol*\ error for \"hosts_ctl"\ when I try to
+       build Exim. (On some systems this error is \*undefined reference to
+       'hosts_ctl'*\.)
+
+A0103: You should either remove the definition of \\USE_TCP_WRAPPERS\\ or add
+       \"-lwrap"\ to your \\EXTRALIBS\\ setting in Local/Makefile.
+
+
+Q0104: I'm about to upgrade to a new Exim release. Do I need to ensure the
+       spool is empty, or take any other special action?
+
+A0104: It depends on where you are coming from.
+
+       (1) If you are changing to release 4.00 or later from a release prior to
+       4.00, you will need to make changes to the run time configuration file.
+       See the file \(doc/Exim4.upgrade)\ for details. If you are coming from
+       before release 3.00, you should also see \(doc/Exim3.upgrade)\.
+
+       (2) If you are upgrading from an Exim 4 release to a later release, you
+       do not need to take special action. New releases are made backwards
+       compatible with old spool files and hints databases, so that upgrading
+       can be done on a running system. All that should be necessary is to
+       install a new binary and then HUP the daemon.
+
+
+Q0105: What does the error \*install-info: command not found*\ mean?
+
+A0105: You have set \\INFO_DIRECTORY\\ in your \(Local/Makefile)\, and Exim is trying
+       to install the Texinfo documentation, but cannot find the command called
+       \(install-info)\. If you have a version of Texinfo prior to 3.9, you
+       should upgrade. Otherwise, check your installation of Texinfo to see why
+       the \(install-info)\ command is not available.
+
+
+Q0106: Exim doesn't seem to be recognizing my operating system type correctly,
+       and so is failing to build.
+
+A0106: Run the command \"scripts/os-type -generic"\. The output should be one of
+       the known OS types, and should correspond to your operating system. You
+       can see which OS are supported by obeying \"ls OS/Makefile-*"\ and looking
+       at the file name suffixes.
+
+       If there is a discrepancy, it means that the script is failing to
+       interpret the output from the \"uname"\ command correctly, or that the
+       output is wrong. Meanwhile, you can build Exim by obeying
+
+==>      EXIM_OSTYPE=xxxx make
+
+       instead of just \"make"\, provided you are running a Bourne-compatible
+       shell, or otherwise by setting \\EXIM_OSTYPE\\ correctly in your
+       environment. It is probably best to start again from a clean
+       distribution, to avoid any wreckage left over from the failed attempt.
+
+
+Q0107: Exim fails to build, complaining about the absence of the \"killpg"\
+       function.
+
+A0107: This function should be present in all modern flavours of Unix. If you
+       are using an older version, you should be able to get round the problem
+       by inserting
+
+==>      #define killpg(pgid,sig)   kill(-(pgid),sig)
+
+       into the file called \(OS/os.h-xxx)\, where xxx identifies your operating
+       system, and is the output of the command \"scripts/os-type -generic"\.
+
+
+Q0108: I'm getting an unresolved symbol \"ldap_is_ldap_url"\ when trying to build
+       Exim.
+
+A0108: You must have specified \"LOOKUP_LDAP=yes"\ in the configuration. Have you
+       remembered to set \"-lldap"\ somewhere (e.g. in \\LOOKUP_LIBS\\)? You need that
+       in order to get the LDAP library scanned when linking.
+
+
+Q0109: I'm getting an unresolved symbol \"mysql_close"\ when trying to build Exim.
+
+A0109: You must have specified \"LOOKUP_MYSQL=yes"\ in the configuration. Have you
+       remembered to set \"-lmysqlclient"\ somewhere (e.g. in \\LOOKUP_LIBS\\)? You
+       need that in order to get the MySQL library scanned when linking.
+
+
+Q0110: I'm trying to build Exim with PAM support. I have included \"-lpam"\ in
+       \\EXTRALIBS\\, but I'm still getting a linking error:
+
+==>      /lib/libpam.so: undefined reference to `dlerror'
+         /lib/libpam.so: undefined reference to `dlclose'
+         /lib/libpam.so: undefined reference to `dlopen'
+         /lib/libpam.so: undefined reference to `dlsym'
+
+A0110: Add \"-ldl"\ to \\EXTRALIBS\\. In some systems these dynamic loading functions
+       are in their own library.
+
+
+Q0111: I'm getting the error \*db.h: No such file or directory*\ when I try to
+       build Exim.
+
+A0111: This problem has been seen with RedHat 7.0, but could also happen in
+       other environments. If your system is using the DB library, you
+       need to install the DB development package in order to build Exim.
+       The package is called something like \"db3-devel-3.1.14-16.i386.rpm"\ for
+       Linux systems, but you should check which version of DB you have
+       installed (current releases are DB 4).
+
+
+Q0112: I'm getting the error \*/usr/bin/ld: cannot find -ldb*\ when I try to
+       build Exim.
+
+A0112: This is probably the same problem as Q0111.
+
+
+Q0113: I've compiled Exim and I've managed to start it but there was one
+       problem - it always complained that \(libmsqlclient.so.10)\ was not found,
+       even though this file is in \(/usr/local/lib/mysql/)\.
+
+A0113: Solaris: ensure you have this in your \(Local/Makefile)\:
+
+==>      LOOKUP_LIBS=-L/usr/local/lib/mysql -R/usr/local/lib/mysql
+
+       Net/Open/FreeBSD: Run this command (or ensure it gets run automatically
+       at boot time):
+
+==>      ldconfig -m /usr/local/lib/mysql
+
+       Linux: add \(/usr/local/lib/mysql)\ to \(/etc/ld.so.conf)\ and re-run \(ldconfig)\.
+       Alternatively, add
+
+==>      -Wl,-rpath -Wl,/usr/local/lib/mysql
+
+       to EXTRA_LIBS and  then re-link (this is similar to the Solaris solution
+       above). This will probably also work on other systems that use GNU
+       Binutils.
+
+
+Q0114: How can I remove Sendmail from my system? I've built Exim and run \"make
+       install"\, but it still doesn't seem to be fully operational.
+
+A0114: If you are running FreeBSD, see Q9201. Otherwise, you need to arrange
+       that whichever of the paths \(/usr/sbin/sendmail)\ or \(/usr/lib/sendmail)\
+       exists on your system is changed to refer to Exim. For example, you
+       could use these commands (as \/root/\):
+
+==>      mv /usr/sbin/sendmail /usr/sbin/sendmail.original
+         chmod u-s /usr/sbin/sendmail.original
+         ln -s /path/to/exim /usr/sbin/sendmail
+
+       The second command removes the setuid privilege from the old MTA, as a
+       general safety precaution. In the third command, substitute the actual
+       path to the Exim binary for \(/path/to/exim)\.
+
+
+Q0115: What does \*Can't open \(../scripts/newer)\: No such file or directory*\
+       mean? I got it while trying to build Exim.
+
+A0115: You are using FreeBSD, or another OS that has a \^make^\ command which
+       tries to optimize the running of commands. Exim's \(Makefile)\ contains
+       targets with sequential commands like this:
+
+==>      buildpcre:
+           @cd pcre; $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" \
+             CFLAGS="$(CFLAGS) $(PCRE_CFLAGS)" \
+             RANLIB="$(RANLIB)" HDRS="$(PHDRS)" \
+             INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"
+           @if $(SHELL) $(SCRIPTS)/newer pcre/libpcre.a exim; then \
+             /bin/rm -f exim eximon.bin; fi
+
+       The second command assumes that the \"cd pcre"\ in the first command is
+       no longer in effect. If you have \"-j3"\ in your default set of
+       \"MAKEFLAGS"\, FreeBSD \^make^\ tries to optimize, and ends up up with both
+       commands in the same shell process. The result is that \"$(SCRIPTS)"\
+       (which has a value of \"../scripts"\) is not found.
+
+       The simplest solution is to force \^make^\ to use backwards compatibility
+       mode with each command in its own shell, by using the \-B\ flag. To
+       ensure that this happens throughout the build, it's best to export it in
+       your environment:
+
+==>     MAKEFLAGS='-B'
+        export MAKEFLAGS
+        make
+
+
+Q0116: I have tried to build Exim with Berkeley DB 3 and 4, but I always get
+       errors.
+
+A0116: One common problem, especially when you have several different versions
+       of BDB installed on the same host, is that the header files and library
+       files for BDB are not in a standard place. You therefore need to tell
+       Exim where they are, by setting INCLUDE and DBMLIB in your
+       \(Local/Makefile)\. For example, I use this on my workstation when
+       I want to build with DB 4.1:
+
+==>      INCLUDE=-I/opt/local/include/db-4.1
+         DBMLIB=/opt/local/lib/db-4.1/libdb.a
+
+       Specifying the complete library file like this will cause it to be
+       statically linked with Exim. You'll have to check to see where these
+       files are on your system. For example, on FreeBSD 5, the header is in
+       \(/usr/local/include/db4)\ and the library is in \(/usr/local/lib)\ and
+       called \(libdb4)\. In that environment, you could use:
+
+==>      INCLUDE=-I/usr/local/include/db4
+         DBMLIB=-L/usr/local/lib -ldb4
+
+       This time, DBMLIB is specifying the library directory (\(/usr/local/lib)\)
+       and the name of the library (\(db4)\) separately. The name of the actual
+       library file is \(/usr/local/lib/libdb4.something)\. If the library was
+       compiled for dynamic linking, that will be used.
+
+
+Q0117: Is there a quick walk-through of an Exim install from source anywhere?
+
+A0117: Here! This is a contribution from a RedHat user, somewhat edited. On
+       other operating systems things may be slightly different, but the
+       general approach is the same.
+
+       (1) Install the db needed for Exim. This needs to be done first if you
+       don't have a DBM library installed. Go to \?http://www.sleepycat.com?\
+       and download \(db-4.1.25.tar.gz)\, or whatever the current release is.
+       Then:
+
+==>      gunzip db-4.1.25.tar.gz
+         tar -xvf db-4.1.25.tar
+         cd db-4.1.25
+         cd build_unix
+         ../dist/configure
+         make
+         make install
+
+       (2) Add a user for use by Exim, unless you want to use an existing user
+       such as \/mail/\:
+
+==>      adduser exim
+
+       (3) Now you can prepare to build Exim. Go to \?http://www.exim.org?\ or
+       one of its mirrors, or the master ftp site
+       \?ftp://ftp.csx.cam.ac.uk/pub/software/email/exim/exim4?\, and download
+       \(exim-4.20.tar.gz)\ or whatever the current release is. Then:
+
+==>      gunzip exim-4.20.tar.gz
+         tar -xvf exim-4.20.tar
+         cd exim-4.20
+         cp src/EDITME Local/Makefile
+         cp exim_monitor/EDITME Local/eximon.conf
+
+       (4) Edit \(Local/Makefile)\:
+
+       Comment out EXIM_MONITOR= unless you want to install the Exim
+         monitor (it requires X-windows).
+
+       Set the user you want Exim to use for itself:
+
+==>        EXIM_USER=exim
+
+       If your DBM library is Berkeley DB, set up to use its native interface:
+
+==>        USE_DB=yes
+
+       Make sure Exim's build can find the DBM library and its headers. If
+         you've installed Berkeley DB 4 you'll need to have settings like this
+         in \(Local/Makefile)\:
+
+==>        INCLUDE=-I/usr/local/BerkeleyDB.4.1/include
+           DBMLIB=/usr/local/BerkeleyDB.4.1/lib/libdb.a
+
+         (Check that the first directory contains the db.h file and that the
+         second library exists.)
+
+       You don't need to change anything else, but you might want to review
+         the default settings in the ``must specify'' section.
+
+       (4) Build Exim by running the \/make/\ command.
+
+       (5) Install Exim by running, as \/root/\:
+
+==>      make install
+
+       You \*must*\ be \/root/\ to do this. You do not have to be root for any of
+       the previous building activity.
+
+       (6) Run some tests on Exim; see if it will do local and remote
+       deliveries. Change the configuration if necessary (for example,
+       uncommenting \group\ on the \%local_delivery%\ transport if you don't
+       use a ``sticky bit'' directory).
+
+       (7) Change Sendmail to Exim (of course you need to have had Sendmail
+       installed to do this).
+
+==>      /etc/init.d/sendmail stop
+         mv /usr/sbin/sendmail /usr/sbin/sendmail.org
+         ln -s /usr/exim/bin/exim /usr/sbin/sendmail
+         /etc/init.d/sendmail start
+
+       (8) Check the Exim log. Either use the Exim monitor, or:
+
+==>      tail -f /var/spool/exim/log/mainlog
+
+
+Q0118: I've set \"LOOKUP_INCLUDE=-I/client/include"\ in Local/Makefile, but the
+       compilation of \^exim_dumpdb^\ is ignoring this option and failing. Why?
+
+A0118: LOOKUP_INCLUDE is the special include file for lookup modules in Exim
+       (e.g. mysql, LDAP). Confusingly, it doesn't apply to basic DBM code
+       which is used also for other things. Try setting INCLUDE and DBMLIB
+       instead. For example:
+
+==>      USE_DB=yes
+         INCLUDE=-I/client/include
+         DBMLIB=/client/lib/libdb.a
+
+
+Q0119: I know there are some 3rd-party patches for Exim, for exiscan and
+       other things. Where are they?
+
+A0119: Exiscan is at \?http://duncanthrax.net/exiscan-acl/?\.
+[[br]]
+       Scanexi is at \?http://w1.231.telia.com/~u23107873/scanexi.html?\
+[[br]]
+       A sample \^^local_scan()^^\ function for interfacing to \^uvscan^\ is
+       at \?http://www.dcs.qmul.ac.uk/~mb/local_scan/?\.
+[[br]]
+       An interface to SpamAssassin at SMTP time is at
+       \?http://marc.merlins.org/linux/exim/sa.html?\.
+[[br]]
+       A mini-HOWTO (PDF file) about scanning and virus scanning, and some RPMs
+       can be found at \?http://www.timj.co.uk/linux/exim.php?\.
+
+
+
+2. ROUTING IN GENERAL
+
+Q0201: How can I arrange that messages larger than some limit are handled by
+       a special router?
+
+A0201: You can use a \condition\ option on the router line this:
+
+==>      condition = ${if >{$message_size}{100K}{yes}{no}}
+
+
+Q0202: Can I specify a list of domains to explicitly reject?
+
+A0202: Set up a named domain list containing the domains in the first section
+       of the configuration, for example:
+
+==>      domainlist reject_domains = list:of:domains:to:reject
+
+       You can use this list in an ACL to reject any SMTP recipients in those
+       domains. You can also give a customized error message, like this:
+
+==>      deny message = The domain $domain is no longer supported
+              domains = +reject_domains
+
+       If you also want to reject these domains in messages that are submitted
+       from the command line (not using SMTP), you need to set up a router to
+       do it, like this:
+
+==>      reject_domains:
+           driver = redirect
+           domains = +reject_domains
+           allow_fail
+           data = :fail: The domain $domain is no longer supported
+
+
+Q0203: How can I arrange to do my own qualification of non-fully-qualified
+       domains, and then pass them on to the next router?
+
+A0203: If you have some list of domains that you want to qualify, you can do
+       this using a redirect router. For example,
+
+==>      qualify:
+           driver = redirect
+           domains = *.a.b
+           data = ${quote:$local_part}@$domain.c.com
+
+       This adds \".c.com"\ to any domain that matches \"*.a.b"\.
+       If you want to do this in conjunction with a \%dnslookup%\ router, the
+       \widen_domains\ option of that router may be another way of achieving
+       what you want.
+
+
+Q0204: Every system has a \"nobody"\ account under which httpd etc run. I would
+       like to know how to restrict mail which comes from that account to users
+       on that host only.
+
+A0204: Set up a first router like this:
+
+==>      fail_nobody:
+            driver = redirect
+            senders = nobody@your.domain
+            domains = ! +local_domains
+            allow_fail
+            data = :fail: Nobody may not mail off-site
+
+       This assumes you have defined \+local_domains\ as in the default
+       configuration.
+
+
+Q0205: How can I get Exim to deliver to me locally and everyone else at the same
+       domain via SMTP to the MX record specified host?
+
+A0205: Create an \%accept%\ router to pick off the one address and pass it to
+       an appropriate transport. Put this router before the one that does MX
+       routing:
+
+==>      me:
+           driver = accept
+           domains = dom.com
+           local_parts = me
+           transport = local_delivery
+
+       In the transport you will have to specify the \user\ option. An
+       alternative way of doing this is to add a condition to the router that
+       does MX lookups to make it skip your address. Subsequent routers can then
+       deliver your address locally. You'll need a condition like this:
+
+==>      condition = \
+           ${if and {{eq{$domain}{dom.com}}{eq{$local_part}{me}}}{no}{yes}}
+
+
+Q0206: How can I get Exim to deliver certain domains to a different SMTP port
+       on my local host?
+
+A0206: You must set up a special \%smtp%\ transport, where you can specify the
+       \port\ option, and then set up a router to route the domains to that
+       transport. There are two possibilities for specifying the host:
+
+       (1) If you use a \%manualroute%\ router, you can specify the local host
+           in the router options. You must also set
+
+==>          self = send
+
+           so that it does not object to sending to the local host.
+
+       (2) If you use a router that cannot specify hosts (for example, an
+           \%accept%\ router with appropriate conditions), you have to specify
+           the host using the \hosts\ option of the transport. In this case,
+           you must also set \allow_localhost\ on the transport.
+
+
+Q0207: Why does Exim lower-case the local-part of a non-local domain when
+       routing?
+
+A0207: Because \caseful_local_part\ is not set (in the default configuration)
+       for the \%dnslookup%\ router. This does not matter because the local
+       part takes no part in the routing, and the actual local part that is
+       sent out in the RCPT command is always the original local part.
+
+
+
+3. ROUTING TO REMOTE HOSTS
+
+Q0301: What do \*lowest numbered MX record points to local host*\ and \*remote
+       host address is the local host*\ mean?
+
+A0301: They mean exactly what they say. Exim expected to route an address to a
+       remote host, but the IP address it obtained from a router was for the
+       local host. If you really do want to send over TCP/IP to the local host
+       (to a different version of Exim or another MTA, for example), see Q0206.
+
+       More commonly, these errors arise when Exim thinks it is routing some
+       foreign domain. For example, the router configuration causes Exim to
+       look up the domain in the DNS, but when Exim examines the DNS output,
+       either the lowest numbered MX record points at the local host, or there
+       are no MX records, and the address record for the domain contains an
+       IP address that belongs to the local host.
+
+       There has been a rash of instances of domains being deliberately set up
+       with MX records pointing to \"localhost"\ (or other names with A records
+       that specify 127.0.0.1), which causes this behaviour. You can use the
+       \ignore_target_hosts\ option to get Exim to ignore these records. The
+       default contiguration does this. For more discussion, see Q0319. For
+       other cases:
+
+       (1) If the domain is meant to be handled as a local domain, there
+           is a problem with the configuration, because it should not then have
+           been looked up in the DNS. Check the \domains\ settings on your
+           routers.
+
+       (2) If the domain is one for which the local host is providing a
+           relaying service (called ``mail hubbing''), possibly as part of a
+           firewall, you need to set up a router to tell Exim where to send
+           messages addressed to this domain, because the DNS directs them to
+           the local host. You should put a router like this one before the one
+           that does DNS lookups:
+
+==>          hubbed_hosts:
+               driver = manualroute
+               transport = remote_smtp
+               route_list = see discussion below
+
+           The contents of the \route_list\ option depend on how many hosts you
+           are hubbing for, and how their names are related to the domain name.
+           Suppose the local host is a firewall, and all the domains in
+           \(*.foo.bar)\ have MX records pointing to it, and each domain
+           corresponds to a host of the same name. Then the setting could be
+
+==>          route_list = *.foo.bar $domain
+
+           If there isn't a convenient relationship between the domain names
+           and the host names, you either have to list each domain separately,
+           or use a lookup expansion to look up the host from the domain, or
+           put the routing information in a file and use the \route_data\
+           option with a lookup expansion.
+
+       (3) If neither (1) nor (2) is the case, the lowest numbered MX record or
+           the address record for the domain should not be pointing to your
+           host. You should arrange to get the DNS mended.
+
+
+Q0302: Why does Exim say \*all relevant MX records point to non-existent hosts*\
+       when MX records point to IP addresses?
+
+A0302: MX records cannot point to IP addresses. They are defined to point to
+       host names, so Exim always interprets them that way. (An IP address is a
+       syntactically valid host name.) The DNS for the domain you are having
+       problems with is misconfigured.
+
+       However, it appears that more and more DNS zones are breaking the rules
+       and putting IP addresses on the RHS of MX records. Exim follows the
+       rules and rejects this, but other MTAs do support it, so the
+       \allow_mx_to_ip\ was regretfully added at release 3.14 to permit this
+       heinous activity.
+
+
+Q0303: How do I configure Exim to send all messages to a central server? I
+       don't want to do any local deliveries at all on this host.
+
+A0303: Use this as your first and only router:
+
+==>      send_to_gateway:
+           driver = manualroute
+           transport = remote_smtp
+           route_list = * central.server.host
+
+
+Q0304: How do I configure Exim to send all non-local mail to a gateway host?
+
+A0304: Replace the \%dnslookup%\ router in the default configuration with the
+       following:
+
+==>      send_to_gateway:
+           driver = manualroute
+           domains = !+local_domains
+           transport = remote_smtp
+           route_list = * gate.way.host
+
+       If there are several hosts you can send to, you can specify them as a
+       colon-separated list.
+
+
+Q0305: How can I arrange for mail on my local network to be delivered directly
+       to the relevant hosts, but all other mail to be sent to my ISP's mail
+       server? The local hosts are all DNS-registered and behave like normal
+       Internet hosts.
+
+A0305: Set up a first router to pick off all the domains for your local
+       network. There are several ways you might do this. For example
+
+==>      local_network:
+           driver = dnslookup
+           transport = remote_smtp
+           domains = *.mydomain.com
+
+       This does a perfectly conventional DNS routing operation, but only for
+       the domains that match \(*.mydomain.com)\. Follow this with a `smart
+       host' router:
+
+==>      internet:
+           driver = manualroute
+           domains = !+local_domains
+           transport = remote_smtp
+           route_list = * mail.isp.net
+
+       This routes any other non-local domains to the smart host.
+
+
+Q0306: How do I configure Exim to send all non-local mail to a central server
+       if it cannot be immediately delivered by my host? I don't want to have
+       queued mail waiting on my host.
+
+A0306: Add to the \%remote_smtp%\ transport the following:
+
+==>      fallback_hosts = central.server.name(s)
+
+       If there are several names, they must be separated by colons.
+
+
+Q0307: The \route_list\ setting \"^foo$:^bar$ $domain"\ in a \%manualroute%\
+       router does not work.
+
+A0307: The first thing in a \route_list\ item is a single pattern, not a list of
+       patterns. You need to write that as \"^(foo|bar)$ $domain"\.
+       Alternatively, you could use several items and write
+
+==>      route_list = foo $domain; bar $domain
+
+       Note the semicolon separator. This is because the second thing in each
+       item can itself be a list - of hosts.
+
+
+Q0308: I have a domain for which some local parts must be delivered locally,
+       but the remainder are to be treated like any other remote addresses.
+
+A0308: One possible way of doing this is as follows: Assuming you are using a
+       configuration that is similar to the default one, first exclude your
+       domain from the first router by changing it to look like this:
+
+==>      non_special_remote:
+           driver = dnslookup
+           domains = ! +local_domains : ! special.domain
+           transport = remote_smtp
+           ignore_target_hosts = 127.0.0.0/8
+           no_more
+
+       Then add a second router which handles the local parts that are not to
+       be delivered locally:
+
+==>      special_remote:
+           driver = dnslookup
+           domains = special.domain
+           local_parts = ! lsearch;/list/of/special/localparts
+           transport = remote_smtp
+           ignore_target_hosts = 127.0.0.0/8
+           no_more
+
+       The remaining local parts will fall through to the remaining routers,
+       which can delivery them locally.
+
+
+Q0309: How can I configure Exim on a firewall machine so that if mail arrives
+       addressed to a domain whose MX points to the firewall, it is forwarded
+       to the internal mail server, without having to have a list of all the
+       domains involved?
+
+A0309: As your first router, have the standard \%dnslookup%\ router from the
+       default configuration, with the added option
+
+==>      self = pass
+
+       This will handle all domains whose lowest numbered MX records do not
+       point to your host. Because of the \no_more\ setting, if it encounters
+       an unknown domain, routing will fail. However, if it hits a domain whose
+       lowest numbered MX points to your host, the \self\ option comes into
+       play, and overrides \no_more\. The \"pass"\ setting causes it to pass
+       the address on to the next router. (The default causes it to generate an
+       error.)
+
+       The only non-local domains that reach the second router are those with
+       MX records pointing to the local host. Set it up to send them to the
+       internal mail server like this:
+
+==>      internal:
+           driver = manualroute
+           domains = ! +local_domains
+           transport = remote_smtp
+           route_list = * internal.server
+
+
+Q0310: If a DNS lookup returns no MX records why doesn't Exim just bin the
+       message?
+
+A0310: If a DNS lookup returns no MXs, Exim looks for an address record, in
+       accordance with the rules that are defined in the RFCs. If you want to
+       break the rules, you can set \mx_domains\ in the \%dnslookup%\ router, but
+       you will cut yourself off from those sites (and there still seem to be
+       plenty) who do not set up MX records.
+
+
+Q0311: When a DNS lookup for MX records fails to complete, why doesn't Exim
+       send the messsage to the host defined by the A record?
+
+A0311: The RFCs are quite clear on this. Only if it is known that there are no
+       MX records is an MTA allowed to make use of the A record. When an MX
+       lookup fails to complete, Exim does not know whether there are any MX
+       records or not. There seem to be some name servers (or some
+       configurations of some name servers) that give a ``server fail'' error when
+       asked for a non-existent MX record. Exim uses standard resolver calls,
+       which unfortunately do not distinguish between this case and a timeout,
+       so all Exim can do is try again later.
+
+
+Q0312: Is it possible to use a conditional expression for the host item in a
+       \route_list\ for \%manualroute%\ router? I tried the following, but it
+       doesn't work:
+
+==>      route_list = * ${if match{$header_from:}{\N.*\.usa\.net$\N} \
+                      {<smarthost1>}{<smarthost2>}
+
+A0312: The problem is that the second item in \route_list\ contains white
+       space, which means that it gets terminated prematurely. To avoid this,
+       you must put the second item in quotes:
+
+==>      route_list = * "${if match{$header_from:}{\N.*\.usa\.net$\N} \
+                      {<smarthost1>}{<smarthost2>}}"
+
+
+Q0313: I send all external mail to a smart host, but this means that bad
+       addresses also get passed to the smart host. Can I avoid this?
+
+A0313: Assuming you have DNS availability, set up a conventional \%dnslookup%\
+       router to do the routing, but in the \%remote_smtp%\ transport set this:
+
+==>    hosts = your.smart.host
+       hosts_override
+
+       This will override the hosts that the router finds so that everything
+       goes to the smart host, but any non-existent domains will be failed by
+       the router.
+
+
+Q0314: I have a really annoying intermittent problem where attempts to mail to
+       valid sites are rejected with \*unknown mail domain*\. This only happens a
+       few times a day and there is no particular pattern to the sites it
+       rejects. If I try to lookup the same domain a few minutes later then it
+       is OK.
+
+A0314: This is almost certainly a problem with the DNS resolver or the the
+       domain's name servers.
+
+       (1) Have you linked Exim against the newest DNS resolver library that
+       comes with Bind? If you are using SunOS4 that may be your problem, as
+       the resolver that comes with that OS is known to be buggy and to give
+       intermittent false negatives.
+
+       (2) Effects like this are sometimes seen if a domain's name servers get
+       out of step with each other.
+
+
+Q0315: I'd like route all mail with addresses that can't be resolved (the DNS
+       lookup times out) to a relay machine.
+
+A0315: Set \pass_on_timeout\ on your \%dnslookup%\ router, and add below it a
+       \%manualroute%\ router that routes all relevant domains to the relay.
+
+
+Q0316: I would like to forward all incoming email for a particular domain to
+       another host via SMTP. Whereabouts would I configure that?
+
+A0316: Use this as your first router:
+
+==>      special:
+           driver = manualroute
+           transport = remote_smtp
+           route_list = the.particular.domain the.other.host
+
+       You will also need to adjust the ACL for incoming SMTP so that this
+       domain is accepted for relaying. If you are using the default
+       configuration, there is a domain list called \relay_domains\ that is
+       set up for this.
+
+
+Q0317: What I'd like to do is have alternative smart hosts, where the one to be
+       used is determined by which ISP I'm connected to.
+
+A0317: The simplest way to do this is to arrange for the name of the smart host
+       du jour to be placed in a file when you connect, say \(/etc/smarthost)\.
+       Then you can read this file from a \%manualroute%\ router like this:
+
+==>      smarthost:
+           driver = manualroute
+           transport = remote_smtp
+           route_list = * ${readfile{/etc/smarthost}{}}
+
+       The second argument of the \"readfile"\ item is a string that replaces
+       any newline characters in the file (in this case, with nothing).
+       By keeping the data out of the main configuration file, you avoid having
+       to HUP the daemon when it changes.
+
+
+Q0318: Exim won't route to a host with no MX record.
+
+A0318: More than one thing may cause this.
+
+       (1) Are you sure there really is no MX record? Sometimes a typo results
+       in a malformed MX record in the zone file, in which case some name
+       servers give a SERVFAIL error rather than NXDOMAIN. Exim has to treat
+       this as a temporary error, so it can't go on to look for address records.
+       You can check for this state using one of the DNS interrogation commands,
+       such as \(nslookup)\, \(host)\, or \(dig)\.
+
+       (2) Is there a wildcard MX record for \(your)\ domain? Is the
+       \search_parents\ option on in your \%dnslookup%\ router? If the answer to
+       both these questions is ``yes'', that is the cause of the problem. When
+       the DNS resolver fails to find the MX record, it tries adding on your
+       domain if \search_parents\ is true, and thereby finds your wildcard MX
+       record. For example:
+
+         .  There is a wildcard MX record for \(*.a.b.c)\.
+
+         .  There is a host called \(x.y.z)\ that has an A record and no MX record.
+
+         .  Somebody on the host \(m.a.b.c)\ domain tries to mail to \(user@x.y.z)\.
+
+         .  Exim calls the DNS to look for an MX record for \(x.y.z)\.
+
+         .  The DNS doesn't find any MX record. Because \search_parents\ is true,
+            it then tries searching the current host's parent domain, so it
+            looks for \(x.y.z.a.b.c)\ and picks up the wildcard MX record.
+
+       Setting \search_parents\ false makes this case work while retaining the
+       wildcard MX record. However, anybody on the host \(m.a.b.c)\ who mails to
+       \(user@n.a)\ (expecting it to go to \(user@n.a.b.c)\) now has a problem. The
+       \widen_domains\ option of the \%dnslookup%\ router may be helpful in this
+       circumstance.
+
+
+Q0319: I have some mails on my queues that are sticking around longer than
+       the retry time indicates they should. They are all getting frozen
+       because some remote admin has set their MX record to 127.0.0.1.
+
+A0319: The admin in question is an idiot. Exim will always freeze such messages
+       because they are apparently routed to the local host. To bounce these
+       messages immediately, set
+
+==>      ignore_target_hosts = 127.0.0.1
+
+       on the \%dnslookup%\ router. This causes Exim to completely ignore any hosts
+       with that IP address. In fact, there are quite a number of IP addresses
+       that should never be used. Here is a suggested configuration list for
+       the IPv4 ones:
+
+==>      # Don't allow domains whose single MX (or A) record is a
+         # "special-use IPv4 address", as listed in RFC 3330.
+         ignore_target_hosts = \
+              # Hosts on "this network"; RFC 1700 (page 4) states that these
+              # are only allowed as source addresses
+              0.0.0.0/8 : \
+              # Private networks, RFC 1918
+              10.0.0.0/8 : 172.16.0.0/12 : 192.168.0.0/16 : \
+              # Internet host loopback address, RFC 1700 (page 5)
+              127.0.0.0/8 : \
+              # "Link local" block
+              169.254.0.0/16 : \
+              # "TEST-NET" - should not appear on the public Internet
+              192.0.2.0/24 : \
+              # 6to4 relay anycast addresses, RFC 3068
+              192.88.99.0/24 : \
+              # Network interconnect device benchmark testing, RFC 2544
+              198.18.0.0/15 : \
+              # Multicast addresses, RFC 3171
+              224.0.0.0/4 : \
+              # Reserved for future use, RFC 1700 (page 4)
+              240.0.0.0/4
+
+
+Q0320: How can I arrange for all mail to \*user@some.domain*\ to be forwarded
+       to \*user@other.domain*\?
+
+A0320: Put this as your first router:
+
+==>      forward:
+           driver = redirect
+           domains = some.domain
+           data = ${quote:$local_part}@other.domain
+
+
+Q0321: How can I tell an Exim router to use only IPv4 or only IPv6 addresses
+       when it finds both types in the DNS?
+
+A0321: You can do this by making it ignore the addresses you don't want. This
+       example ignores all IPv6 addresses and all IPv4 addresses in the 127
+       network:
+
+==>      ignore_target_hosts = <; 0000::0000/0 ; 127.0.0.0/8
+
+       To ignore all IPv4 addresses, use
+
+==>      ignore_target_hosts = 0.0.0.0/0
+
+       See Q0319 for a general discussion of \ignore_target_hosts\.
+
+
+Q0322: How can I reroute all messages bound for 192.168.10.0 and 10.0.0.0 to
+       a specific mail server?
+
+A0322: That is an odd requirement. However, there is an obscure feature in
+       Exim, originally implemented for packet radio people, that perhaps can
+       help. Check out the \translate_ip_address\ generic router option.
+
+
+
+4. ROUTING FOR LOCAL DELIVERY
+
+Q0401: I need to have any mail for \(virt.dom.ain)\ that doesn't match one of the
+       aliases in \(/usr/lib/aliases.virt)\ delivered to a particular address, for
+       example, \(postmaster@virt.dom.ain)\.
+
+A0401: Adding an asterisk to a search type causes Exim to look up ``*'' when the
+       normal lookup fails. So if your aliasing router is something like this:
+
+==>      virtual:
+           driver = redirect
+           domains = virt.dom.ain
+           data = ${lookup{$local_part}lsearch{/usr/lib/aliases.virt}}
+           no_more
+
+       you should change \"lsearch"\ to \"lsearch*"\, and put this in the alias
+       file:
+
+==>      *: postmaster@virt.dom.ain
+
+       This solution has the feature that if there are several unknown
+       addresses in the same message, only one copy gets sent to the
+       postmaster, because of Exim's normal de-duplication rules.
+
+       NOTE: This solution works only if there is also an entry for \(postmaster)\
+       in the alias file, ultimately resolving to an address that is not in
+       \(virt.dom.ain)\. See also Q0434.
+
+
+Q0402: How do I arrange for all incoming email for \(*@some.domain)\ to go into one
+       pop3 mail account? The customer doesn't want to add a list of specific
+       local parts to the system.
+
+A0402: Set up a special transport that writes to the mailbox like this:
+
+==>      special_transport:
+           driver = appendfile
+           file = /pop/mailbox
+           envelope_to_add
+           return_path_add
+           delivery_date_add
+           user = exim
+
+       The file will be written as the user \"exim"\. Then arrange to route all
+       mail for that domain to that transport, with a router like this:
+
+==>      special_router:
+           driver = accept
+           domains = some.domain
+           transport = special_transport
+
+
+Q0403: How do I configure Exim to send messages for unknown local users to a
+       central server?
+
+A0403: Assuming you are using something like the default configuration, where
+       local users are processed by the later routers, you should add the
+       following router at the end:
+
+==>      unknown:
+           driver = manualroute
+           transport = remote_smtp
+           route_list = * server.host.name
+           no_verify
+
+       However, you should if possible try to verify that the user is known on
+       the central server before accepting the message in the first place. This
+       can be done by making use of Exim's ``call forward'' facility.
+
+
+Q0404: How can I arrange for messages submitted by (for example) Majordomo to
+       be handled specially?
+
+A0404: You can use the \condition\ option on a router, with a setting such as
+
+==>      condition = ${if and {{eq {$sender_host_address}{}} \
+                     {eq {$sender_ident}{majordom}}} {yes}{no}}
+
+       This first tests for a locally-submitted message, by ensuring there is
+       no sending host address, and then it checks the identity of the user
+       that ran the submitting process.
+
+
+Q0405: On a host that accepts mail for several domains, do I have to use fully
+       qualified addresses in \(/etc/aliases)\ or do I have to set up an alias
+       file for each domain?
+
+A0405: You can do it either way. The default aliasing router contains this line:
+
+==>      data = ${lookup{$local_part}lsearch{/etc/aliases}}
+
+       which is what does the actual lookup. To make it look up the complete
+       address instead of just the local part, use
+
+==>      data = ${lookup{$local_part@$domain}lsearch{/etc/aliases}}
+
+       If you want to use a separate file for each domain, use
+
+==>      data = ${lookup{$local_part}lsearch{/etc/aliases/$domain}}
+
+
+Q0406: Some of my users are using the \(.forward)\ to pipe to a shell command which
+       appends to the user's INBOX. How can I forbid this?
+
+A0406: If you allow your users to run shells in pipes, you cannot control which
+       commands they run or which files they write to. However, you should point
+       out to them that writing to an INBOX by arbitrary commands is not
+       interlocked with the MTA and MUAs, and is liable to mess up the contents
+       of the file.
+
+       If a user simply wants to choose a specific file for the delivery of
+       messages, this can be done by putting a file name in a \(.forward)\ file
+       rather than using a pipe, or by using the \"save"\ command in an Exim
+       filter file.
+
+       You can set \forbid_pipe\ on the router, but that will prevent them from
+       running any pipe commands at all. Alternatively, you can restrict which
+       commands they may run in their pipes by setting the \allow_commands\
+       and/or \restrict_to_path\ options in the \%address_pipe%\ transport.
+
+
+Q0407: How can I arrange for a default value when using a query-style lookup
+       such as LDAP or NIS+ to handle aliases?
+
+A0407: Use a second query in the failure part of the original lookup, like
+       this:
+
+==>      data = ${lookup ldap\
+           {ldap://x.y.z/l=yvr?aliasaddress?sub?(&(mail=$local_part@$domain))}\
+           {$value}\
+           {\
+           ${lookup ldap \
+             {ldap://x.y.z/l=yvr?aliasaddress?sub?(&(mail=default@$domain))}}\
+           }}
+
+        Of course, if the default is a fixed value you can just include it
+        directly.
+
+
+Q0408: If I don't fully qualify the addresses in a virtual domain's alias file
+       then mail to aliases which also match the local domain get delivered to
+       the local domain.
+
+A0408: Set the \qualify_preserve_domain\ option on the \%redirect%\ router.
+
+
+Q0409: I want mail for any local part at certain virtual domains to go
+       to a single address for each domain.
+
+A0409: One way to to this is
+
+==>      virtual:
+           driver = redirect
+           data = ${lookup{$domain}lsearch{/etc/virtual}}
+
+       The \(/etc/virtual)\ file contains a list of domains and the addresses to
+       which their mail should be sent. For example:
+
+==>       domain1:  postmaster@some.where.else
+          domain2:  joe@xyz.plc
+
+       If the number of domains is large, using a DBM or cdb file would be more
+       efficient. If the lookup fails to find the domain in the file, the value
+       of the \data\ option is empty, causing the router to decline.
+
+
+Q0410: How can I make Exim look in the alias NIS map instead of \(/etc/aliases)\?
+
+A0410: The default configuration does not use NIS (many hosts don't run it).
+       You need to change this line in the \%system_aliases%\ router:
+
+==>      data = ${lookup{$local_part}lsearch{/etc/aliases}}
+
+       Change it to
+
+==>      data = ${lookup{$local_part}nis{mail.aliases}}
+
+       If you want to use \(/etc/aliases)\ as well as NIS, put this router (with
+       a different name) before or after the default one, depending on which
+       data source you want to take precedence.
+
+
+Q0411: Why will Exim deliver a message locally to any username that is longer
+       than 8 characters as long as the first 8 characters match one of the
+       local usernames?
+
+A0411: The problem is in your operating system. Exim just calls the \^^getpwnam()^^\
+       function to test a local part for being a local login name. It does not
+       presume to guess the maximum length of user name for the underlying
+       operating system. Many operating systems correctly reject names that are
+       longer than the maximum length; yours is apparently deficient in this
+       regard. To cope with such systems, Exim has an option called
+       \max_user_name_length\ which you can set to the maximum allowed length.
+
+
+Q0412: Why am I seeing the error \*bad mode (100664) for /home/test/.forward*\?
+       I've looked through the documentation but can't see anything to suggest
+       that Exim has to do anything other than read the \(.forward)\ file.
+
+A0412: For security, Exim checks for mode bits that shouldn't be set, by
+       default 022. You can change this by setting the \modemask\ option of the
+       \%redirect%\ router that is handling \(.forward)\ files.
+
+
+Q0413: When a user's \(.forward)\ file is syntactially invalid, Exim defers
+       delivery of all messages to that user, which sometimes include the
+       user's own test messages. Can it be told to ignore the \(.forward)\ file
+       and/or inform the user of the error?
+
+A0413: Setting \skip_syntax_errors\ on the redirect router causes syntax
+       errors to be skipped. When dealing with users' \(.forward)\ files it is best
+       to combine this with a setting of \syntax_errors_to\ in order to send
+       a message about the error to the user. However, to avoid an infinite
+       cascade of messages, you have to be able to send to an address that
+       bypasses \(.forward)\ file processing. This can be done by including a
+       router like this one
+
+==>      real_localuser:
+           driver = accept
+           check_local_user
+           transport = local_delivery
+           prefix = real-
+
+       before the \%redirect%\ router that handles \(.forward)\ files. This will
+       do an ordinary local delivery without \(.forward)\ processing, if the
+       local part is prefixed by \"real-"\. You can then set something like
+       the following options on the \%redirect%\ router:
+
+==>      skip_syntax_errors
+         syntax_errors_to = real-$local_part@$domain
+         syntax_errors_text = "\
+           This is an automatically generated message. An error has been \
+           found\nin your .forward file. Details of the error are reported \
+           below. While\nthis error persists, messages addressed to you will \
+           get delivered into\nyour normal mailbox and you will receive a \
+           copy of this message for\neach one."
+
+       A final tidying setting to go with this is a rewriting rule that changes
+       \"real-username"\ into just \"username"\ in the headers of the message:
+
+==>      \N^real-([^@]+)@your\.dom\.ain$\N    $1@your.dom.ain   h
+
+       This means that users won't ever see the \"real-"\ prefix, unless they
+       look at the ::Envelope-To:: header.
+
+
+Q0414: I have set \caseful_local_part\ on the routers that handle my local
+       domain because my users have upper case letters in their login names,
+       but incoming mail now has to use the correct case. Can I relax this
+       somehow?
+
+A0414: If you really have to live with caseful user names but want incoming
+       local parts to be caseless, then you have to maintain a file, indexed by
+       the lower case forms, that gives the correct case for each login, like
+       this:
+
+==>      admin:    Admin
+         steven:   Steven
+         mcdonald: McDonald
+         lamanch:  LaManche
+         ...
+
+       and at the start of the routers that handle your local domain, put one
+       like this:
+
+==>      set_case_router:
+           driver = redirect
+           data = ${lookup{${lc:$local_part}}lsearch{/the/file}}
+           qualify_preserve_domain
+
+       For efficiency, you should also set the \redirect_router\ option to cause
+       processing of the changed address to begin at the next router. If you
+       are otherwise using the default configuration, the setting would be
+
+==>      redirect_router = system_aliases
+
+       If there are lots of users, then a DBM or cdb file would be more
+       efficient than a linear search. If you are handling several domains,
+       you will have to extend this configuration to cope appropriately.
+
+
+Q0415: Can I use my existing alias files and forward files as well as procmail
+       and effectively drop in Exim in place of Sendmail ?
+
+A0415: Yes, as long as your alias and forward files don't assume that pipes are
+       going to run under a shell. If they do, you either have to change them,
+       or configure Exim to use a shell (which it doesn't by default).
+
+
+Q0416: What is quickest way to set up Exim so any message sent to a
+       non-existing user would bounce back with a different message, based
+       on the name of non-existing user?
+
+A0416: Place this router last, so that it catches any local addresses that
+       are not otherwise handled:
+
+==>      non_exist:
+           driver = accept
+           transport = non_exist_reply
+           no_verify
+
+       Then add the following transport to the transports section:
+
+==>      non_exist_reply:
+           driver = autoreply
+           user = exim
+           to = $sender_address
+           subject = User does not exist
+           text = You sent mail to $local_part. That's not a valid user here. \
+                  The subject was: $subject.
+
+       If you want to pick up a message from a file, you can use the \file\
+       option (use \file_expand\ if you want its contents expanded).
+
+
+Q0417: What do I need to do to make Exim handle \(/usr/ucb/vacation)\ processing
+       automatically, so that people could just create a \(.vacation.msg)\ file in
+       their home directory and not have to edit their \(.forward)\ file?
+
+A0417: Add a new router like this, immediately before the normal \%localuser%\
+       router:
+
+==>      vacation:
+           driver = accept
+           check_local_user
+           require_files = $home/.vacation.msg
+           transport = vacation_transport
+           unseen
+
+       and a matching new transport like this:
+
+==>      vacation_transport:
+           driver = pipe
+           command = /usr/ucb/vacation $local_part
+
+       However, some versions of \(/usr/ucb/vacation)\ do not work properly unless
+       the DBM file(s) it uses are created in advance - it won't create them
+       itself. You also need a way of removing them when the vacation is over.
+
+       Another possibility is to use a fixed filter file which is run whenever
+       \(.vacation.msg)\ exists, for example:
+
+==>      vacation:
+           driver = redirect
+           check_local_user
+           require_files = $home/.vacation.msg
+           file = /some/central/filter
+           allow_filter
+
+       The filter file should use the \"if personal"\ check before sending mail,
+       to avoid generating automatic responses to mailing lists. If sending a
+       message is all that it does, this doesn't count as a ``significant''
+       delivery, so the original message goes on to be delivered as normal.
+
+       Yet another possibility is to make use of Exim's \%autoreply%\ transport,
+       and not use \(/usr/ucb/vacation)\ at all.
+
+
+Q0418: I want to use a default entry in my alias file to handle unknown local
+       parts, but it picks up the local parts that the aliases generate. For
+       example, if the alias file is
+
+==>      luke.skywalker: luke
+         ls: luke
+         *: postmaster
+
+       then messages addressed to \/luke.skywalker/\ end up at \/postmaster/\.
+
+A0418: The default mechanism works best with virtual domains, where the
+       generated address is not in the same domain. If you just want to pick up
+       all unknown local parts and send them to postmaster, an easier way to do
+       it is to put this as your last router:
+
+==>      unknown:
+           driver = redirect
+           data = postmaster
+           no_verify
+
+       Another possibility is to put the redirect router for these aliases
+       after all the other routers, so that local parts which are user names
+       get picked off first. You will need to have two aliasing routers if
+       there are some local parts (e.g. \/root/\) which are login names, but which
+       you want to handle as aliases.
+
+
+Q0419: I have some obsolete domains which people have been warned not to use
+       any more. How can I arrange to delete any mail that is sent to them?
+
+A0419: To reject them at SMTP time, with a customized error message, place
+       statments like this in the ACL:
+
+==>      deny message = The domain $domain is obsolete
+              domains = lsearch;/etc/exim/obsolete.domains
+
+       For messages that don't arrive over SMTP, you can use a router like
+       this to bounce them:
+
+==>      obsolete:
+           driver = redirect
+           domains = lsearch;/etc/exim/obsolete.domains
+           allow_fail
+           data = :fail: the domain $domain is obsolete
+
+       If you just want to throw away mail to those domains, accept them at
+       SMTP time, and use a router like this:
+
+==>      obsolete:
+           domains = lsearch;/etc/exim/obsolete.domains
+           data = :blackhole:
+
+
+Q0420: How can I arrange that mail addressed to \(anything@something.mydomain.com)\
+       gets delivered to \(something@mydomain.com)\?
+
+A0420: Set up a router like this:
+
+==>      user_from_domain:
+           driver = redirect
+           data = ${if match{$domain}{\N^(.+)\.mydomain\.com$\N}\
+             {$1@mydomain.com}}
+
+
+Q0421: I can't get a regular expression to work in a \local_parts\ option on
+       one of my routers.
+
+A0421: Have you remembered to protect any backslash and dollar characters in
+       your regex from unwanted expansion? The easiest way is to use the
+       \"@\N"\ facility, like this:
+
+==>      local_parts = \N^0740\d{6}\N
+
+
+Q0422: How can I arrange for all addresses in a group of domains \(*.example.com)\
+       to share the same alias file? I have a number of such groups.
+
+A0422: For a single group you could just hard wire the file name into a router
+       that had
+
+==>      domains = *.example.com
+
+       set, to restrict it to the relevant domains. For a number of such groups
+       you can create a file containing the domains, like this:
+
+==>      *.example1.com    example1.com
+         *.example2.com    example2.com
+         ...
+
+       Then create a router like this
+
+==>      domain_aliases:
+           driver = redirect
+           domains = partial-lsearch;/that/file
+           data = ${lookup{$local_part}lsearch*{/etc/aliases.d/$domain_data}}
+
+       The variable \$domain_data$\ contains the data that was looked up when the
+       \domains\ option was matched, i.e. \"example1.com"\, \"example2.com"\, etc.
+       in this case.
+
+
+Q0423: Some of our users have no home directories; the field in the password
+       file contains \(/no/home/dir)\. This causes the error \*failed to stat
+       /no/home/dir (No such file or directory)*\ when Exim tries to look for a
+       \(.forward file)\, and the delivery is deferred.
+
+A0423: There are two issues involved here:
+
+       (1) With the default configuration, you are asking Exim to check for a
+       \(.forward)\ file in the user's home directory. If no file is found,
+       Exim tries to \^^stat()^^\ the home directory. This is so that it will
+       notice a missing NFS home directory, and not treat it as if the
+       \(.forward)\ file did not exist. This \^^stat()^^\ is failing when the
+       home directory really doesn't exist. You should arrange for the
+       \%userforward%\ router not to run for these special users, by adding
+       this line:
+
+==>      condition = ${if eq {$home}{/no/home/dir}{no}{yes}}
+
+       (2) If you use \check_local_user\ on another router to route to a local
+       transport (again, this is what is in the default configuration), you
+       will also have to specify a current directory for the transport, because
+       by default it makes the home directory current. This is easily done by
+       adding
+
+==>      current_directory = /
+
+       to the transport or
+
+==>      transport_current_directory = /
+
+       to the router. Or you can add \home_directory\ to the transport, because
+       the current directory defaults to the home directory.
+
+
+Q0424: How can I disable Exim's de-duplication features? I want it to do two
+       deliveries if two different aliases expand to the same address.
+
+A0424: This is not possible. Duplication has other ramifications other than
+       just (in)convenience. Consider:
+
+         . Message is addressed to A and to B.
+
+         . Both A and B are aliased to C.
+
+         . Without de-duplication, two deliveries to C are scheduled.
+
+         . One delivery happens, Exim records that it has delivered the message
+           to C.
+
+         . The next delivery fails (C's mailbox is over quota, say).
+
+       Next time round, Exim wants to know if it has already delivered to C or
+       not, before scheduling a new delivery. Has it? Obviously, if duplicate
+       deliveries are supported, it has to remember not only that it has
+       delivered to C but also the ``history'' of how that delivery happened - in
+       effect an ancestry list back to the original envelope address. This it
+       does not do, and changing it to work in that way would be a lot of work
+       and a big upheaval.
+
+       The best way to get duplicate deliveries if you want them is not to use
+       aliases, but to route the addresses directly to a transport, e.g.
+
+==>    duplicates:
+         driver = accept
+         local_parts = lsearch;/etc/list/of/special/local/parts
+         transport = local_delivery
+         user = exim
+
+
+Q0425: My users' mailboxes are distributed between several servers according to
+       the first letter of the user name. All the servers receive incoming mail
+       at random. I would like to have the same configuration file for all the
+       servers, which does local delivery for the mailboxes it holds, and sends
+       other addresses to the correct other server. Is this possible?
+
+A0425: It is easiest if you arrange for all the users to have password entries
+       on all the servers. This means that non-existent users can be detected
+       at the first server they reach. Set up a file containing a mapping from
+       the first letter of the user names to the servers where their mailboxes
+       are held. For example:
+
+==>      a: server1
+         b: server1
+         c: server2
+         ...
+
+       Before the normal \%localuser%\ router, place the following router:
+
+==>      mailbox_host:
+           driver = manualroute
+           check_local_user
+           transport = remote_smtp
+           route_list = * ${lookup{${substr_0_1:$local_part}}lsearch{/etc/mapfile}}
+           self = pass
+
+       This router checks for a local account, then looks up the host from the
+       first character of the local part. If the host is not the local host,
+       the address is routed to the \%remote_smtp%\ transport, and sent to the
+       correct host. If the host is the local host, the \self\ option causes
+       the router to pass the address to the next router, which does a local
+       delivery.
+
+       The router is skipped for local parts that are not the names of local
+       users, and so these addresses fail.
+
+
+Q0426: One of the things I want to set up is for \(anything@onedomain)\ to forward
+       to \(anything@anotherdomain)\. I tried adding \($local_part@anotherdomain)\ to
+       my aliases but it did not expand - it sent it to that literal address.
+
+A0426: If you want to do it that way, you can use the \"expand"\ operator on
+       the lookup used in the data option of the redirect router. For example:
+
+==>      data = ${expand:${lookup{$local_part}lsearch*{/etc/aliases}}}
+
+       Another approach is to use a router like this:
+
+==>      forwarddomain:
+           driver = redirect
+           domains = onedomain
+           data = $local_part@anotherdomain
+
+       The value of \data\ can, of course, be more complicated, involving
+       lookups etc. if you have lots of different cases.
+
+
+Q0427: How can I have an address looked up in two different alias files, and
+       delivered to all the addresses that are found?
+
+A0427: Use a router like this:
+
+==>      multi_aliases:
+           driver = redirect
+           data = ${lookup{$local_part}lsearch{/etc/aliases1}\
+             {$value${lookup{$local_part}lsearch{/etc/aliases2}{,$value}}}\
+             {${lookup{$local_part}lsearch{/etc/aliases2}{$value}fail}}}\
+
+       If the first lookup succeeds, the result is its data, followed by the
+       data from the second lookup, if any, separated by a comma. If the first
+       lookup fails, the result is the data from the third lookup (which also
+       looks in the second file), but if this also fails, the entire expansion
+       is forced to fail, thereby causing the router to decline.
+
+       Another approach is to use two routers, with the first re-generating the
+       original local part when it succeeds. This won't get processed by the
+       same router again. For example:
+
+==>      multi_aliases1:
+           driver = redirect
+           data = ${lookup{$local_part}lsearch{/etc/aliases1}{$value,$local_part}}
+
+==>      multi_aliases2:
+           data = ${lookup{$local_part}lsearch{/etc/aliases2}}
+
+       This scales more easily to three or more alias files.
+
+
+Q0428: I've converted from Sendmail, and I notice that Exim doesn't make use
+       of the \"owner-"\ entries in my alias file to change the sender address in
+       outgoing messages to a mailing list.
+
+A0428: If you have an alias file with entries like this:
+
+==>      somelist:        a@b, c@d, ...
+         owner-somelist:  postmaster
+
+       Sendmail assumes that the second entry specifies a new sender address
+       for the first. Exim does not make this assumption. However, you can make
+       it take the same action, by adding
+
+==>      errors_to = owner-$local_part@whatever.domain
+
+       to the configuration for your aliasing router. This is fail-safe,
+       because Exim verifies a new sender address before using it. Thus, the
+       change of sender address occurs only when the owner entry exists.
+
+
+Q0429: I would like to deliver mail addressed to a given domain to local
+       mailboxes, but also to generate messages to the envelope senders.
+
+A0429: You can do this with an ``unseen'' router and an \%autoreply%\ transport,
+       along the following lines:
+
+==>      # Router
+         auto_warning_r:
+           driver = accept
+           check_local_user
+           domains = <domains you want to do this for>
+           condition = ${if eq{$sender_address}{}{no}{yes}}
+           transport = warning_t
+           no_verify
+           unseen
+
+       Place this router immediately before the normal \%localuser%\ router. The
+       \unseen\ option means that the address is still passed on to the next
+       router. The transport is configured like this:
+
+==>      # Transport
+         warning_t:
+           driver = autoreply
+           file = /usr/local/mail/warning.txt
+           file_expand
+           from = postmaster@your.domain
+           to = $sender_address
+           user = exim
+           subject = Re: Your mail to $local_part@$domain
+
+       Note the use of the \condition\ option to avoid attempting to send a
+       message when there is no sender (that is, when the incoming message is a
+       bounce message). You can of course extend this to include other
+       conditions. If you want to log the sending of messages, you can add
+
+==>      log = /some/file
+
+       to the transport and also make use of the \once\ option if you want to
+       send only one message to each sender.
+
+
+Q0430: Whenever Exim tries to route a local address, it gives a permission
+       denied error for the \(.forward)\ file, like this:
+
+==>      1998-08-10 16:55:32 0z5y2W-0000B8-00 == xxxx@yyy.zzz <xxxx@yyy.zz>
+           D=userforward defer (-1): failed to open /home/xxxx/.forward
+           (userforward router): Permission denied (euid=1234 egid=101)
+
+A0430: Have you remembered to make Exim setuid \/root/\?
+
+
+Q0431: How do I configure Exim to allow arbitrary extensions in local parts, of
+       the form \/+extension/\?
+
+A0431: Add this pre-condition to the relevant router:
+
+==>      local_part_suffix = +*
+
+       If you want the extensions to be optional, also add the option
+
+==>      local_part_suffix_optional
+
+       When the router runs, \$local_part$\ contains the local part with the
+       extension removed, and the extension (if any) is in \$local_part_suffix$\.
+       If you have set \check_local_user\, the test is carried out after the
+       extension is removed.
+
+
+Q0432: I use NIS for my user data. How can I stop Exim rejecting mail when my
+       NIS servers are being restarted?
+
+A0432: Exim doesn't know that you are using NIS; it just calls the \^^getpwnam()^^\
+       function, which is routed by nsswitch. Unfortunately, \^^getpwnam()^^\
+       was never designed to be routed through NIS, and it returns NULL if the
+       entry is not found or if the connection to the NIS server fails. This
+       means that Exim cannot tell the difference between ``no such user'' and
+       ``NIS is down''.
+
+       Crutches to help with this problem are \finduser_retries\ in Exim, and
+       \^nscd^\ on the Unix side, but they are not perfect, and mail can still
+       be lost. However, Nico Erfurth pointed out that you can create a router
+       for Exim that tests for the availability of NIS, and force a defer if
+       NIS is not running:
+
+==>      check_nis:
+            driver = redirect
+            data = ${lookup {$local_part} nis {passwd}{}}
+
+       This should be placed before any router that makes any use of NIS,
+       typically at the start of your local routers. How does it work? If
+       your NIS server is reachable, the lookup will take place, and whether it
+       succeeds or fails, the result is an empty strting. This causes the
+       router to decline, and the address is passed to the following routers.
+       If your NIS server is down, the lookup defers, and this causes the
+       router to defer. A verification of an incoming address gets a temporary
+       rejection, and a delivery is deferred till later.
+
+
+Q0433: How can I arrange for a single address to be processed by \*both*\
+       \%redirect%\ \*and*\ \%accept%\?
+
+A0433: Check out the \unseen\ option.
+
+
+Q0434: How can I redirect all local parts that are not in my system aliases to
+       a single address? I tried using an asterisk in the system alias file
+       with an \"lsearch*"\ lookup, but that send \*all*\ messages to the
+       default address.
+
+A0434: If your alias file generates addresses in the local domain, they are
+       also processed as a potential aliases. For example, suppose this is your
+       alias file:
+
+==>      caesar:   jc
+         anthony:  ma
+         *:        brutus
+
+       The local part \/caesar/\ is aliased to \/jc/\, but that address is then
+       reprocessed by the routers. As the address is in the local domain, the
+       alias file is again consulted, and this time the default matches. In
+       fact after the second aliasing, \/brutus/\ is also processed again from
+       the start, and is aliased to itself. However, this happens only once,
+       because the next time, Exim notices that the aliasing router has already
+       processed \/brutus/\, so the router is skipped in order to avoid
+       looping.
+
+       There are several ways of solving this problem; which one you use
+       depends on your aliasing data.
+
+       (1) If the result of aliasing is always a local user name, that is,
+           aliasing never generates another alias, you can use the
+           \redirect_router\ option on the router to specify that processing
+           the generated addresses must start at the next router. For example:
+
+==>          redirect_router = userforward
+
+           assuming that the next router is called \%userforward%\. This
+           ensures that there is at most one pass through the aliasing router.
+
+       (2) If you cannot rely on aliases generating non-aliases, it is often
+           easier not to use a default alias, but instead to place a router
+           such as the one below after all the other local routers (for the
+           relevant domains):
+
+==>          catch_unknown:
+               driver = redirect
+               domains = ...
+               data = brutus@$domain
+
+       Note that the default aliasing technique works more successfully for
+       virtual domains (see Q0401) because the generated address for the
+       default is not usually in the same virtual domain as the incoming
+       address.
+
+
+Q0435: My alias file contains fully qualified addresses as keys, and some
+       wildcard domains in the form @foo.bar. Can Exim handle these?
+
+A0435: You can handle fully qualified addresses with this router:
+
+==>      qualified_aliases:
+           driver = redirect
+           data = ${lookup{$local_part@$domain}lsearch{/etc/aliases}}
+
+       (Add any other options you need for the \%redirect%\ router.) Place this
+       router either before or after the default aliases router that looks up
+       the local part only. (Or, if you have no unqualified aliases, replace
+       the default router.)
+
+       To handle wildcards in the form @foo.bar you will need yet another
+       router. (Wildcards of the form *@foo.bar can be handled by an lsearch*@
+       lookup.) Something like this:
+
+==>      wildcard_aliases:
+           driver = redirect
+           data = ${lookup{@$domain}lsearch{/etc/aliases}}
+
+       Place this after the routers that handle the more specific aliases.
+
+
+
+5. FILTERING
+
+Q0501: My filter isn't working. How can I test it?
+
+A0501: Use the \-bf-\ option (\-bF-\ for a system filter) to test the basic operation
+       of your filter. You can request debugging information for filtering only
+       by adding \"-d-all+filter"\ to the command.
+
+
+Q0502: What I really need is the ability to obtain the result of a pipe
+       command so that I can filter externally and redirect internally. Is
+       this possible?
+
+A0502: The result of a pipe command is not available to a filter, because Exim
+       does not run any actual deliveries while filtering. It just sets up
+       deliveries at this time. They all actually happen later. If you want to
+       run pipes and examine their results, you need to set up a single
+       delivery to a delivery agent such as \^procmail^\ which provides this kind
+       of facility.
+
+       An possible alternative is to use the \"${run"\ expansion item to run an
+       external command while filtering. In this case, you can make use of some
+       of the results of the command.
+
+
+Q0503: I received a message with a ::Subject:: line that contained a non-printing
+       character (a carriage return). This messed up my filter file. Is there a
+       way to get round it?
+
+A0503: Instead of \"$h_subject:"\ use \"${escape:$h_subject:}"\
+
+
+Q0504: I want to search for \"$"\ in the subject line, but I can't seem to get
+       the syntax.
+
+A0504: Try one of these:
+
+==>      if $h_subject: contains \$ then ...
+         if $h_subject: contains "\\$" then ...
+
+
+Q0505: My problem is that Exim replaces \$local_part$\ with an empty string in the
+       system filtering. What's wrong or what did I miss?
+
+A0505: A message may have many recipients. The system filter is run just once
+       at the start of a delivery attempt. Consequently, it does not make sense
+       to set \$local_part$\. Which recipient should it be set to? However, you
+       can access all the recipients from a system filter via the variable
+       called \$recipients$\.
+
+
+Q0506: Using \$recipients$\ in a system filter gives me another problem: how can
+       I do a string lookup if \$recipients$\ is a list of addresses?
+
+A0506: Check out the section of the filter specification called \*Testing a list of
+       addresses*\. If that doesn't help, you may have to resort to calling an
+       embedded Perl interpreter - but that is expensive.
+
+
+Q0507: What are the main differences between using an Exim filter and using
+       \^procmail^\?
+
+A0507: Exim filters and \^procmail^\ provide different facilities. Exim filters run
+       at routing time, before any deliveries are done. A filter is like a
+       ``\(.forward)\ file with conditions''. One of the benefits is de-duplication.
+       Another is that if you forward, you are forwarding the original message.
+
+       However, this does mean that pipes etc. are not run at filtering time,
+       nor can you change the headers, because the message may have other
+       recipients and Exim keeps only a single set of headers.
+
+       \^procmail^\ runs at delivery time. This is for one recipient only, and so
+       it can change headers, run pipes and check the results, etc. However, if
+       it wants to forward, it has to create a new message containing a copy
+       of the original message.
+
+       It's your choice as to which of these you use. You can of course use
+       both.
+
+
+Q0508: How can I allow the use of relative paths in users' filter files when
+       the directories concerned are not available from the password data?
+
+A0508: You need to be running Exim 4.11 or later. You can then specify a value
+       for \$home$\ by setting the router_home_directory option on the
+       \%redirect%\ router.
+
+       For earlier releases, there is no way to specify the value of \$home$\
+       for a \%redirect%\ router; it either comes from the password data as a
+       result of \check_local_user\, or is unset.
+
+
+Q0509: How can I set up a filter file to detect and block virus attachments?
+
+A0509: Exim's filter facilities aren't powerful enough to do much more than
+       very crude testing. Most people that want virus checking are nowadays
+       using one of the separate scanning programs such as \^exiscan^\ (see
+       \?http://duncanthrax.net/exiscan/?\). There is some further information
+       about scanning with Exim via \?http://www.timj.co.uk/linux/exim.php?\.
+
+
+Q0510: Is it possible to write code for scanning messages in Python?
+
+A0510: \^elspy^\ is a layer of glue code that enables you to write Python code
+       to scan email messages at SMTP time. \^elspy^\ also includes a small
+       Python library with common mail-scanning tools, including an interface
+       to SpamAssassin and a simple but effective virus detector. You can
+       optain \^elspy^\ from \?http://elspy.sourceforge.net/?\.
+
+
+Q0511: Whenever my system filter uses a \mail\ command to send a message, I get
+       the error \*User 0 set for address_reply transport is on the never_users
+       list*\. What does this mean?
+
+A0511: The system filter runs as \/root/\ in Exim 4, unless you set
+       \system_filter_user\ to specify otherwise. When you set up a delivery
+       direct from a system filter (an autoreply is a special kind of
+       ``delivery'') the transport runs as the same user, unless it has a
+       \user\ setting of its own. Normally, deliveries are not allowed to run
+       as \/root/\ as a security precaution; this is implemented by the
+       \never_users\ option.
+
+       The easiest solution is to add this to your configuration:
+
+==>      system_filter_user = exim
+
+       The system filter then runs as \/exim/\ instead of \/root/\.
+       Alternatively, you can arrange for autoreplies from the system filter to
+       use a special transport of their own, and set the \user\ option on that
+       transport.
+
+
+Q0512: I'm trying to reference the ::Envelope-To:: header in my filter, but
+       \$h_envelope-to:$\ is always empty.
+
+A0512: ::Envelope-To:: is added at delivery time, by the transport. Therefore,
+       the header doesn't exist at filter time. In a user filter, the values
+       you probably want are in \$original_local_part$\ and
+       \$original_domain$\. In a system filter, the complete list of all
+       envelope recipients is in \$recipients$\.
+
+
+Q0513: I want my system filter to freeze all mails greater than 500K in size,
+       but to exclude those to a specific domain. However, I don't seem to be
+       able to use \$domain$\ in a system filter.
+
+A0513: You cannot do this in a system filter, because a single message may have
+       multiple recipients, some in the special domain, and some not. That is
+       also the reason why \$domain$\ is not set in a system filter.
+
+       If you want to take actions on a per-recipient basis, you have to do it
+       in a router. However, freezing is not appropriate, because freezing
+       stops all deliveries. You could, however, delay delivery to all but the
+       special domains by using something like this:
+
+==>      delay_if_too_big:
+           driver = redirect
+           domains = !the.special.domain
+           condition = ${if >{$message_size}{500K}{yes}{no}}
+           allow_defer
+           data = :defer: message too big.
+
+       However, there isn't an easy way of ``releasing'' such messages at
+       present.
+
+
+Q0514: When I try to send to two addresses I get an error in the filter
+       file \*malformed address: , e@fgh.com may not follow a@bcd.com*\. What
+       is going on?
+
+A0514: Have you got
+
+==>      deliver "a@bcd.com, e@fgh.com"
+
+       in your filter? If so, that is your problem. You should have
+
+==>      deliver a@bcd.com
+         deliver e@fgh.com
+
+       Each \deliver\ command expects just one address.
+
+
+
+6. DELIVERY
+
+Q0601: What does the error \*Neither the xxx router nor the yyy transport set
+       a uid for local delivery of...*\ mean?
+
+A0601: Whenever Exim does a local delivery, it runs a process under a specific
+       user and group id (uid and gid). For deliveries into mailboxes, and to
+       pipes and files set up by forwarding, it normally picks up the uid/gid
+       of the receiving user. However, if an address is directed to a pipe or a
+       file by some other means, such an entry in the system alias file of the
+       form
+
+==>      majordomo: |/local/mail/majordomo ...
+
+       then Exim has to be told what uid/gid to use for the delivery. This can
+       be done either on the routerr that handles the address, or on the
+       transport that actually does the delivery. If a pipe is going to run a
+       setuid program, then it doesn't matter what uid Exim starts it out with,
+       and so the most straightforward thing is to put
+
+==>      user = exim
+
+       on either the router or the transport. A setting on the transport
+       overrides a setting on the router, so if the same transport is being
+       used with several routers, you should set the user on it only if you
+       want the same uid to be used in all cases.
+
+       In the default configuration, the transports used for file and pipe
+       deliveries are the ones called \address_file\ and \address_pipe\. You
+       can specify different transports by setting, for example,
+
+==>      pipe_transport = special_pipe_transport
+
+       on the \%system_aliases%\ router. Then you can set up \%special_pipe_transport%\
+
+==>      special_pipe_transport:
+           driver = pipe
+           user = ????
+
+       which will be used only for pipe deliveries from that one router.
+       What you put for the ???? is up to you, and depends on the particular
+       circumstances.
+
+
+Q0602: Exim keeps crashing with segmentation errors (signal 11 or 139) during
+       delivery. This seems to happen when it is about to contact a remote
+       host or when a delivery is deferred.
+
+A0602: This could be a problem with Exim's databases. Try running a delivery
+       with debugging turned on. If the last line of the debug output is
+       something like this:
+
+==>      locked /var/spool/exim/db/retry.lockfile
+
+       the crash is happening inside the DBM library. Check that your DBM
+       library is correctly installed. In particular, if you have installed a
+       second DBM library onto a system that already had one, check that its
+       version of \(ndbm.h)\ is being seen first. For example, if the new
+       version is in \(/usr/local/include)\, check that there isn't another
+       version in \(/usr/include)\. If you are using Berkeley db, you can set
+
+==>      USE_DB=yes
+
+       in your \(Local/Makefile)\ to avoid using \(ndbm.h)\ altogether. This is
+       particularly relevant for version 2 (or later) of Berkeley db, because
+       no \(ndbm.h)\ file is distributed with it. Another thing you can try is
+       to run
+
+==>      exim_dumpdb /var/spool/exim retry
+
+       to see if it also crashes, or build the \^test_dbfn^\ tool and fiddle
+       around with it. If both fail, it is most almost certainly a problem with
+       your DBM library. You could try to update it, or force Exim to use
+       another library. See the file \(doc/dbm.discuss.txt)\ for hints about
+       this.
+
+
+Q0603: How can mails that are being routed through routers that do not set
+       \check_local_user\ be delivered under the uid of the recipient?
+
+A0603: Q0601 contains background information on this. If you are using, say, an
+       alias file to direct messages to specific mailboxes, you can use
+       the \user\ option on either the router or the transport to set the uid.
+       What you put in the setting depends on how the required uid is to be
+       found. It could be looked up in a file or computed somehow from the
+       local part, for example.
+
+
+Q0604: I want to use MMDF-style mailboxes. How can I get Exim to append the
+       ctrl-A characters that separate indvidual emails?
+
+A0604: Set the \message_suffix\ option in the \%appendfile%\ transport. In fact,
+       for MMDF mailboxes you need a prefix as well as a suffix to get it
+       working right, so your transport should contain these settings:
+
+==>      message_prefix = "\1\1\1\1\n"
+         message_suffix = "\1\1\1\1\n"
+
+       Also, you need to change the \check_string\ and \escape_string\ settings so
+       that the escaping happens for lines in the message that happen to begin
+       with the MMDF prefix or suffix string, rather than ``From'' (the default):
+
+==>      check_string  = "\1\1\1\1\n"
+         escape_string = "\1\1\1\1 \n"
+
+       Adding a space to the line is sufficient to prevent it being taken as a
+       separator.
+
+
+Q0605: If a user's mailbox is over quota, is there a way for me to set it up so
+       that the mail bounces to the sender and is not stored in the mail queue?
+
+A0605: In the retry section of the configuration, put
+
+==>      *@your.dom.ain        quota
+
+       That is, provide no retry timings for over quota errors. They will then
+       bounce immediately. Alternatively, you can set up retries for a short
+       time only, or use something like this:
+
+==>      *@your.dom.ain        quota_7d
+         *@your.dom.ain        quota       F,2h,15m; F,3d,1h
+
+       which bounces immediately if the user's mailbox hasn't been read for 7
+       days, but otherwise tries for up to 3 days after the first quota
+       failure.
+
+
+Q0606: I'm using tmail to do local deliveries, but when I turned on the
+       \use_crlf\ option on the \%pipe%\ transport (tmail prefers \"@\r@\n"\
+       terminations) message bodies started to vanish.
+
+A0606: You need to unset the \mesage_prefix\ option, or change it so that its
+       default \"@\n"\ terminator becomes \"@\r@\n"\. For example, the
+       transport could be:
+
+==>      local_delivery_mbx:
+          driver = pipe
+          command = /usr/local/bin/tmail $local_part
+          user = exim
+          current_directory = /
+           use_crlf
+           message_prefix =
+
+       The reason for this is as follows: tmail uses the line terminator on
+       the first line it sees to determine whether lines are terminated by
+       \"@\r@\n"\ or \"@\n"\. If the latter, it moans to stderr and changes subsequent
+       \"@\n"\ terminators to \"@\r@\n"\. The default setting of the \message_prefix\
+       option is \"From ...@\n"\, and this is unaffected by the \use_crlf\ option.
+       If you don't change this, tmail sees the first line terminated by
+       \"@\n"\ and prepends \"@\r"\ to the \"@\n"\ terminator on all subsequent
+       lines. However, if \use_crlf\ is set, Exim makes all other lines
+       \"@\r@\n"\ terminated, leading to doubled \"@\r@\r@\n"\ lines and
+       corrupt mbx mailboxes.
+
+
+Q0607: When I activate ``return receipt'' for example in Netscape Mailbox
+       sending options, then I get an error message from Exim... something
+       like \*not supported*\. Can I activate delivery confirmations?
+
+A0607: Exim does not support any kind of delivery notification.
+
+       (1) You can configure it to recognize headers such as
+       \Return-receipt-to:\ if you wish.
+
+       (2) Some people want MSN (message status notification). Such services
+       are implemented in MUAs, and don't impact on the MTA at all.
+
+       (3) I investigated the RFCs which describe the DSN (delivery status
+       notification) system. However, I was unable to specify any sensible way
+       of actually doing anything with the data. There were comments on the
+       mailing list at the time; many people, including me, conclude that DSN
+       is in practice unworkable. The killer problem is with forwarding and
+       aliasing. Do you propagate the DSN data with the generated addresses?
+       Do you send back a ``reached end of the DSN world'' or ``expanded'' message?
+       Do you do this differently for different kinds of aliasing/forwarding?
+       For a user who has a \(.forward)\ file with a single address in, this
+       might seem easy - just propagate the data. But what if there are several
+       forwardings? If you propagate the DSN data, the sender may get back
+       several DSN messages - and should the sender really know about the
+       detail of the receiver's forwarding arrangements? There isn't really
+       any way to distinguish between a \(.forward)\ file that is forwarding
+       and one that is a mini mailing list. And so on, and so on. There are so
+       many questions that don't have obvious answers.
+
+
+Q0608: What does the message \*retry time not reached [for any host]*\ on the log
+       mean? Why won't Exim try to deliver the message?
+
+A0608: That is not an error. It means exactly what it says. A previous attempt
+       to deliver to that address failed with a temporary error, and Exim
+       computed the earliest time at which to try again. This can apply to
+       local as well as to remote deliveries. For remote deliveries, each host
+       (if there are several) has its own retry time.
+
+       If you are running on a dial-up host, the rest of this answer probably
+       does not apply to you. Go and read Q1404 instead. If your host is
+       permanently online, read on...
+
+       Some MTAs have a retrying schedule for each message. Exim does not work
+       like this. Retry timing is normally host-based for remote deliveries and
+       address-based for local deliveries. (There are some exceptions for certain
+       kinds of remote failure - see \*Errors in outgoing SMTP*\ in the manual.)
+
+       If a new message arrives for a failing address and the retry time has
+       not yet arrived, Exim will log \*retry time not reached*\ and leave the
+       message on the queue, without attempting delivery. Similarly, if a queue
+       runner notices the message before the time to retry has arrived, it
+       writes the same log entry. When the retry time has past, Exim attempts
+       delivery at the next queue run. If you want to know when that will be,
+       run the exinext utility on the address, for example:
+
+==>      exinext user@some.domain
+
+       You can suppress these messages on the log by including \"-retry_defer"\
+       in the setting of \log_selector\. You can force a delivery attempt on a
+       specific message (overriding the retry time) by means of the -M option:
+
+==>      exim -M 10hCET-0000Bf-00
+
+       If you want to do this for the entire queue, use the \-qf-\ option.
+
+
+Q0609: Exim seems to be sending the same message twice, according to the log,
+       although there is a difference in capitalization of the local part of
+       the address.
+
+A0609: That is correct. The RFCs are explicit in stating that capitalization
+       matters for local parts. For remote domains, Exim is not entitled to
+       assume case independence of local parts. I know, it is utterly silly,
+       and it causes a lot of grief, but that's what the rules say. Here is a
+       quote from RFC 2821:
+
+         ... a command verb, an argument value other than a mailbox local-part,
+         and free form text MAY be encoded in upper case, lower case, or any
+         mixture of upper and lower case with no impact on its meaning.  This
+         is NOT true of a mailbox local-part.  The local-part of a mailbox
+         MUST BE treated as case sensitive.  Therefore, SMTP implementations
+         MUST take care to preserve the case of mailbox local-parts.  Mailbox
+         domains are not case sensitive.  In particular, for some hosts the
+         user "smith" is different from the user "Smith".  However, exploiting
+         the case sensitivity of mailbox local-parts impedes interoperability
+         and is discouraged.
+
+
+Q0610: How can I force the next retry time for a host to be now?
+
+A0610: You can change the retry time with the \^exim_fixdb^\ utility, but its
+       interface is very clumsy. If you have a message for the host on the
+       queue, the simplest thing to do is to force a delivery with the \-M-\
+       command line option. If delivery succeeds, the retry data will get
+       cleared. If the host is past the cutoff time, so that messages are
+       bouncing immediately without trying a delivery, you can use \-odq-\ to
+       put a message on the queue without a delivery attempt, and then use
+       \-M-\ on it.
+
+
+Q0611: I set up \"|/bin/grep Subject|/usr/bin/smbclient -M <netbiosname>"\ as an
+       alias but it doesn't work.
+
+A0611: That is a shell command line. Exim does not run pipe commands under a
+       shell by default (for added security - and it saves a process). You
+       need something like
+
+==>      "|/bin/sh -c '/bin/grep Subject|/usr/bin/smbclient -M <netbiosname>'"
+
+
+Q0612: Why does the \%pipe%\ transport add a line starting with \">From"\ to
+       messages?
+
+A0612: Actually, it adds a line starting with \"From"\ followed by a space.
+       This is commonly referred to as the \"From_"\ line, to emphasize the
+       fact that \"From"\ is followed by a space and not a colon. This is a
+       pseudo-header line that contains the envelope sender address and the
+       time of delivery. It originated as a separator line in Berkeley format
+       mailboxes, but is also used in other contexts. (And yes, it is often
+       confused with the ::From:: header line, and this causes a lot of grief.
+       The use of \"From_"\ was one of the really bad email design decisions.)
+
+       Exim's \%pipe%\ transport adds this pseudo-header line by default
+       because \(/usr/ucb/vacation)\ needs it, and that is one of the the most
+       common uses of piping. The \^procmail^\ local delivery agent also makes
+       use of the \"From_"\ line. If you do not want it, change the setting of
+       \message_prefix\ on the \%pipe%\ transport. For example, to remove the
+       line altogether, use
+
+==>      message_prefix =
+
+       If you are not piping to \(/usr/ucb/vacation)\ or \^procmail^\, it is
+       likely that you do not need a \"From_"\ line, and indeed it may cause
+       problems if it is present.
+
+       One user reported that this line gave trouble when a pipe was used to
+       send messages to Courier's \^deliverquota^\ program. The line was
+       retained with the message, and caused problems for MS Exchange 2000 when
+       retrieving messages with its built-in POP collector. Specifically, it
+       caused Exchange to not be able to recognise message attachments.
+
+
+Q0613: I have set \fallback_hosts\ on my \%smtp%\ transport, but after the error
+       \*sem@chat.ru cannot be resolved at this time*\ Exim isn't using them.
+
+A0613: \fallback_hosts\ works only if an attempt at delivery to the original
+       host(s) fails. In this case, Exim couldn't even resolve the domain
+       \(chat.ru)\ to discover what the original hosts were, so it never got as far
+       as the transport. However, see Q0315 for a possible solution.
+
+
+Q0614: After the holidays my ISP has always hundreds of e-mails waiting for me.
+       These are forced down Exim's throat in one go. Exim spawns a lot of
+       kids, but is there some limit to the number of processes it creates?
+
+A0614: Unless you have changed \smtp_accept_queue_per_connection\ it should
+       spawn only that many processes per connection (default 10). Your ISP
+       may be making many connections, of course. That is limited by
+       \smtp_accept_max\.
+
+
+Q0615: When a message in the queue got to 12h old, Exim wrote \*retry timeout
+       exceeded*\ and removed all messages in the queue to this host - even
+       recent messages. How I can avoid this behaviour? I only want to remove
+       messages that have exceeded the maximum retry time.
+
+A0615: Exim's retrying is host-based rather than message-based. The philosophy
+       is that if a host has been down for a very long time, there is no point
+       in keeping messages hanging around. However, you might like to check
+       out \delay_after_cutoff\ in the \%smtp%\ transport. It doesn't do what you
+       want, but it might help.
+
+
+Q0616: Can Exim add a ::Content-Length:: header to messages it delivers?
+
+A0616: You could include something like
+
+==>      headers_remove = "content-length"
+         headers_add = "Content-Length: $message_body_size"
+
+       to the \%appendfile%\ transport. However, the use of ::Content-Length:: can
+       cause several problems, and is not recommended unless you really know
+       what you are doing. There is a discussion of the problems in
+       \?http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html?\.
+
+
+Q0617: Exim seems to be trying to deliver a message every 10 minutes, though
+       the retry rules specify longer times after a while, because it is
+       writing a log entry every time, like this:
+
+==>    1999-08-26 14:51:19 11IVsE-000MuP-00 == example@example.com T=smtp defer
+       (-34): some host address lookups failed and retry time not reached for
+       other hosts or connection limit reached
+
+A0617: It is looking at the message every 10 minutes, but it isn't actually
+       trying to deliver. It's looking up \(example.com)\ in the DNS and finding
+       this information:
+
+==>      example.com.                MX 10 example-com.isp.example.com.
+         example.com.                MX  0 mail.example.com.
+         mail.example.com.           A  202.77.183.45
+         A lookup for example-com.isp.example.com. yielded NXDOMAIN
+
+       The last line means that there is no address (A) record in the DNS for
+       \(example-com.isp.example.com)\. That accounts for \*some host address
+       lookups failed*\, but the retry time for \(mail.example.com)\ hasn't been
+       reached, which accounts for \*retry time not reached for other hosts*\.
+
+
+Q0618: I am trying to set exim up to have a automatic failover if it sees that
+       the system that it is sending all mail to is down.
+
+A0618: Add to the \%remote_smtp%\ transport the following:
+
+==>      fallback_hosts = failover.server.name(s)
+
+       If there are several names, they must be separated by colons.
+
+
+Q0619: I can't get Exim to deliver over NFS. I get the error \*fcntl() failed:
+       No locks available*\, though the lock daemon is running on the NFS server
+       and other hosts are able to access it.
+
+A0619: Check that you have \(lockd)\ running on the NFS client. This is not
+       always running by default on some systems (Red Hat is believed to be one
+       such system).
+
+
+Q0620: Why does Exim bounce messages without even attempting delivery, giving
+       the error \*retry time not reached for any host after a long failure
+       period*\?
+
+A0620: This message means that all hosts to which the message could be sent
+       have been failing for so long that the end of the retry period
+       (typically 4 or 5 days) has been reached. In this situation, Exim still
+       computes a next time to retry, but any messages that arrive in the
+       meantime are bounced straight away. You can alter this behaviour by
+       unsetting the \delay_after_cutoff\ option on the smtp transport. Then Exim
+       will try most messages for those hosts once before giving up.
+
+
+Q0621: My \(.forward)\ file is \"|/usr/bin/procmail -f-"\ and mail gets delivered,
+       but there was a bounce to the sender, sending him the output of procmail.
+       How can I prevent this?
+
+A0621: Exim's default configuration is set up like this:
+
+==>      address_pipe:
+           driver = pipe
+           return_output
+
+       The \return_output\ option requests that any output that the pipe
+       produces be returned to the sender. That is the safest default. If you
+       don't want this, you can either remove the option altogether, or change
+       it to \return_fail_output\, to return output only if the command fails.
+       Note that this will affect all pipes that users run, not just your
+       procmail one. It might be better to arrange for procmail not to produce
+       any output when it succeeds.
+
+
+Q0622: Can I write an ordinary file when I run a perl script as a transport
+       filter for the \%remote_smtp%\ and \%address_pipe%\ transports?
+
+A0622: Yes, provided the file is writeable by the uid under which the transport
+       runs (the Exim user in the case of the remote transport). However, if two
+       messages are being delivered at once, their data will get mixed up in
+       the file unless you implement your own locking scheme. If all you want
+       to do is to take a copy of the message, another approach that avoids
+       the locking problem is to use a system filter to set up an ``unseen''
+       delivery to a file. If you only want the message's headers, you can
+       set \message_filter_file_transport\ to point to a special \%appendfile%\
+       transport that has \headers_only\ set.
+
+
+Q0623: My \(/var/spool/mail)\ has grown drastically. Is there any possibility of
+       using two directories?
+
+A0623: You can use an expansion string to split mailboxes between two
+       directories. For example,
+
+==>      file = /var/spool/mail${nhash_2:$local_part}/$local_part
+
+       which does a hash on the local part, producing either 0 or 1, thereby
+       using \(mail0) or \(mail1)\. But remember, the MUAs that read these mailboxes
+       also have to know where they are.
+
+
+Q0624: Sendmail has a program called \^smrsh^\ that restricts what binaries
+       can be run from sendmail aliases. Is there something like this in Exim ?
+
+A0624: Check out the \allow_commands\ option in the \%pipe%\ transport.
+
+
+Q0625: I wish to have large emails go out one at a time.
+
+A0625: One possibility is to set up a router that defers all large messages,
+       except in queue runs. Since queue runners deliver just one
+       message at a time, if you limited the number of simultaneous queue
+       runners to 1, you would get the effect you wanted. A suitable router
+       might be
+
+==>      defer_if_large_unless_queue_run:
+           driver = redirect
+           condition = ${if or{{queue_running}{<{$message_size}{200K}}}{no}{yes}}
+           allow_defer
+           data = :defer: too large for immediate delivery
+           no_verify
+
+       Of course, this would always delay any large message until the next
+       queue runner, but if you run them fairly regularly, this shouldn't be a
+       huge problem, and may even be desirable. Note the use of \no_verify\ to
+       ensure that this router is not used when Exim is verifying addresses.
+
+
+Q0626: Exim can route local parts independent of their case, but the Cyrus LMTP
+       daemon requires the correct case. How can I fix this?
+
+A0626: You need to rewrite the local part to the correct case before running
+       the router that routes to Cyrus. For example, if you require all lower
+       case, and your router is called \local_user\, put this router in front
+       of it:
+
+==>      lowercase_local:
+           driver = redirect
+           redirect_router = local_user
+           domains = +local_domains
+           data = ${lc:$local_part}@$domain
+
+       The setting of \redirect_router\ causes processing of the rewritten
+       address to start at the next router, instead of the first router. See
+       also Q0630, and C045 for a more complete Cyrus configuration.
+
+
+Q0627: Is there a command I can send to Exim to retry all queued messages
+       regardless of their retry schedule?
+
+A0627: The \-qff-\ option starts a queue runner that forces a delivery attempt
+       for all messages, including frozen ones. If you use \-qf-\, frozen
+       messages are skipped.
+
+
+Q0628: I have the default retry rule, which I thought meant that Exim should
+       keep trying for four days, but it seems to be bouncing some messages
+       immediately.
+
+A0628: See Q0615 and Q0620.
+
+
+Q0629: I'm having trouble with quotas and Courier, because Exim is not handling
+       maildirsize files.
+
+A0629: You will do better to move the quota handling to Courier. Use \^maildrop^\
+       as your MDA rather than direct Exim delivery.  This also has the
+       advantage that if you give web access to the mail spool (over \^sqwebmail^\)
+       you can then use the web front end to edit \^maildrop^\ filter files.
+
+
+Q0630: How can I configure Exim to deliver to a Cyrus message store?
+
+A0630: (1) The reference manual contains an example that uses pipe delivery.
+
+       (2) Here is a transport that uses LMTP delivery, assuming that
+           \$local_part$\ contains the username:
+
+==>      cyrus_inbox:
+           driver =lmtp
+           user = cyrus
+           socket = /var/cyrus/socket/lmtp
+
+       (3) This is a transport that delivers direct to a non-inbox mailbox:
+
+==>      cyrus_mailbox:
+           driver = pipe
+           user = $local_part
+           message_prefix =
+           message_suffix =
+           log_fail_output
+           return_output
+           command = "/usr/cyrus/bin/deliver -a $local_part \
+                      -m <mailbox-name> $local_part"
+
+       This delivers to the Cyrus mailbox \"user.$local_part.<mailbox-name>"\.
+       Using \"user = $local_part"\ and \"-a $local_part"\ makes it work
+       without needing an explicit `p' ACL set for `anyone' on the mailbox.
+
+
+Q0631: I would like to choose a retry rule based on on the sender rather than
+       the recipient address. Is this possible?
+
+A0631: Yes. The address part of a retry rule is matched as a single-item
+       address list. Such lists are always expanded, so you can use something
+       like this:
+
+==>      "${if eq{$sender_address}{xxx}{*@*}{no@no}}" quota F,1h,10m; ...
+
+       If the sender address is ``xxx'', the pattern expands to ``*@*'', which
+       matches all recipient addresses; if you want to, you can make this a
+       more restrictive pattern. If the sender address is not ``xxx'', the
+       pattern expands to ``no@no'', which is assumed to be a recipient address
+       that can never match, so the retry rule is skipped.
+
+
+Q0632: What does the error \*User 1 set for local_mbx_delivery transport is on
+       the never_users list*\ mean?
+
+A0632: You have configured the \%local_mbx_delivery%\ to run as the user whose
+       id (uid) is 1. However, this user is on the list defined by the
+       \never_users\ runtime option, or the \\FIXED_NEVER_USERS\\ compile-time
+       option. These are ``safety catch'' lists; Exim refuses to deliver to any
+       user that is on them. The most common use of \never_users\ is to avoid
+       doing any deliveries as \/root/\, but it can contain other uids.
+
+
+Q0633: Why is \$domain$\ not set in the \%smtp%\ transport?
+
+A0633: The \%smtp%\ transport can handle several recipient addresses at once.
+       This happens by default if the host lists for the addresses are
+       identical. A single copy of the message is sent, using multiple \\RCPT\\
+       commands to transmit multiple envelope recipients. The \$domain$\
+       variable is set in the \%smtp%\ transport only if all the recipient
+       addresses have the same domain. You must have a case where several
+       addresses with different domains resolve to the same set of hosts.
+
+       If you want to restrict the transport so that it handles only a single
+       domain at once (but still possibly with more than one recipient), set
+
+==>      multi_domain = false
+
+       If you want to restrict the transport so that it handles only a single
+       address at once, set
+
+==>      max_rcpt = 1
+
+
+Q0634: How can I stop a local transport from trying to access the user's home
+       directory, even when the delivery is to a file that is elsewhere?
+
+A0634: See answer (2) for Q0423.
+
+
+Q0635: The log message \*error ignored*\ appears after some delivery failures.
+       What does it mean?
+
+A0635: This message is written when Exim fails to deliver a bounce message whose
+       age is greater than \ignore_bounce_errors_after\. It indicates that the
+       failing bounce message has been discarded.
+
+       The same message is written after failed deliveries when a filter file
+       uses the \noerror\ feature when setting up a delivery, or if a router
+       has the setting
+
+==>      errors_to = <>
+
+       Both of these specify that delivery failures are to be discarded.
+
+
+
+7. POLICY CONTROLS
+
+Q0701: How do I block unwanted messages from outside my host?
+
+A0701: Exim uses Access Control Lists (ACLs) for controlling incoming mail from
+       other hosts. A whole chapter in the reference manual is devoted to
+       describing how they work. A wide variety of conditions can be imposed on
+       incoming messages.
+
+       The default Exim run time configuration contains an example of an ACL
+       which blocks all relaying, and messages whose senders cannot be
+       verified. This example is heavily commented and worth studying.
+
+
+Q0702: I don't want to block spam entirely; how can I inspect each message
+       before deciding whether or not to deliver it?
+
+A0702: Wherever possible, inspection and rejection is best done automatically
+       in an ACL, that is, before the message is accepted. If you want to
+       verify manually each message that is classified as spam by an automatic
+       check, you can arrange for a system filter to freeze such messages after
+       they have been accepted.
+
+       If, after inspection, you decide not to deliver the message, it is
+       safest to discard it, using the \-Mrm-\ option. Use of the \-Mg-\ option
+       to force a bounce carries the risk of ``collateral spam'' if the sender
+       address is faked.
+
+
+Q0703: How can I test that my spam blocks are working?
+
+A0703: The \-bh-\ option allows you to run a testing SMTP session as if from a
+       given IP address. For example,
+
+==>      exim -bh 192.168.178.39
+
+       In addition to the normal SMTP replies, it outputs commentary about
+       which tests have succeeded or failed. If you are not interested in the
+       details, but just want to know if a particular sender at a particular IP
+       address is able to mail to a particular recipient, you can use the
+       \exim_checkaccess\ utility, which provides a ``packaged'' version of
+       \-bh-\. You call it like this:
+
+==>      exim_checkaccess 192.168.53.23 recip@my.domain -f sender@some.domain
+
+       If you don't give a sender, \"<>"\ is used (that it, it acts like a
+       bounce message).
+
+
+Q0704: How can I test that Exim is correctly configured to use the Realtime
+       Blackhole List (RBL)?
+
+A0704: The \-bh-\ option allows you to run a testing SMTP session as if from a
+       given address. The \^exim_checkaccess^\ utility provides a more packaged
+       version of this facility. You need to know a blocked IP address with
+       which to test. Such a testing address is kindly provided by Russell
+       Nelson:
+
+==>      linux.crynwr.com [192.203.178.39]
+
+       You can also send mail to \(nelson@linux.crynwr.com)\ from the server
+       whose RBL block you are testing. The robot that receives that email
+       will attempt to send a piece of test email in reply. If your RBL block
+       didn't work, you get a message to that effect. Regardless of whether the
+       RBL block succeeds or not, it emails you the results of the SMTP
+       conversation from a host that is not on the RBL, so you can see how your
+       server looks from the view of someone on the RBL.
+
+
+Q0705: How can I use tcpwrappers in conjunction with Exim?
+
+A0705: Exim's own control facilities can do all that tcpwrappers can do.
+       However, if you are already using tcpwrappers for other things it might
+       be convenient to include Exim controls in the same place.
+
+       First of all, ensure that Exim is built to call the tcpwrappers library,
+       by including \\USE_TCPWRAPPERS=yes\\ in \(Local/Makefile)\. You also need to
+       ensure that the header file \(tcpd.h)\ is available at compile time, and the
+       \(libwrap.a)\ library is available at link time, typically by including it in
+       \\EXTRALIBS\\. You may need to copy these two files from the tcpwrappers
+       build directory to, for example, \(/usr/local/include)\ and \(/usr/local/lib)\,
+       respectively. Then you could reference them by
+
+==>      CFLAGS=-I/usr/local/include
+         EXTRALIBS=-L/usr/local/lib -lwrap
+
+       in \(Local/Makefile)\. There are two ways to make use of the functionality,
+       depending on how you have tcpwrappers set up. If you have it set up to
+       use only one file, you ought to have something like:
+
+==>      /etc/hosts.allow:
+
+==>          exim : <client_list>  : <allow_or_deny>
+
+         For example:
+
+==>          exim : LOCAL  192.168.0.  .friendly.domain  special.host : ALLOW
+             exim : ALL                                               : DENY
+
+       This allows connections from local hosts (chiefly //localhost//), from
+       the subnet 192.168.0.0/24, from all hosts in \(*.friendly.domain)\, and
+       from a specific host called \(special.host)\. All other connections are
+       denied. If you have tcpwrappers set up to use two files, use the
+       following:
+
+==>      /etc/hosts.allow:
+
+==>          exim    : <client_list>
+
+==>      /etc/hosts.deny:
+
+==>          exim    : <client_list>
+
+       Read the \^hosts_access^\ man page for more ways of specifying clients,
+       including ports, etc., and on logging connections.
+
+
+Q0706: How can I get POP-auth-before-relay (aka POP-before-SMTP) support in
+       Exim?
+
+A0706: Exim 4 supports the ``whoson'' (\?http://whoson.sourceforge.net?\)
+       facility for doing this. If you set this up, you can do the check in an
+       Exim ACL by a statement like this:
+
+==>      require condition = \
+           ${lookup whoson {$sender_host_address}{yes}{no}}
+
+       Otherwise you need to arrange for a list of permitted IP addresses to be
+       maintained in a file or database, and use this in a \hosts\ condition in
+       an ACL statement. An Exim user has published this recipe:
+
+       \#\#\#\#\?http://www.zeiss.cx/memo/computer/linux/email/exim-s-a-p.html?\
+
+       Another Exim user submitted the following idea:
+
+       Use a script to grab authenticated IP addresses from the log files of
+       the POP3 and IMAP4 daemons. These are used to create files in the
+       directory tree \(/var/db/popb4smtp)\. The existence of a file represents a
+       valid ``popped recently token'' for the IP address used as the filename.
+
+       Another script periodically removes stale files from the tree (after two
+       hours).  There's a small race condition here; it's possible for a file
+       to be deleted just after it has been updated by the script that watches
+       the logs. For low-volume servers, the odds of hitting this window are
+       low.
+
+       A POPB4SMTP_CLIENT macro in the Exim configure file provides a reusable
+       ``has this sender popped recently?'' query:
+
+==>    POPB4SMTP_SUBDIR = /var/db/popb4smtp/${substr_-1_1:$sender_host_address}
+       POPB4SMTP_CLIENT = ${if exists {POPB4SMTP_SUBDIR/$sender_host_address} \
+           {$sender_host_address} {0} }
+
+       Now you can use it just about anywhere, including in your ACLs. Simple
+       examples include:
+
+==>    hostlist relay_hosts = 127.0.0.1/32 : ... : POPB4SMTP_CLIENT
+       host_lookup = !127.0.0.1/32 : ... : !POPB4SMTP_CLIENT
+       rfc1413_hosts = !127.0.0.1/32 : ... : !POPB4SMTP_CLIENT
+
+       The two scripts (and a FreeBSD startup script for them) are available
+       for download at:
+
+       \#\#\#\#\?http://people.FreeBSD.org/~sheldonh/popb4smtp-nodb.tar.gz?\
+
+
+Q0707: I have one or two cases where my host correctly rejects messages, but
+       the remote host is quite persistent, and keeps trying over and over.
+
+A0707: It is an unfortunate fact that a number of SMTP clients, in violation of
+       the SMTP RFC, do not treat a permanent error code that is given after
+       the DATA portion of the transaction as a permanent error. Consequently
+       they keep resending the message, and the worst offenders do so at very
+       short intervals.
+
+       The only way to stop such behaviour is to blacklist the IP address, or
+       the envelope sender, or both, in such a way that future messages get
+       rejected at RCPT time instead of at DATA time. You could also complain
+       to the remote host's administrators.
+
+
+Q0708: How can I run customized verification checks on incoming addresses?
+
+A0708: There are a number of possibilities:
+
+       (1) If you can implement your checks in Perl, you can use Exim's
+       facility for running an embedded Perl interpreter. For example, if you
+       want to run special checks on local addresses, you could use ACL
+       an statement like this:
+
+==>      require domains = my.local.domain
+                 condition = ${perl{verify}{$local_part}}
+
+       The result of the Perl function should be ``yes'' or ``no''.
+
+       (2) You could also run an external program in a similar way, by a
+       statement such as:
+
+==>      require domains = my.local.domain
+                 condition = ${run{/my/verifier $local_part}}
+
+       This requires the use of another process, so could prove more expensive
+       than Perl.
+
+       (3) If you are prepared to write C code, read the chapter in the manual
+       entitled \*Adding a local scan function to Exim*\.
+
+
+Q0709: Does Exim apply RBL checks to error messages, those with an envelope
+       sender of \"<>"\ ?
+
+A0709: This depends on the ACL configuration. You can test for bounce messages
+       (by looking for an empty sender address) and thereby exclude them from
+       RBL checking if you want. This ACL statement does that:
+
+==>      deny senders = ! :
+              dnslist = blackholes.mail-abuse.org
+
+       However, some spam does come with an empty sender address, so this may
+       not be a good idea.
+
+
+Q0710: I want to reject certain sender-recipient combinations, with a specific
+       message for each such combination.
+
+A0710: Set up a file (or database) containing the messages, keyed by the
+       combination, for example:
+
+==>      sender1@sdomain1=>recipient1@rdomain1: blocked because...
+         sender2@sdomain2=>recipient2@rdomain2: blocked because...
+
+       If you have lots of recipients for the same sender, it might be easier
+       to generate this file from more convenient data. In your ACL that is run
+       for each RCPT command, you can then put:
+
+==>      deny message   = ${lookup{$sender_address=>$local_part@$domain}\
+                          lsearch{/that/file}}
+              condition = ${lookup{$sender_address=>$local_part@$domain}\
+                          lsearch{/that/file}}{yes}{no}}
+
+       The condition is tested first. If the lookup succeeds, the condition
+       succeeds so access is denied. The message is then expanded, but the
+       lookup won't be repeated, because Exim will have cached the previous
+       result.
+
+       This approach blocks only incoming SMTP messages. If you need to do
+       similar blocks for messages that do not arrive over SMTP, you have to
+       set up a suitable \%redirect%\ router with a \:fail:\ setting.
+
+
+Q0711: Will Exim allow me to create a file of regexs and match incoming
+       external email to the list - and if a match is found file the offending
+       message into a special location? Also is it possible to make Exim only
+       filter parts of an incoming email - e.g. ignore large MIME attachments
+       for example and only process text/plain?
+
+A0711: You can do some of this in a system filter. For example:
+
+==>      if $message_body matches <...some complicated regex...> or
+            $message_body matches <...some other regex...> or
+            $header_from: matches <...regex...> or
+            etc.
+         then
+           save /some/special/file
+         endif
+
+       or instead of \"save"\ you could have \"deliver"\ (to some address) or
+       \"pipe"\ (to some script).
+
+       There isn't any mechanism for ignoring attachments, but \$message_body$\
+       only looks at the first n bytes of the body, where n defaults to 500 but
+       can be changed.
+
+       A more expensive alternative would be to run a Perl subroutine using the
+       embedded Perl mechanism. If you passed over the message id, the Perl
+       code could read the message files on the spool and implement any
+       algorithm it liked for deciding what should be done.
+
+
+Q0712: I've hacked sendmail to make an ioctl call at the time of the SMTP RCPT
+       command, to check if a user has exceeded their email quota. If they have
+       I issue a temporary failure and a message - can I do this with Exim?
+
+A0712: If you can make this happen in Perl you can use the embedded Perl
+       facility, and use it from a \condition\ condition in an ACL statement.
+       You can also use the expansion facility to run an external program, but
+       this uses more resources because it uses another process.
+
+
+Q0713: I'd like to pass all messages through a virus-scanning system before
+       delivery. Can Exim do this?
+
+A0713: One way of achieving this is to deliver all messages via a pipe to a
+       checking program that resubmits them for delivery in some private way
+       that can be checked (e.g. on a specific SMTP port, or IP address). One
+       possibility is to use the `received protocol` field that can be set
+       for locally submitted mail via the \-oMr-\ command line option. This
+       router sends all messages that are not from the local host and whose
+       received protocol is not \"scanned-ok"\ to the \%virus_scan%\ transport:
+
+==>      vircheck:
+           driver = accept
+           transport = virus_scan
+           condition = ${if or {{eq {$received_protocol}{scanned-ok}} \
+                                {eq {$sender_host_address}{127.0.0.1}}}\
+                                {0}{1}}
+
+       One problem is that this approach scans the message for each recipient,
+       not just once per message.
+
+       The virus_scan transport should be set up to pipe the message to a
+       suitable checking program or script which runs as a trusted user. This
+       can then re-submit the message to Exim, using \-oMr-\ to set the received
+       protocol to \"scanned-ok"\, and the \-f-\ option to set the correct envelope
+       sender address. \**Warning:**\ If you forget to make the resubmitting process
+       run as a trusted user, the received protocol does not get set, and you
+       are likely to generate a loop.
+
+
+Q0714: Is there a way to configure Exim to reject mail to a certain local host?
+
+A0714: No, only to certain domains. To reject at SMTP time, you can put a line
+       like this in your ACL:
+
+==>      deny message = this domain is deliberately rejected
+              domains = a.certain.domain
+
+       To fail addresses in messages that do not arrive over SMTP, you can set
+       up a router like this:
+
+==>      reject_a_certain_domain:
+           driver = redirect
+           domains = a.certain.domain
+           allow_fail
+           data = :fail: this domain is deliberately rejected
+
+
+Q0715: How can I get Exim to remove attachments from messages?
+
+A0715: Exim does not contain facilities for modifying messages. You must use
+       an external program if you want to do this. You can route messages that
+       have a ::Content-type:: header line via a pipe to a command that does
+       the job and then re-submits the message to Exim. Alternatively, you
+       could use a transport filter to do this job.
+
+
+Q0716: How can I arrange for each user to have a file listing the only sender
+       addresses from which she will accept mail? I want to do this so my
+       family members don't get any spam (or other inappropriate mail).
+
+A0716: Let's assume each user has a file called \(.acceptlist)\ in the home
+       directory. You can put in your ACL a line like this:
+
+==>      require senders = /home/$local_part/.acceptlist
+
+       This will reject RCPT commands when the sender is not in the accept
+       list for the recipient. (Replace \(/home/$local_part)\ with whatever
+       the correct path to your user's home directories is.)
+
+       One problem with this is that it will block bounce messages, which have
+       empty senders. You can get round this, by changing the line to this:
+
+==>      require senders =  : /home/$local_part/.acceptlist
+
+       However, this will, of course, let in spam that has a null sender.
+
+
+Q0717: When using Nessus on a system that runs Exim, a number of security
+       issues are raised. Nessus complains that Exim answers to EXPN and/or
+       VRFY; sometimes it even complains that Exim allows relaying.
+
+A0717: Exim supports EXPN and VRFY only if you permit it to do so in the ACLs
+       defined by \acl_smtp_expn\ and \acl_smtp_vrfy\, respectively. Otherwise,
+       its responses are
+
+==>      550 Administrative prohibition
+         252 Administrative prohibition
+
+       Maybe the use of 252 is the ``problem''. It is recommended that this be
+       done (by those that discuss these things) because there are stupid
+       clients that attempt VRFY before sending a message.
+
+
+Q0718: Could anyone points me to right rules to prevent sending/receiving
+       messages to/for domains which have one MX to localhost or only have
+       address 127.0.0.1 ?
+
+A0718: See Q0319.
+
+
+Q0719: I would like to have a per-user limit for the maximum size of messages
+       that can be sent.
+
+A0719: The simplest way to do this is to put something in a system filter along
+       these lines:
+
+==>    if $message_size is above
+         "${lookup{$sender_address}lsearch{/some/file}{$value}{10M}}"
+       then
+         fail "Message is larger than $sender_address is allowed to send"
+       endif
+
+       In practice, an additional check that the message has arrived from your
+       local host or local network is probably wise because sender addresses
+       are easily forged.
+
+
+Q0720: I set \"accept hosts=192.168.122.96/32"\ in order to accept mail for
+       relaying from my local LAN, but it doesn't work. What's wrong?
+
+A0720: 192.168.122.96/32 is not a network, it is a single host. Exim uses CIDR
+       notation for specifying networks, where the number after the slash is
+       the number of bits in the IP address that must match. Your setting says
+       ``32 bits must match''. If you really mean to specify ``the next 32
+       IP addresses'', you need 192.168.122.96/27.
+
+
+Q0721: I have POP-before-SMTP set up on my Exim server, but some clients use
+       Outlook Express, which sends queued messages before checking the
+       mailbox, so it doesn't work.
+
+A0721: Implement SMTP authentication.
+
+
+Q0722: I installed Amavis and it is working, but bounces are simply vanishing.
+
+A0722: Check that you haven't inadvertently set up the transport like this:
+
+==>      amavis:
+           driver = pipe
+           command = "/usr/sbin/amavis -f ${sender_address} -d ${pipe_addresses}"
+
+       The last line should be:
+
+==>        command = /usr/sbin/amavis -f <$sender_address> -d $pipe_addresses
+
+       The important thing is the <> around the sender address; removal of
+       the unnecessary "" and {} is just tidying. See the amavis FAQ at
+       \?http://www.amavis.org/amavis-faq.php3?\.
+
+
+Q0723: I can't get Pine to work with PLAIN authentication; Exim keeps
+       responding "535 Incorrect authentication data".
+
+A0723: You need to have this setting in your PLAIN authenticator:
+
+==>      server_prompts = :
+
+       This is missing in the examples in all but the most recent Exim
+       documentation, because it was not realized that PLAIN authentication
+       could be requested by a client without sending the data with the
+       request. If the data is not sent, an empty prompt is expected.
+
+
+Q0724: I have used \":fail:"\ in some aliases; when one of these addresses is
+       refused, I see the message on the log, but the response to the remote
+       user is ``unknown user'' instead of the message from the alias file.
+       How can I change this?
+
+A0724: Have you got a \message\ qualifier in the relevant ACL? Exim uses the
+       message line in the ACL in preference to the message returned by the
+       router. This is so you can restrict the amount of information that
+       ``escapes'' from your site via SMTP if you want to. Remove the \message\
+       line in the ACL entry that has \"verify = recipient"\ and your message
+       will get through.
+
+       Alternatively, if you are running Exim 4.10 or later, you can use the
+       \$acl_verify_message$\ variable in your message to include the message
+       from the router. See also Q0725.
+
+
+Q0725: I've set up some specific rejection messages for certain recipients, but
+       when I test them, the SMTP message is always \*550 5.1.1
+       <user@mydomain.com>... User unknown*\.
+
+A0725: That is not an Exim message (the ``5.1.1'' is a clue; Exim doesn't use
+       those extended codes). You are probably being defeated by software that
+       sees the 550 error code, and insists on putting in its own text. There
+       is stupid software that does this. You can test Exim by using \-bh-\ or
+       making a telnet call to the SMTP port. That way, there's no other
+       software intervening.
+
+
+Q0726: My SMTP authentication can be bypassed by sending an unknown user name
+       and an empty password. What is wrong with this condition in a PLAIN
+       authenticator?
+
+==>     server_condition = ${if eq{$2} {${lookup mysql{SELECT password FROM \
+          accounts WHERE username='${local_part:$1}'}}}{1}{0}}
+
+A0726: Your lookup item returns an empty string when the user does not exist.
+       You should instead arrange for the lookup to fail:
+
+==>     server_condition = ${if eq{$2} {${lookup mysql{SELECT password FROM \
+          accounts WHERE username='${local_part:$1}'}{$value}fail}}{1}{0}}
+
+
+Q0727: When a message has many recipients, how can I stop SpamAssassin from
+       being called for each of them? I'm running it from a pipe transport.
+
+A0727: In the transport configuration, set \batch_max\ to a value greater than
+       one.
+
+
+Q0728: How do I use Exiscan, SA-Exim, SpamAssassin, Clam Antivirus, Sophos
+       SAVI, or sophie with Exim?
+
+A0728: There's a mini-HOWTO about these available via
+       \?http://www.timj.co.uk/linux/exim.php?\.
+       See also sample configuration C047.
+
+
+Q0729: How can I screen out addresses that are neither valid usernames or
+       distribution lists on mail being forwarded to an internal Win2K server?
+
+A0729: A user suggested using a router like this to do the recipient
+       verification:
+
+==>      verify_user_router:
+            driver = accept
+            domains = win2kdomain.com
+            local_parts=\
+              ldap;user="cn=ldap-guest,cn=Users,dc=win2kdomain,dc=com"\
+              pass=guest \
+              ldap:://win2kpdc/dc=win2kdomain,dc=com?mailNickname?\
+              sub?(&(mailNickname=$local_part)\
+              (showInAddressBook=*)(sAMAccountName=*))
+            verify_only
+
+       Set up ldap-guest as a normal domain user on the Win2K PDC.
+
+       Also, you need to set \no_verify\ on all the other routers that handle
+       that domain.
+
+
+Q0730: How can I use the same passwords for SMTP authentication as I use for
+       Courier IMAP access to my server?
+
+A0730: You can access the Courier authdaemon from an Exim authenticator. You
+       must arrange for the Exim user (often \/exim/\ but sometimes \/mail/\)
+       to be able to access \(/var/run/courier/authdaemon/socket)\. The
+       configuration is something of a hack, but it is reported to work. Here
+       is a LOGIN authenticator:
+
+==>      login:
+           driver = plaintext
+           public_name = LOGIN
+           server_prompts = Username:: : Password::
+           server_condition = \
+             ${if eq {${readsocket{/var/run/courier/authdaemon/socket}\
+             {AUTH 76\n${length_76:exim\nlogin\n$1\n$2\
+             \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
+             \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
+             \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n}}}}{FAIL\n} {no}{yes}}
+           server_set_id = $1
+
+       Here is a PLAIN authenticator:
+
+==>      plain:
+           driver = plaintext
+           public_name = PLAIN
+           server_prompts = :
+           server_condition = \
+             ${if eq {${readsocket{/var/run/courier/authdaemon/socket}\
+             {AUTH 76\n${length_76:exim\nlogin\n$2\n$3\
+             \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
+             \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
+             \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n}}}}{FAIL\n} {no}{yes}}
+           server_set_id = $2
+
+
+Q0731: Is there any defence I can use against spam sent through an open proxy?
+
+A0731: The \*ident*\ feature can be used in some cases. See the discussion in
+       Q5023.
+
+
+Q0732: I would like to either warn or deny when a host uses an underscore in
+       the EHLO command.
+
+A0732: First, set
+
+==>      helo_allow_chars = _
+
+       This tells Exim not to reject the EHLO or HELO command immediately. Once
+       you have done that, you can test for the underscore in an ACL. For
+       example, to log a warning for hosts in your LAN, and reject for other
+       hosts, you could do something like this:
+
+==>      deny  message = Underscores are not valid in host names
+               hosts = ! +lan_hosts
+               condition = ${if match{$sender_helo_name}{_}{yes}{no}}
+
+==>      warn  log_message = Accepted underscore from [$sender_host_address]
+               condition = ${if match{$sender_helo_name}{_}{yes}{no}}
+
+
+Q0733: Is there any way to tell Exim not to lookup the IP address against any
+       DNS black list if the connection is over IPv6?
+
+A0733: Use this condition in your ACL:
+
+==>      condition = ${if match{${mask:$sender_host_address/0}}\
+                      {${mask:::0/0}}{no}{yes}}
+
+       From Exim 4.23 onwards, this can be simplified to
+
+==>      condition = ${if isip6{$sender_host_address}{no}{yes}}
+
+
+Q0734: How do MailScanner and Exiscan compare? What are the pros and cons?
+
+A0734: The big advantage of Exiscan is that it can reject messages at SMTP time
+       before you have accepted responsibility for them, which means you don't
+       have to deal with bouncing messages and thereby becoming a collateral
+       spammer.
+
+       The big advantage of MailScanner is that it gives you much greater
+       control over the load on your machines. You configure it according to
+       the maximum processing capacity of your computer and it will not exceed
+       that; in fact because it deals with messages in batches the cost of
+       processing a message actually goes down slightly as the load increases,
+       because the per-batch costs are shared by more messages.
+
+       With Exiscan, you have to rely on Exim's load protection mechanisms,
+       which basically means that you have to stop accepting messages when your
+       machine gets too loaded. This is bad if the machine happens to be an
+       SMTP smarthost. You therefore need more overcapacity with Exiscan than
+       with MailScanner.
+
+
+Q0735: How can I block non-FQDNs in HELO/EHLOs?
+
+A0735: Many workstation clients send single-component names; take care that you
+       do not block legitimate mail. With that proviso, you can do it using
+       something like this in an ACL:
+
+==>     drop  message = HELO doesn't look like a hostname
+              log_message = Not a hostname
+              condition = ${if match{$sender_helo_name} \
+                               {\N^[^.].*\.[^.]+$\N}{no}{yes}}
+
+       This means: Drop the HELO unless it contains a dot somewhere in the HELO
+       string, but the string may not begin or end with a dot. Thus, the
+       imposed minimum length is 3 characters.
+
+       The data for HELO/EHLO doesn't have to be a host name; it may
+       legitimately be an IP address literal instead. The above test succeeds
+       with an IPv4 address literal, but if you want also to accept IPv6
+       address literals, you will have to modify the regular expression.
+
+
+Q0736: Is it possible to tell exim to drop the connection after a server
+       attempts to send a message to a number of unknown users?
+
+A0736: Yes. Use \$rcpt_fail_count$\ and the \^drop^\ ACL command, as in this
+       example:
+
+==>      drop  message = Too many unknown users
+               condition = ${if >{$rcpt_fail_count}{15}{yes}{no}}
+
+
+Q0737: Is there some way to tell Exim not to consider 127.0.0.1 as a valid MX?
+
+A0737: See Q0319.
+
+
+Q0738: How can I configure Exim to delay the SMTP connection if more than 10
+       invalid recipients are received in one message?
+
+A0738: Put something like this in your RCPT ACL:
+
+==>      deny  message         = Max $rcpt_fail_count failed recipients allowed
+               condition       = ${if >{$rcpt_fail_count}{10} {1}}
+               ! verify        = recipient
+               delay           = ${eval: $rcpt_fail_count * 10}s
+               log_message     = $rcpt_fail_count failed recipient attempts
+
+       This example increases the delay for each failed recipient.
+
+
+Q0739: Does Exim support SPF?
+
+A0739: An Exim ACL can be used. See \?http://spf.pobox.com/downloads.html?\.
+
+
+
+8. REWRITING ADDRESSES
+
+Q0801: How can I get Exim to strip the hostname from the sender's address?
+
+A0801: If you set up a rewriting rule in the following form:
+
+==>       *@*.your.domain  $1@your.domain
+
+       then Exim will rewrite all addresses in the envelope and the headers,
+       removing anything between \"@"\ and \"your.domain"\. This applies to all
+       messages that Exim processes. If you want to rewrite sender addresses
+       only, the the rule should be
+
+==>       *@*.your.domain  $1@your.domain  Ffrs
+
+       This applies the rule only to the envelope sender address and to the
+       ::From::, ::Reply-to::, and ::Sender:: headers.
+
+
+Q0802: I have Exim configured to remove the hostname portion of the domain on
+       outgoing mail, and yet the hostname is present when the mail gets
+       delivered.
+
+A0802: Check the DNS record for your domain. If the MX record points to a CNAME
+       record instead of to an A record, some MTAs (not Exim) are liable to
+       rewrite addresses, changing your domain name to its ``canonical'' form,
+       as obtained from the CNAME record.
+
+
+Q0803: I want to rewrite local addresses in mail that goes to the outside
+       world, but not for messages that remain within the local intranet.
+
+A0803: You can use the \headers_rewrite\ option on a transport to do this.
+       The rewriting will then apply to just those copies of a message that
+       pass through the transport. The \return_path\ option can similarly be
+       used to rewrite the sender address. There is no way of rewriting
+       recipient addresses at transport time. However, as these are by
+       definition remote addresses, you probably don't want to rewrite them.
+
+       You have to set up the configuration so that it uses different SMTP
+       transports for internal and external mail. If you are using a single
+       router in both cases, you could configure it like this:
+
+==>    dnslookup:
+         driver = dnslookup
+         transport = ${if match{$domain}{\N\.my\.domain$\N}{int_smtp}{ext_smtp}}
+
+       This example uses the \%int_smtp%\ transport for domains ending in
+       \(.my.domain)\, and \%ext_smtp%\ for everything else. The \%ext_smtp%\ transport
+       could be something like this:
+
+==>    ext_smtp:
+         driver = smtp
+         headers_rewrite = *@*.my.domain \
+              ${lookup{$1}cdb{/etc/$2/mail.handles.cdb}{$value}fail}
+         return_path = \
+           ${if match{$return_path}{\N^([^@]+)@(.*)\.my\.domain$\N}\
+            {\
+            ${lookup{$1}cdb{/etc/$2/mail.handles.cdb}{$value}fail}\
+            }\
+            fail}
+
+       This example uses a separate file of local-to-external address
+       translations for each domain. This is not the only possibility, of
+       course. The \headers_rewrite\ and \return_path\ options apply the same
+       rewriting to the header lines and the envelope sender address,
+       respectively.
+
+
+Q0804: I'm using this rewriting rule to change login names into ``friendly''
+       names, but if mail comes in for an upper case login name, it doesn't
+       get rewritten.
+
+==>     *@my.domain     ${lookup{$1}dbm{/usr/lib/exim/longforms}\
+                        {$value}fail}@my.domain bcfrtFT
+
+       The longforms database has entries of the form:
+
+==>      ano23: A.N.Other
+
+A0804: Replace \"$1"\ in your rule by \"${lc:$1}"\ to force the local part to lower
+       case before it is used as a lookup key.
+
+
+Q0805: Is it possible to completely fail a message if the rewrite rules fail?
+
+A0805: It depends on what you mean by ``fail a message'' and what addresses you
+       are rewriting. If you are rewriting recipient addresses for your local
+       domain, you can do:
+
+==>     *@dom.ain  ${lookup{$1}dbm{/wher/ever}{$value}{failaddr}}  Ehq
+
+       and in your alias file put something like
+
+==>     failaddr:   :fail: Rewriting failed
+
+       This fails a single recipient - others are processed independently.
+
+
+Q0806: I'm using \$domain$\ as the key for a lookup in a rewriting rule, but its
+       contents are not being lowercased. Aren't domains supposed to be handled
+       caselessly?
+
+A0806: The value of \$domain$\ is the actual domain that appears in the address.
+       It could of course be lower cased, but I know that would cause some
+       unhappiness, because some people have mixed-case domain names which look
+       silly if the case is changed. Thus, one wants to preserve the case in
+       rewrites such as
+
+==>      *@*.TheRap.com   something@$domain
+
+       because ``therap'' doesn't look like two words. I know it seems trivial,
+       but it is important to some people - especially if by some unfortunate
+       accident the lowercased word is something indecent.
+
+       You can trivally force lower casing by means of the \"${lc:"\ operator.
+       Instead of \"$domain"\ write \"${lc:$domain}"\.
+
+
+Q0807: I want to rewrite local sender addresses depending on the domain of the
+       recipient.
+
+A0807: In general, this is not possible, because a message may have more than
+       one recipient and Exim keeps just a single copy of each message. It may
+       also deliver one copy of a message with several recipient addresses.
+       You can do an incomplete job by using a regular expression match in a
+       rewrite rule to test, for example, the contents of the ::To:: header. This
+       would work except in cases of multiple recipients.
+
+
+
+9. HEADERS
+
+Q0901: I would like add some custom headers to selected outgoing mail based on
+       a specific domain and the subject line.
+
+A0901: To the remote_smtp transport, add something like
+
+==>      headers_add = ${if and{\
+                       {eq{$domain}{spec.dom}}\
+                       {matches{$h_subject:}{whatever}}}\
+                       {Content-Type: text/html; charset="us-ascii"} fail }
+
+       This example shows a ::Content-Type:: header, but you can have anything you
+       like, and multiple headers can be inserted by using \"@\n"\ to separate them.
+
+
+Q0902: Is it possible to have Exim add a header to only certain local parts of
+       outgoing mail?
+
+A0902: Only if you arrange for each such local part to receive its own private
+       copy of the mail. See \max_rcpt\ in the SMTP transport. If you set this
+       to 1, you could use conditions in an expansion string to add or not add
+       a header.
+
+
+Q0903: How can I remove some part of the ::Received:: header?
+
+A0903: Set \received_header_text\.
+
+
+Q0904: How I can insert the PGP header line using Exim filters?
+
+A0904: You can't insert headers in a user filter. A system filter can do so,
+       but the inserted lines then are included for all recipients.
+
+
+Q0905: I know I can use a system filter to replace certain headers in messages,
+       but how can I add text to existing headers? I want to add [SPAM] to
+       the subject line of messages that appear to be spam.
+
+A0905: You can only do this in a round about way, using filter commands like
+       this:
+
+==>      headers add "New-Subject: SPAM: $h_subject:"
+         headers remove subject
+         neaders add "Subject: $h_new-subject:"
+         headers remove new-subject
+
+       This trick works only in system filters, where the commands are obeyed
+       in order, and affect the master list of headers that apply to the whole
+       message. You cannot do this with the \headers_add\ and \headers_remove\
+       options on drivers.
+
+
+
+10. PERFORMANCE
+
+Q1001: I'm running a large mail server. Should I set \split_spool_directory\ to
+       improve performance?
+
+A1001: Splitting the spool directory has most benefit if there are times when
+       there are a large number of messages on the queue. If all mail is
+       delivered very quickly, and the queue is always less than, say, a few
+