[comp.mail.sendmail] Sendmail/UUCP hack for domain qualified UUCP sites

taylor@limbo.Intuitive.Com (Dave Taylor) (06/07/90)

As a site that has a real domain name but UUCP only connectivity, I
have been continually frustrated by the mismatch of the abilities of
the Sendmail program and the needs of the UUX portion of UUCP.  In a
nutshell, to have "domain-ized" email come from my site, I need to
have the message queued in UUCP with the following format:

	From <username> <date> remote from <hostname>
	From: <username>@<qualified.hostname> (<fullname>)

Problem is, "sendmail" wants to have the 'username' in the first From_
line match the 'username@<qualified.hostname>' in the second.  The
bigger problem on top of that is that uux absolutely insists on either
the "remote from host" format, or having a "hostname!" prefix on the
address in the From_ line.  

The easy solution, of course, is to have "sendmail" output the common
address as "hostname!user@qualified-hostname", but, frankly, I think
that email addresses like "limbo!taylor@limbo.intuitive.com" look 
quite terrible!

Instead, what I did as a Unix style hack was to teach "sendmail" to 
deliver UUCP mail to a different program instead of "uux"; the
program attached below, called "uux.filter".  The "sendmail.cf" file
was hacked on a bit so that it now *doesn't* think that "uux" is a
UUCP style mailer (e.g the "U" flag in the "F=" mailer definition)
and so that it just uses domain style "user@host.domain" addresses
for both the From: and From_ lines.

So what ends up happening is that a typical message comes out of
"sendmail" like:
	
	From taylor@limbo.intuitive.com <date>
	From: taylor@limbo.intuitive.com (Dave Taylor)
	Subject: hi

and then "uux.filter" rewrites it as:

	From taylor <date> remote from limbo
	From: taylor@limbo.intuitive.com (Dave Taylor)
	Subject: hi

and hands it to the real "uux" program.  End result: "uux" and the
entire "uucp" package is happy, *and* we end up with nice looking
From: addresses without mixed mode, redundant hostname addresses.

The modification to my "sendmail.cf" file is on the two mailer definition
lines below - note the P= value and the F= flags...

  ############################################################
  ###                   UUCP mailer                        ###
  ############################################################

  Muucp, P=/usr/bin/uux.filter,  F=DFMshu,   S=13, R=23, A=uux - $h!rmail ($u)

  S13
  R$+<@$+.UUX>		$@$2!$1<@$H.UUX>	host!user => my_host!host!user 
  R$+<@$+>		$@$1%$2<@$j>		user@host => user%host@my_host
  R<@$+>:$+		$@<@$j>:@$1:$2		prepend @my_host to route
  R$+			$@$1<@$j>		user => user@my_host

  S23

  ############################################################
  ###                Dumb UUCP mailer                      ###
  ############################################################

  Mdumbuucp,  P=/usr/bin/uux.filter,  F=DMshux,  R=23, A=uux - $h!rmail ($u)

As you can see, we simply "stick it in the middle".

			Enjoy!
						-- Dave Taylor

						taylor@limbo.intuitive.com

-- Attachment: "uux.filter.c"

/**				uux.filter.c				**/

/** A simple program that puts itself in front of the standard "uux" command 
    to allow us to have non-UUCP style messages come from "sendmail" and end 
    up, correctly formatted, in the UUCP outbound queue.  Note that the "real" 
    uux is still used; we just expect "sendmail" to call us instead.

    The fixing up involved in this program is simply to change the format of 
    the "From " line to ensure that it ends with the suffix of "remote from 
    HOSTNAME".

	(C) Copyright 1990, Dave Taylor, Intuitive Systems.

    Distribution of any nature allowed as long as this header is retained
    without modification.

    Compile with: "cc -O uux.filter.c -o uux.filter" and then fix your
    "sendmail.cf" UUCP mailer definition to know about it.
**/

/** include the following if you're debugging your installation... 

#define DEBUGGING

**/

#include <stdio.h>
#include <errno.h>
#include <ctype.h>

#define REAL_UUX	"/usr/bin/uux"
#define TEMPFILE	"/tmp/uux.fix.%d"

/** the following should be changed to reflect your own site values! **/

#define HOSTNAME	"limbo"
#define TO_STRIP	"@limbo.intuitive.com"

/** compares in a case-independent way... **/

#define same_char(c,d)	(c == d || c == isupper(d) ? tolower(d) : d ||  \
			 d == isupper(c) ? tolower(c) : c)

extern int errno;

main(argc, argv)
int argc;
char **argv;
{
	FILE   *pipe_to_uux;
	char   uux_command[4096];
	char   buffer[256];

	/** build up the command to the real uux program **/

	argv++;
	strcpy(uux_command, REAL_UUX);

	while (--argc) {			/* grab args.. */
	  strcat(uux_command, " '");		/*   and quote */
	  strcat(uux_command, *argv++);		/*     them!   */
	  strcat(uux_command, "'");
	}

	/** now let's try to open a write-only pipe to "uux" **/

	if ((pipe_to_uux = popen(uux_command, "w")) == NULL) {
	   printf("uux.filter: failed trying to popen(%s) error=%d\n", 
		   uux_command, errno);
	   exit(1);	/* This will cause a sendmail bounce messsage */
	}
	else {
	  while (gets(buffer) != NULL) {
	    if (strncmp(buffer, "From ", 5) == 0) {
	      fix_buffer(buffer);
	      fprintf(pipe_to_uux, "%s remote from %s\n", buffer, HOSTNAME);
	    }
	    else
	      fprintf(pipe_to_uux, "%s\n", buffer);
	  }
	  pclose(pipe_to_uux);
	}

#ifdef DEBUGGING
	printf("uux.filter: delivered message to '%s'\n", uux_command);
#endif

	exit(0);
}

fix_buffer(buffer)
char *buffer;
{
	/** Given a buffer of the form "From user@host <DATE>" return
	    it as "From user <DATE>"  We do this by stripping out the
	    @host field; but only iff it matches our "TO_STRIP" value
	    as we go along.  As soon as it fails, we'll bail!
	**/

	char ourbuffer[256];
	register int i, j = 0, k=1;
	int  skip = 0;

	for (i = 0; buffer[i] != 0; i++) {
	  if (buffer[i] == '@')         skip = 1;
	  if (buffer[i] == ' ' && skip) skip = 0;

	  if (! skip) 
	    ourbuffer[j++] = buffer[i];
	  else
	   if (! same_char(buffer[i], TO_STRIP[k])) {	/* they don't match */
#ifdef DEBUGGING
	     printf("uux.filter: fields '%s' and '%s' diverge at char %d/%d\n",
		     buffer, TO_STRIP, i, k);
#endif
	     return;
	   }
	}

	ourbuffer[j] = 0;

	strcpy(buffer, ourbuffer);
}

/** end of program listing **/