jer@peora.UUCP (J. Eric Roskos) (09/13/85)
With a certain amount of reluctance, I am posting the following set of routines for the translation of RFC822-style mail addresses to net.sources. These are the routines which I have recently discussed at great length in net.mail. See that newsgroup for more information on what they do. These routines require a DBM-style pathalias database. Pathalias was posted a few weeks ago to this newsgroup, by Peter Honeyman. There are 2 pieces of documentation included. People familiar with RFC822 should read OPATH(3), which gives a complete explanation. People who don't know what RFC822 is should read ADDRESS(1), which gives a very simplified (and sometimes out-of-date) description of the basic ideas behind RFC822-based addressing (with simplifications such as in the description of what a "domain" is). These routines are intended to be included in a UUCP transport-mechanism mailer (oupath() serves this role), or in a user interface (opath() serves this function). The typical way to invoke them is: From a user interface: route=opath(address); From a transport-level mailer: if (index(address,"!")) /* better tests are possible */ route=oupath(address); else route=opath(address); These programs are posted in answer to the assertion that rational principles of routing using existing mailers are "an academic exercise at best". They have been working here for nearly a year. Note that someone at another site is working on a mailer which will include these; if you don't have source code for your mailer, you may want to use his, when it is completed. AT&T's UUCP Project is also shortly going to come out with a mailer, which may or may not be compatible with this software. Gateways named in the sample domain table provided are not necessarily valid gateways, nor necessarily those you should use at your site. # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #-----cut here-----cut here-----cut here-----cut here----- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # opath.c # address.c # /usr/man/local/man1/address.1 # /usr/man/local/man3/opath.3 # /usr/lib/uucp/domains # This archive created: Fri Sep 13 09:06:34 1985 echo shar: extracting opath.c '(5859 characters)' cat << \SHAR_EOF > opath.c /* * opath.c - get an optimal uucp path from the path database, using an * RFC882-style address as input. The '%' character is properly translated, * and gateway-substitution is done to get mail onto other networks. * * This program requires the DBM-style pathalias database. * * Eric Roskos, Perkin-Elmer Corp. SDC * Version 3.2 created 85/09/12 15:21:51 */ static char *opathsccsid = "@(#)opath.c 3.2 (peora) 15:21:51 - 85/09/12"; #include <stdio.h> #include <whoami.h> /** ** User-configurable parameters **/ /* locations of files */ static char *archive = "/usr/lib/uucp/alpath"; /* pathalias database */ static char *domfile = "/usr/lib/uucp/domains"; /* gateway/domain table */ static char *logfile = "/usr/adm/opath.log"; /* activity log */ /** ** Global Variables **/ static char pval[150]; /* the path string is built here */ /* * the following are used to pass results by side-effect from the domain() * routine. */ static char prefix[80], suffix[80], fullsite[80]; /** ** Subroutines **/ /* * The Domain Table and its associated routines */ static struct domains { char dom[50]; char pre[50]; char suf[50]; char map[50]; } domtab[100]; /* Inline routine to copy a domain into the domain table */ #define DOMCPY(fld) { int i = 0; q=dp->fld; while (*p!=','&&*p!='\n'&&*p) \ {*q++ = *p++; if (i++>=48) break;} \ *q++ = '\0'; if (!*p) { \ fprintf(stderr,"opath: fld(s) missing in %s at %s\n", \ s, buf); \ dp++; continue;} p++; } /* Load the domain table from disk */ static int loaddomtab(s) char *s; { FILE *f; char buf[100]; register char *p,*q; struct domains *dp; f = fopen(s,"r"); if (f==NULL) { fprintf(stderr,"opath: can't open domain file '%s'\n",s); exit(1); } dp = domtab; while (fgets(buf,100,f)) { if (buf[0]=='#') continue; /* comments start with "#" */ p = buf; DOMCPY(dom); DOMCPY(pre); DOMCPY(suf); DOMCPY(map); if (dp->map[0] == '\0') { fprintf(stderr,"opath: bad route template in %s\n",s); strcpy(dp->map,"Invalid"); } dp++; } dp->map[0] = '\0'; /* mark end of table */ fclose(f); return(0); } /* Get a UUCP path from the pathalias database */ static char * gpath(s) char *s; { static char path[100]; char *uupath(); strcpy(path,uupath(s)); return(path); } /* String compare: entire first argument must match suffix of 2nd argument */ static int domcmp(ss,tt) char *ss, *tt; { char *s, *t; int cmp; s = ss + strlen(ss) - 1; t = tt + strlen(tt) - 1; do { if (*s - *t) break; s--; t--; } while (s >= ss); if (++s == ss) return(0); else return(1); } /* Look up a domain, and by side effect set prefix and suffix appropriately */ char *domain(s) char *s; { struct domains *d; char *p; static int loaded = 0; if (!loaded++) loaddomtab(domfile); if (*s!='.') /* default to UUCP domain */ { prefix[0]=suffix[0]='\0'; return("%R!%U"); } for (p=s; *p; p++) if (*p>='a' && *p<='z') *p -= 'a'-'A'; for (d = &domtab[0]; (int)d->map[0]; d++) { if (domcmp(d->dom,s)==0) break; } strcpy(prefix,(d->pre[0]=='>')? gpath(&d->pre[1]) : d->pre); strcpy(suffix,d->suf); return(d->map); } /* opath: generates a UUCP path from an RFC-822 address */ #define COPYON(s) {char *r; r=s; while (*r) *p++ = *r++; *p = '\0';} char * opath(s) char *s; { char user[50],site[50]; static char cm[150]; FILE *f; char *p, *q, *t; char *d; int i; int found; char *suf; for (p=user,q=s;(*p = *q)!='@'; p++,q++) if (*q=='\0') return(s); *p = '\0'; strcpy(fullsite,++q); for (p=site;(*p = *q)!='.'; p++,q++) if (*q=='\0') break; *p = '\0'; d = domain(q); if (d[0]=='\0') return(s); /* unknown domain - do nothing */ for (p=pval, q=d; *q; q++) { if (*q=='%') { switch(*++q) { case 'P': COPYON(prefix); break; case 'S': COPYON(suffix); break; case 'U': COPYON(user); break; case 'N': COPYON(site); break; case 'D': COPYON(fullsite); break; case 'R': COPYON(gpath(site)); break; case '%': *p++ = '%'; break; } } else *p++ = *q; } return(pval); } /* oupath: generates a uucp path from a (possibly disconnected) uucp path */ char *oupath(s) char *s; { char *p,*q; static char adr[100]; char first[100]; int found; for (p=s,q=first,found=0; *p!='!' && *p!='\0'; p++) { if (*p=='.') found++; *q++ = *p; } if (*p=='\0') return (s); *q = '\0'; if (found) { strcpy(adr,++p); strcat(adr,"@"); strcat(adr,first); return(opath(adr)); } else { int i; strcpy(adr,gpath(first)); strcat(adr,/* ++ */p); return(adr); } } /** ** Public-domain subroutines obtained from net.sources **/ /* * The following is extracted from William Sebok's uupath program */ /* * * * uupath - look up path to computer in database * * * W.Sebok 11/4/83 */ #ifdef NULL #undef NULL #define NULL 0 #endif typedef struct {char *dptr; int dsize;} datum; datum fetch(); datum firstkey(); datum nextkey(); static char * uupath(s) char *s; { char *fil; int ret; datum key; static datum result; char buf[BUFSIZ]; static int inited = 0; fil = archive; strcpy(buf,s); /*** strcat(buf,"!"); ***/ key.dptr = buf; key.dsize = strlen(key.dptr) + 1 ; if (!inited++) { ret = dbminit(fil); if (ret != 0) { fprintf(stderr,"Can't open database '%s'\n",fil); return(s); } } result = fetch(key); if (result.dptr != NULL) { if (domcmp("!%s",result.dptr)==0) { result.dptr[result.dsize-4] = '\0'; } /* next line handles strange pathalias "feature" */ if (strcmp(result.dptr,"%s")==0) return(SYSNAME); return(result.dptr); } else { fprintf(stderr,"%s not found\n",s); return(s); } return(s); } opathlog(fmt,a,b,c,d) char *fmt; int a,b,c,d; { FILE *f; f = fopen(logfile,"a"); if (f==NULL) return; fprintf(f,fmt,a,b,c,d); fclose(f); } SHAR_EOF if test 5859 -ne "`wc -c opath.c`" then echo shar: error transmitting opath.c '(should have been 5859 characters)' fi echo shar: extracting address.c '(581 characters)' cat << \SHAR_EOF > address.c /* * address - run opath to see what a translated RFC822 address will come * out as. * * By E. Roskos 1/16/85 */ #include <stdio.h> char *opath(); main(argc,argv) int argc; char **argv; { char *p; int uswitch; if (argc < 2) { fprintf(stderr,"usage: %s rfcaddress [...]\n", argv[0]); exit(1); } while (--argc) { p = *++argv; if (*p=='-') { switch(*++p) { case 'u': uswitch++; continue; default: printf("unknown switch: %c\n",*p); continue; } continue; } printf("%s: %s\n",p,uswitch?oupath(p):opath(p)); } exit(0); } SHAR_EOF if test 581 -ne "`wc -c address.c`" then echo shar: error transmitting address.c '(should have been 581 characters)' fi echo shar: extracting address.1 '(3563 characters)' cat << \SHAR_EOF > address.1 .TH ADDRESS 1 local .SH NAME address - display the path generated by \fBdeliver\fR for an RFC822-format address. .SH SYNOPSIS address rfc-address [ ... ] .SH DESCRIPTION This program allows you to check the UUCP mail routing path that will be generated by the UUCP mailer \fBdeliver\fR if you specify an RFC822-format address \fBrfc-address\fR in the ``To:'' field of the mail header. For each RFC-style address on the command line, \fBaddress\fR echoes the address to the standard output, followed by a colon, followed by the UUCP address that will be used to send the message to that address. .SH "ADDRESS FORMAT" Briefly, the RFC822-format address is of the form .nf .sp 1 <localaddress>@<hostname>.<network> .sp 1 .fi where <hostname> is the name of the system you are sending the message to, <network> is a modifier for <hostname> identifying the network in which the address is to be interpreted (UUCP, ARPA, MAILNET, CSNET, etc); and <localaddress> is an address string to be interpreted on the host machine. The <localaddress> field may contain further remote addresses to be interpreted on the host machine. Typically this will be an address for mailing via another network; and in particular, the <localaddress> may (recursively) be identical in format to the RFC address, but with the symbol `%' replacing the symbol `@' in the standard address format. Where this form is used, the rightmost % is replaced by an @ before the host machine sends the message out. On our system, the presently valid <network>s are UUCP, ARPA, CSNET, and MAILNET. The recently proposed UUCP domain names are also accepted, although they are treated the same as plain ``UUCP''. Omitting the <network> causes the network to default to UUCP. The <hostname> should be the name of a remote machine to which the message is directed; see \fI/usr/lib/uucp/uuaddress.alpha\fR for a list of all known UUCP hostnames. It is \fInot\fR necessary to specify a UUCP pathname when using this format; the pathname is automatically determined for you and substituted into the address before mailing. The selected pathname is determined using the \fBpathalias\fR database, and is supposed to be optimal, taking into consideration information provided by each site about how often they send mail out, etc. .SH EXAMPLES .HP 5 joe .br The message is sent to the user ``joe'' on the local system. .HP 5 joe@ucbvax .br The message is sent to joe on the UUCP system named ``ucbvax''; this address is automatically translated to a proper (and ostensibly optimal) UUCP path. .HP 5 joe@ucbvax.UUCP .br Same as joe@ucbvax .HP 5 joe@ucbvax.ARPA .br The message is addressed to joe at ucbvax, using the ARPA network. The message will be routed to the ARPAnet via a UUCP-ARPAnet gateway. .HP 5 joe%mit-multics.ARPA@ucbvax .br The message is sent to ucbvax, who then uses the address joe@mit-multics.ARPA to send the message on to mit-multics via the ARPAnet. Since ucbvax is on the arpanet, this address will work correctly (as long as there is someone named joe on the MIT multics machine). .HP 5 joe%vanderbilt.MAILNET%mit-multics.ARPA@ucbvax .br The message is sent via UUCP to ucbvax, who then sends the message to mit-multics via the arpanet; mit-multics then sends the message to joe@vanderbilt via MAILNET. Since the above machines each have access to the networks named in the address, this address will work correctly. .SH FILES /usr/lib/uucp/domains - Domain/gateway table .br /usr/lib/uucp/archive - Pathalias database .SH "SEE ALSO" opath(3) .SH AUTHOR Eric Roskos, PE SDC, 1/16/85 SHAR_EOF if test 3563 -ne "`wc -c address.1`" then echo shar: error transmitting address.1 '(should have been 3563 characters)' fi echo shar: extracting opath.3 '(4896 characters)' cat << \SHAR_EOF > opath.3 .TH OPATH 3 "PE SDC" .SH NAME opath - Generate a UUCP route from an RFC822 address .br oupath - Generate a UUCP route from a (possibly disconnected) UUCP path .SH SYNOPSIS char *opath(s) .br char *s; .sp 1 char *oupath(s) .br char *s; .SH DESCRIPTION These routines use the \fBpathalias\fR database to generate UUCP routing paths from your local site to specified remote sites on either the UUCP network or other connected networks. .PP \fBopath\fR takes one argument, an RFC822 address, as described in ADDRESS(1). From this, it generates and returns a UUCP path to the site named in the argument. .PP \fBoupath\fR takes one argument, a UUCP path. If the next site on this path is named \fIx\fR, \fBoupath\fR will prepend a path from your site to \fIx\fR, if \fIx\fR is nonadjacent to your site. If \fIx\fR is a domain, i.e. contains a dot (.), \fBoupath\fR will generate a path to a gateway for this domain. Note that \fBoupath\fR will \fInot\fR alter the argument path, other than to make the above transformations; it does not check whether sites in the argument are adjacent to one another, or whether they represent an optimal path; it is assumed that if the user has specified a path, then he wants to use that path. .PP The principal difference between \fBopath\fR and \fBoupath\fR is that the former gives precedence to ``@'', whereas the latter gives precedence to ``!''. The former is intended to be invoked when receiving mail from a user interface or a non-UUCP source (if the subsequent transport mechanism is to be UUCP), whereas the latter is intended solely to be used by UUCP internal software, principally \fBrmail\fR, in routing mail through the UUCP network. .SH "FILES" \fI/usr/lib/uucp/archive\fR - The pathalias database, in DBM(3) format. See PATHALIAS(1) for information; pathalias is a public-domain program distributed via the Usenet's net.sources facility. .br .sp 1 \fI/usr/lib/uucp/domains\fR - The domain/gateway table. Each line of this file consists of either a ``#'' followed by arbitrary comment text, or an entry of the form: .br .in 1i <domain>,<path>,<reserved>,<template> .br .in Where <domain> is the string (in capital letters) identifying a particular <path> is a string which may be included at an arbitrary point in the generated route, <reserved> is currently unused, and <template> is a string indicating the format of the generated route. .PP The <template> is a printf-style string; it is \fBnot\fR quoted, and begins at the character immediately following the comma which separates <template> from <reserved>. The <template> may consist of arbitrary ASCII characters, which are copied unchanged into the generated route; or of a percent (%) sign followed by one of the following characters: .IP P The <path> string is inserted. The <path> may consist either of a string which is inserted unchanged; or of the character ``>'' followed by the name of a UUCP site, in which case the entire <path> string is replaced with a string representing the path to the named site. The last token on this string is the site named in the original <path> string, without a following ``!''. .IP U The user name from the original address is inserted. .IP N The site name from the original address, with the domain specifiers removed, is inserted. .IP D The site name from the original address, including the domain specifiers, is inserted. .IP R The UUCP path to the site named in the original address is looked up in the pathalias database and inserted. Note that this path is looked up only when the %R is seen while scanning the <template>, so an error message for an invalid site name is generated if and only if it appears in an address with a domain which contains a %R in its template. .PP When making entries in the domain table, domain names which are a suffix of another domain name in the table should be ordered such that the longer string(s) appear first. For example, .WA.UUCP should preceed .UUCP in the table. A linear search is made of the table, and the first domain found in the table which is a suffix of the domain in the designated address is used as the domain in generating the routing. .PP Following are some example entries for the domain table. Note that all domain names begin with a ``.''. .sp 1 .nf .in 1i # This is a comment \&.HP.UUCP,,,%R!%U \&.UUCP,,,%R!%U \&.CSNET,>decwrl,,%P!%U%%%S@CSNET-RELAY.ARPA \&.EDU,>ucbvax,,%P!%D .in .fi .sp 1 .SH "SEE ALSO" PATHALIAS(1), ADDRESS(1), RMAIL(1) .SH "AUTHOR" Eric Roskos, Perkin-Elmer Corp. SDC. .SH "NOTE" The <reserved> field in the domain table currently has a function which may be determined by examining the source code for opath. However, this function is a vestigal function provided for sites that used an earlier version of opath; future opath versions will use this field for a different purpose, and new users of opath therefore should \fBnot\fR use this field. SHAR_EOF if test 4896 -ne "`wc -c opath.3`" then echo shar: error transmitting opath.3 '(should have been 4896 characters)' fi echo shar: extracting domains '(1167 characters)' cat << \SHAR_EOF > domains # # Perkin-Elmer SDC Domain Table # # Format: <domain>,<prefix>,<suffix>,<template> # # Where <template> may contain: # %P - prefix string # %S - suffix string # %U - destination user name # %N - destination site name # %D - destination site name with domain suffix # %% - a percent (%) sign # %R - pathalias route to the destination site # .WA.UUCP,,,%R!%U .OR.UUCP,,,%R!%U .N-CA.UUCP,,,%R!%U .S-CA.UUCP,,,%R!%U .MTN.UUCP,,,%R!%U .S-CEN.UUCP,,,%R!%U .MID-W.UUCP,,,%R!%U .S-EAST.UUCP,,,%R!%U .ATL.UUCP,,,%R!%U .N-ENG.UUCP,,,%R!%U .HI.UUCP,,,%R!%U .W-CAN.UUCP,,,%R!%U .E-CAN.UUCP,,,%R!%U .EUR.UUCP,,,%R!%U .UK.UUCP,,,%R!%U .AUS.UUCP,,,%R!%U .ISRAEL.UUCP,,,%R!%U .ATT.UUCP,>ihnp4,,%P!%D!%U .HP.UUCP,,,%R!%U .PE.UUCP,,,%R!%U .UUCP,,,%R!%U .CSNET,>ucbvax,,%P!%U%%%D@CSNET-RELAY.ARPA .MAILNET,>ucbvax,,%P!%U%%%D@MIT-MULTICS.ARPA # .BITNET,>ucbvax,,%P!%U%%%D@WISCVM.ARPA .XEROX,>ucbvax,,%P!%U.%D@XEROX.ARPA .DEC,>decwrl,,%P!%U@%D .ARPA,>ucbvax,,%P!%U@%D .EDU,>ucbvax,,%P!%U@%D .COM,>ucbvax,,%P!%U@%D .GOV,>ucbvax,,%P!%U@%D .MIL,>ucbvax,,%P!%U@%D .OTH,>ucbvax,,%P!%U@%D .BITNET,>psuvax,,%P!%U@%D # # our local domains # .PE,,,%R!%U SHAR_EOF if test 1167 -ne "`wc -c domains`" then echo shar: error transmitting domains '(should have been 1167 characters)' fi # End of shell archive exit 0 -- Shyy-Anzr: J. Eric Roskos UUCP: Ofc: ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jer Home: ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jerpc!jer US Mail: MS 795; Perkin-Elmer SDC; 2486 Sand Lake Road, Orlando, FL 32809-7642