home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Header-cracking and address re-writing routines, with sincere
- ** apologies to Upas and Sendmail.
- */
- #include "gate.h"
- #include <netdb.h>
- #ifdef RCSID
- static char RCS[] =
- "$Header: /nfs/papaya/u2/rsalz/src/newsgate/src/RCS/hdr.c,v 1.15 91/03/15 16:39:42 rsalz Exp $";
- #endif /* RCSID */
-
-
- #ifdef TEST
- #ifndef DO_FIX_ADDRESS
- #define DO_FIX_ADDRESS
- #endif /* DO_FIX_ADDRESS */
- #define dprintf(string, buff) (void)printf((string), (buff))
- #else
- #define dprintf(string, buff) /* NULL */
- #endif /* TEST */
-
-
- /*
- ** List of domains that we recognize.
- */
- STATIC char RELAY_CS_NET[] = "RELAY.CS.NET";
- STATIC char *Domains[] = {
- /* Don't undo the % hack for sites @RELAY.CS.NET, sigh #1. */
- RELAY_CS_NET,
- /* These aren't official domains, but we use them, sigh #2. */
- ".BITNET",
- ".UUCP",
- /* Official organizational domains. */
- ".ARPA", ".COM", ".EDU", ".GOV", ".INT", ".MIL",
- ".NATO", ".NET", ".ORG",
- /* Official natonal domans. */
- ".AR", ".AT", ".AU", ".BE", ".BR", ".CA", ".CH", ".CL",
- ".CN", ".CR", ".CS", ".DE", ".DK", ".EC", ".EG", ".ES",
- ".FI", ".FR", ".GR", ".HK", ".HU", ".IE", ".IL", ".IN",
- ".IS", ".IT", ".JP", ".KR", ".LK", ".MX", ".MY", ".NI",
- ".NL", ".NO", ".NZ", ".PH", ".PL", ".PR", ".PT", ".SE",
- ".SG", ".SU", ".TH", ".TR", ".TW", ".UK", ".US", ".UY",
- ".YU", ".ZA"
- };
-
-
- /*
- ** Local user?
- */
- STATIC int
- Local(p)
- register char *p;
- {
- for ( ; *p; p++)
- if (NETCHR(*p))
- break;
- return *p == '\0';
- }
-
-
- /*
- ** Case-insensitive strncmp.
- */
- STATIC char *
- Found(dp, p)
- register char *dp;
- register char *p;
- {
- register char *q;
- register char *r;
-
- for ( ; *p; p++)
- if (CHREQ(*p, *dp)) {
- for (q = p, r = dp; *r && CHREQ(*q, *r); q++, r++)
- ;
- if (*r == '\0')
- return p;
- }
-
- return NULL;
- }
-
-
- /*
- ** Find all domain names and make them uppercase:
- ** joe%site.edu@relay.cs.net --> joe%site.EDU@RELAY.CS.NET
- */
- STATIC void
- Casify(p)
- register char *p;
- {
- register char *q;
- register char *r;
- register char **dp;
-
- for (dp = Domains; dp < ENDOF(Domains); dp++)
- for (q = p; q = Found(*dp, q); )
- for (r = *dp; *r; *q++ = *r++)
- ;
- }
-
-
- /*
- ** Handle route-addresses:
- ** @cruft:joe@site --> joe@site
- */
- STATIC void
- RouteAddr(p)
- register char *p;
- {
- register char *q;
- register char *r;
-
- for (r = p; *p == '@'; p = q)
- if ((q = IDX(p, ':')) && IDX(q, '@'))
- *q++ = '\0';
- else
- break;
- if (p > r)
- /* Avoid overlaping strcpy() call. */
- while (*r++ = *p++)
- ;
- }
-
- /*
- ** Does the pattern exist in the character range between p and end?
- */
- STATIC int
- Between(p, pat, q)
- register char *p;
- register char *pat;
- register char *q;
- {
- register char *r;
-
- for (r = pat + strlen(pat); p < q && r >= pat && *--q == *--r; )
- ;
- return *r == '\0';
- }
-
-
- /*
- ** Handle the '%' syntax:
- ** joe%site.EDU@gateway.DOMAIN -> joe@site.EDU
- */
- STATIC void
- Percent(p)
- register char *p;
- {
- register char *q;
- register char *r;
- register char **dp;
-
- while ((r = IDX(p, '%')) && (q = IDX(r, '@'))) {
- for (dp = Domains; dp < ENDOF(Domains); dp++) {
- if (*dp == RELAY_CS_NET)
- continue;
- if (Between(r, *dp, q)) {
- *RDX(p, '@') = '\0';
- *RDX(p, '%') = '@';
- break;
- }
- }
- if (dp == ENDOF(Domains))
- break;
- }
- }
-
-
- /*
- ** Handle CSNET, which is domainist except in some people's minds:
- ** joe%site@RELAY.CS.NET --> joe@site.CSNET
- ** joe%site.EDU@RELAY.CS.NET --> joe@site.EDU
- */
- STATIC void
- Csnet(p)
- register char *p;
- {
- register char *q;
- register char *r;
-
- if ((q = RDX(p, '@'))
- && strcmp(q, "@RELAY.CS.NET") == 0
- && (r = RDX(p, '%'))) {
- *RDX(p, '@') = '\0';
- *r = '@';
- if (IDX(r, '.') == NULL)
- Strcat(p, ".CSNET");
- }
- }
-
-
- /*
- ** Handle hybrid "!" and "@" addresses:
- ** a!site!joe@site --> joe@site
- ** a!site!joe --> joe@site.UUCP
- ** a!site.EDU!joe --> joe@site.EDU
- */
- STATIC void
- Hybrid(p)
- register char *p;
- {
- register char *q;
- register char *user;
- char buff[SM_SIZE];
-
- if (user = RDX(p, '!')) {
- *user++ = '\0';
- if (q = IDX(user, '@'))
- *q = '\0';
- q = (q = RDX(p, '!')) ? q + 1 : p;
- Sprintf(buff, "%s@%s", user, q);
- if (IDX(q, '.') == NULL)
- Strcat(buff, ".UUCP");
- Strcpy(p, buff);
- }
- }
-
-
- /*
- ** Handle special case for Australia:
- ** user@site.OZ --> user@site.OZ.AU
- */
- STATIC void
- Endpart(p)
- register char *p;
- {
- register char *r;
-
- if ((r = RDX(p, '.')) && r[1] == 'O' && r[2] == 'Z' && r[3] == '\0')
- Strcpy(&r[3], ".AU");
- }
-
-
- /*
- ** General address canonicalizer.
- */
- STATIC char *
- FixAddress(p)
- register char *p;
- {
- static char buff[1024];
- char host[128];
-
- if (Local(p)) {
- if (gethostname(host, sizeof host) < 0) {
- Fprintf(stderr, "%s: Can't get my hostname, %s.\n",
- Pname, strerror(errno));
- exit(EX_TEMPFAIL);
- }
- Sprintf(buff, "%s@%s", p, host);
- }
- else {
- Strcpy(buff, p);
- Casify(buff);
- dprintf(" Casify returns %s\n", buff);
- RouteAddr(buff);
- dprintf("RouteAddr returns %s\n", buff);
- Percent(buff);
- dprintf(" Percent returns %s\n", buff);
- Csnet(buff);
- dprintf(" Csnet returns %s\n", buff);
- Hybrid(buff);
- dprintf(" Hybrid returns %s\n", buff);
- Endpart(buff);
- dprintf(" Endpart returns %s\n", buff);
- }
- return buff;
- }
-
-
- /*
- ** This subroutine is a concession to the realities of the Internet and
- ** and the USENET. Much as the idea is distasteful and likely to get me
- ** in trouble, I have to hack message-ids into a format that the USENET
- ** won't choke on. Pray that if we're doing multiple insertion point
- ** gatewaying that ALL the gateways mung exactly the same things.
- **
- ** (Death to HERMES! Death to UNIX/MM-11! Death to EAN!)
- */
- STATIC int
- FixMessageID(s)
- register char *s;
- {
- register int atdot;
- register int closed;
-
- /* Quickie tests -- why waste time? */
- if (*s != '<')
- return FALSE;
-
- for (atdot = FALSE, closed = FALSE; *++s; )
- switch (*s) {
- default:
- if (!isascii(*s) || iscntrl(*s) || isspace(*s))
- return FALSE;
- break;
- case '<':
- /* Already got one. */
- return FALSE;
- case '>':
- /* I hope no one is stupid enough to quote this... */
- closed = TRUE;
- s[1] = '\0';
- break;
- case '.':
- case '@':
- /* We should check for a domain spec, not just either/or. */
- atdot = TRUE;
- break;
- case '\t':
- case ' ':
- case '/':
- /* Avoid various problem characters. */
- *s = '.';
- break;
- }
-
- return atdot && closed;
- }
-
-
- /*
- ** Fix up the contents of In-Reply-To: fields and References: fields.
- */
- STATIC void
- FixReferences(hp)
- register HBUF *hp;
- {
- register char *cp;
- register char *ep;
- register char *p;
- register char *max;
- char scratch[LG_SIZE];
-
- cp = hp->followid;
- max = cp + strlen(cp);
- for (p = scratch; cp = IDX(cp, '<'); ) {
- if ((ep = IDX(cp, '>')) == NULL
- || ((ep - cp) + 1) > sizeof scratch - (p - scratch + 2))
- /* Unterminated ID, or no more room. */
- break;
-
- if (FixMessageID(cp)) {
- if (p > scratch) {
- *p++ = ' ';
- *p++ = '\0';
- }
- p += APPEND(p, cp);
- }
- cp = ep + 2;
- if (cp >= max)
- break;
- }
- Strcpy(hp->followid, scratch);
- }
-
-
- /*
- ** Count the number of '@' in the string.
- */
- STATIC int
- AtCount(s)
- register char *s;
- {
- register int n;
-
- for (n = 0; *s; s++)
- if (*s == '@')
- n++;
- return n;
- }
-
-
- /*
- ** Canonicalize the "From:" line into the form
- ** From: local-part@domain (full-name)
- ** RFC822 doesn't require the comment to be at the end of the string
- ** like that.
- */
- STATIC void
- FixFrom(hp)
- register HBUF *hp;
- {
- register char *p;
- register struct hostent *host;
- char address[LG_SIZE];
- char fullname[LG_SIZE];
- char scratch[sizeof address];
-
- /* We should handle "Full-Name:" too, but it doesn't get read by the
- * news header reader. */
- (void)CrackFrom(address, fullname, hp->from);
- #ifdef DO_ADDRESS_CLEANUP
- Strcpy(address, FixAddress(address));
- #endif /* DO_ADDRESS_CLEANUP */
-
- if (AtCount(address) != 1)
- p = NULL;
- else {
- p = IDX(address, '@');
- *p++ = '\0';
-
- #ifdef DO_ADDRESS_CLEANUP
- /* If we can find the host's official name use that. */
- if (host = gethostbyname(p))
- p = host->h_name;
- #endif /* DO_ADDRESS_CLEANUP */
-
- /* We know have the canonical hostname; glue back together. */
- Sprintf(scratch, "%s@%s", address, p);
- Strncpy(address, scratch, sizeof address);
- address[sizeof address - 1] = '\0';
- p = IDX(address, '@');
- *p++ = '\0';
- }
-
- /* Policy decision; what to put in the path? */
- #ifdef FIXED_PATH
- Strcpy(hp->path, FIXED_PATH);
- #else
- #ifdef GATEWAY
- Sprintf(scratch, "%s!%s!%s", GATEWAY, p, address);
- #else
- Sprintf(scratch, "%s!%s", p, address);
- #endif /* GATEWAY */
- Strncpy(hp->path, scratch, sizeof hp->path);
- hp->path[sizeof hp->path - 1] = '\0';
- #endif /* FIXED_PATH */
-
- /* Restore the @ if we took it out. */
- if (p)
- *--p = '@';
-
- if (fullname[0]) {
- p = address + strlen(address);
- *p++ = ' ';
- *p++ = '(';
- p += APPEND(p, fullname);
- *p++ = ')';
- *p++ = '\0';
- }
-
- /* Stick the canonicalized From: back in. */
- Strcpy(hp->from, address);
- }
-
-
- #define ERROR "\
- Message-ID syntax error.\n\
- *** Please refer to page 23, paragraph 4.6.1. and Appendix D\n\
- *** of NIC RFC #822 for the correct syntax, and fix your mailer."
-
- /*
- ** Check an RFC822 header for validity and hack it to RFC1036 spec.
- ** returns NULL for everything OK, or a character pointer to an
- ** error message.
- */
- char *
- HackHeader(hp, SubjectRequired)
- register HBUF *hp;
- int SubjectRequired;
- {
- #ifdef REQUIRE_MESSAGE_ID
- /* Sendmail (almost) always has a Message-ID */
- if (hp->ident[0] == '\0')
- return "Message-ID header missing";
- if (!FixMessageID(hp->ident))
- return ERROR;
- #else
- /* MMDF doesn't always have a Message-ID. */
- if (hp->ident[0] && !FixMessageID(hp->ident))
- return ERROR;
- #endif /* REQUIRE_MESSAGE_ID */
-
- /* Newsgroups */
- if (hp->nbuf[0] == '\0')
- return "Newsgroups header missing";
-
- /* Subject */
- if (hp->title[0] == '\0') {
- if (SubjectRequired)
- return "Subject header missing";
- Strcpy(hp->title, "(none)");
- }
-
- /* From */
- if (hp->from[0] == '\0')
- return "From header missing";
- FixFrom(hp);
-
- /* References and In-Reply-To */
- if (hp->followid[0])
- FixReferences(hp);
-
- return NULL;
- }
-
-
- #ifdef TEST
- main()
- {
- char buff[256];
- int i;
-
- if (i = isatty(0))
- (void)printf("Enter addresses:\n");
- for ( ; ; ) {
- if (i)
- (void)printf("> ");
- if (gets(buff) == NULL || buff[0] == '\0')
- break;
- if (buff[0] != '#')
- (void)printf("\t%s -> %s\n\n", buff, FixAddress(buff));
- }
-
- exit(0);
- }
- #endif /* TEST */
-