home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / newsgate / part03 / hdr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-09  |  10.4 KB  |  520 lines

  1. /*
  2. **  Header-cracking and address re-writing routines, with sincere
  3. **  apologies to Upas and Sendmail.
  4. */
  5. #include "gate.h"
  6. #include <netdb.h>
  7. #ifdef    RCSID
  8. static char RCS[] =
  9.     "$Header: /nfs/papaya/u2/rsalz/src/newsgate/src/RCS/hdr.c,v 1.15 91/03/15 16:39:42 rsalz Exp $";
  10. #endif    /* RCSID */
  11.  
  12.  
  13. #ifdef    TEST
  14. #ifndef    DO_FIX_ADDRESS
  15. #define DO_FIX_ADDRESS
  16. #endif    /* DO_FIX_ADDRESS */
  17. #define dprintf(string, buff)    (void)printf((string), (buff))
  18. #else
  19. #define dprintf(string, buff)    /* NULL */
  20. #endif    /* TEST */
  21.  
  22.  
  23. /*
  24. **  List of domains that we recognize.
  25. */
  26. STATIC char    RELAY_CS_NET[] = "RELAY.CS.NET";
  27. STATIC char    *Domains[] = {
  28.     /* Don't undo the % hack for sites @RELAY.CS.NET, sigh #1. */
  29.     RELAY_CS_NET,
  30.     /* These aren't official domains, but we use them, sigh #2. */
  31.     ".BITNET",
  32.     ".UUCP",
  33.     /* Official organizational domains. */
  34.     ".ARPA",    ".COM",    ".EDU",    ".GOV",    ".INT",    ".MIL",
  35.     ".NATO",    ".NET",    ".ORG",
  36.     /* Official natonal domans. */
  37.     ".AR",    ".AT",    ".AU",    ".BE",    ".BR",    ".CA",    ".CH",    ".CL",
  38.     ".CN",    ".CR",    ".CS",    ".DE",    ".DK",    ".EC",    ".EG",    ".ES",
  39.     ".FI",    ".FR",    ".GR",    ".HK",    ".HU",    ".IE",    ".IL",    ".IN",
  40.     ".IS",    ".IT",    ".JP",    ".KR",    ".LK",    ".MX",    ".MY",    ".NI",
  41.     ".NL",    ".NO",    ".NZ",    ".PH",    ".PL",    ".PR",    ".PT",    ".SE",
  42.     ".SG",    ".SU",    ".TH",    ".TR",    ".TW",    ".UK",    ".US",    ".UY",
  43.     ".YU",    ".ZA"
  44. };
  45.  
  46.  
  47. /*
  48. **  Local user?
  49. */
  50. STATIC int
  51. Local(p)
  52.     register char    *p;
  53. {
  54.     for ( ; *p; p++)
  55.     if (NETCHR(*p))
  56.         break;
  57.     return *p == '\0';
  58. }
  59.  
  60.  
  61. /*
  62. **  Case-insensitive strncmp.
  63. */
  64. STATIC char *
  65. Found(dp, p)
  66.     register char    *dp;
  67.     register char    *p;
  68. {
  69.     register char    *q;
  70.     register char    *r;
  71.  
  72.     for ( ; *p; p++)
  73.     if (CHREQ(*p, *dp)) {
  74.         for (q = p, r = dp; *r && CHREQ(*q, *r); q++, r++)
  75.         ;
  76.         if (*r == '\0')
  77.         return p;
  78.     }
  79.  
  80.     return NULL;
  81. }
  82.  
  83.  
  84. /*
  85. **  Find all domain names and make them uppercase:
  86. **    joe%site.edu@relay.cs.net --> joe%site.EDU@RELAY.CS.NET
  87. */
  88. STATIC void
  89. Casify(p)
  90.     register char    *p;
  91. {
  92.     register char    *q;
  93.     register char    *r;
  94.     register char    **dp;
  95.  
  96.     for (dp = Domains; dp < ENDOF(Domains); dp++)
  97.     for (q = p; q = Found(*dp, q); )
  98.         for (r = *dp; *r; *q++ = *r++)
  99.         ;
  100. }
  101.  
  102.  
  103. /*
  104. **  Handle route-addresses:
  105. **    @cruft:joe@site --> joe@site
  106. */
  107. STATIC void
  108. RouteAddr(p)
  109.     register char    *p;
  110. {
  111.     register char    *q;
  112.     register char    *r;
  113.  
  114.     for (r = p; *p == '@'; p = q)
  115.     if ((q = IDX(p, ':')) && IDX(q, '@'))
  116.         *q++ = '\0';
  117.     else
  118.         break;
  119.     if (p > r)
  120.     /* Avoid overlaping strcpy() call. */
  121.     while (*r++ = *p++)
  122.         ;
  123. }
  124.  
  125. /*
  126. **  Does the pattern exist in the character range between p and end?
  127. */
  128. STATIC int
  129. Between(p, pat, q)
  130.     register char    *p;
  131.     register char    *pat;
  132.     register char    *q;
  133. {
  134.     register char    *r;
  135.  
  136.     for (r = pat + strlen(pat); p < q && r >= pat && *--q == *--r; )
  137.     ;
  138.     return *r == '\0';
  139. }
  140.  
  141.  
  142. /*
  143. **  Handle the '%' syntax:
  144. **    joe%site.EDU@gateway.DOMAIN -> joe@site.EDU
  145. */
  146. STATIC void
  147. Percent(p)
  148.     register char    *p;
  149. {
  150.     register char    *q;
  151.     register char    *r;
  152.     register char    **dp;
  153.  
  154.     while ((r = IDX(p, '%')) && (q = IDX(r, '@'))) {
  155.     for (dp = Domains; dp < ENDOF(Domains); dp++) {
  156.         if (*dp == RELAY_CS_NET)
  157.         continue;
  158.         if (Between(r, *dp, q)) {
  159.         *RDX(p, '@') = '\0';
  160.         *RDX(p, '%') = '@';
  161.         break;
  162.         }
  163.     }
  164.     if (dp == ENDOF(Domains))
  165.         break;
  166.     }
  167. }
  168.  
  169.  
  170. /*
  171. **  Handle CSNET, which is domainist except in some people's minds:
  172. **    joe%site@RELAY.CS.NET --> joe@site.CSNET
  173. **    joe%site.EDU@RELAY.CS.NET --> joe@site.EDU
  174. */
  175. STATIC void
  176. Csnet(p)
  177.     register char    *p;
  178. {
  179.     register char    *q;
  180.     register char    *r;
  181.  
  182.     if ((q = RDX(p, '@'))
  183.      && strcmp(q, "@RELAY.CS.NET") == 0
  184.      && (r = RDX(p, '%'))) {
  185.     *RDX(p, '@') = '\0';
  186.     *r = '@';
  187.     if (IDX(r, '.') == NULL)
  188.         Strcat(p, ".CSNET");
  189.     }
  190. }
  191.  
  192.  
  193. /*
  194. **  Handle hybrid "!" and "@" addresses:
  195. **    a!site!joe@site --> joe@site
  196. **    a!site!joe --> joe@site.UUCP
  197. **    a!site.EDU!joe --> joe@site.EDU
  198. */
  199. STATIC void
  200. Hybrid(p)
  201.     register char    *p;
  202. {
  203.     register char    *q;
  204.     register char    *user;
  205.     char        buff[SM_SIZE];
  206.  
  207.     if (user = RDX(p, '!')) {
  208.     *user++ = '\0';
  209.     if (q = IDX(user, '@'))
  210.         *q = '\0';
  211.     q = (q = RDX(p, '!')) ? q + 1 : p;
  212.     Sprintf(buff, "%s@%s", user, q);
  213.     if (IDX(q, '.') == NULL)
  214.         Strcat(buff, ".UUCP");
  215.     Strcpy(p, buff);
  216.     }
  217. }
  218.  
  219.  
  220. /*
  221. **  Handle special case for Australia:
  222. **    user@site.OZ --> user@site.OZ.AU
  223. */
  224. STATIC void
  225. Endpart(p)
  226.     register char    *p;
  227. {
  228.     register char    *r;
  229.  
  230.     if ((r = RDX(p, '.')) && r[1] == 'O' && r[2] == 'Z' && r[3] == '\0')
  231.     Strcpy(&r[3], ".AU");
  232. }
  233.  
  234.  
  235. /*
  236. **  General address canonicalizer.
  237. */
  238. STATIC char *
  239. FixAddress(p)
  240.     register char    *p;
  241. {
  242.     static char        buff[1024];
  243.     char        host[128];
  244.  
  245.     if (Local(p)) {
  246.     if (gethostname(host, sizeof host) < 0) {
  247.         Fprintf(stderr, "%s:  Can't get my hostname, %s.\n",
  248.             Pname, strerror(errno));
  249.         exit(EX_TEMPFAIL);
  250.     }
  251.     Sprintf(buff, "%s@%s", p, host);
  252.     }
  253.     else {
  254.     Strcpy(buff, p);
  255.     Casify(buff);
  256.     dprintf("   Casify returns %s\n", buff);
  257.     RouteAddr(buff);
  258.     dprintf("RouteAddr returns %s\n", buff);
  259.     Percent(buff);
  260.     dprintf("  Percent returns %s\n", buff);
  261.     Csnet(buff);
  262.     dprintf("    Csnet returns %s\n", buff);
  263.     Hybrid(buff);
  264.     dprintf("   Hybrid returns %s\n", buff);
  265.     Endpart(buff);
  266.     dprintf("  Endpart returns %s\n", buff);
  267.     }
  268.     return buff;
  269. }
  270.  
  271.  
  272. /*
  273. **  This subroutine is a concession to the realities of the Internet and
  274. **  and the USENET. Much as the idea is distasteful and likely to get me
  275. **  in trouble, I have to hack message-ids into a format that the USENET
  276. **  won't choke on.  Pray that if we're doing multiple insertion point
  277. **  gatewaying that ALL the gateways mung exactly the same things.
  278. **
  279. **  (Death to HERMES! Death to UNIX/MM-11! Death to EAN!)
  280. */
  281. STATIC int
  282. FixMessageID(s)
  283.     register char    *s;
  284. {
  285.     register int    atdot;
  286.     register int    closed;
  287.  
  288.     /* Quickie tests -- why waste time? */
  289.     if (*s != '<')
  290.     return FALSE;
  291.  
  292.     for (atdot = FALSE, closed = FALSE; *++s; )
  293.     switch (*s) {
  294.     default:
  295.         if (!isascii(*s) || iscntrl(*s) || isspace(*s))
  296.         return FALSE;
  297.         break;
  298.     case '<':
  299.         /* Already got one. */
  300.         return FALSE;
  301.     case '>':
  302.         /* I hope no one is stupid enough to quote this... */
  303.         closed = TRUE;
  304.         s[1] = '\0';
  305.         break;
  306.     case '.':
  307.     case '@':
  308.         /* We should check for a domain spec, not just either/or. */
  309.         atdot = TRUE;
  310.         break;
  311.     case '\t':
  312.     case ' ':
  313.     case '/':
  314.         /* Avoid various problem characters. */
  315.         *s = '.';
  316.         break;
  317.     }
  318.  
  319.     return atdot && closed;
  320. }
  321.  
  322.  
  323. /*
  324. **  Fix up the contents of In-Reply-To: fields and References: fields.
  325. */
  326. STATIC void
  327. FixReferences(hp)
  328.     register HBUF        *hp;
  329. {
  330.     register char        *cp;
  331.     register char        *ep;
  332.     register char        *p;
  333.     register char        *max;
  334.     char            scratch[LG_SIZE];
  335.  
  336.     cp = hp->followid;
  337.     max = cp + strlen(cp);
  338.     for (p = scratch; cp = IDX(cp, '<'); ) {
  339.     if ((ep = IDX(cp, '>')) == NULL
  340.      || ((ep - cp) + 1) > sizeof scratch - (p - scratch + 2))
  341.         /* Unterminated ID, or no more room. */
  342.         break;
  343.  
  344.     if (FixMessageID(cp)) {
  345.         if (p > scratch) {
  346.         *p++ = ' ';
  347.         *p++ = '\0';
  348.         }
  349.         p += APPEND(p, cp);
  350.     }
  351.     cp = ep + 2;
  352.     if (cp >= max)
  353.         break;
  354.     }
  355.     Strcpy(hp->followid, scratch);
  356. }
  357.  
  358.  
  359. /*
  360. **  Count the number of '@' in the string.
  361. */
  362. STATIC int
  363. AtCount(s)
  364.     register char    *s;
  365. {
  366.     register int    n;
  367.  
  368.     for (n = 0; *s; s++)
  369.     if (*s == '@')
  370.         n++;
  371.     return n;
  372. }
  373.  
  374.  
  375. /*
  376. **  Canonicalize the "From:" line into the form
  377. **    From: local-part@domain (full-name)
  378. ** RFC822 doesn't require the comment to be at the end of the string
  379. ** like that.
  380. */
  381. STATIC void
  382. FixFrom(hp)
  383.     register HBUF        *hp;
  384. {
  385.     register char        *p;
  386.     register struct hostent    *host;
  387.     char            address[LG_SIZE];
  388.     char            fullname[LG_SIZE];
  389.     char            scratch[sizeof address];
  390.  
  391.     /* We should handle "Full-Name:" too, but it doesn't get read by the
  392.      * news header reader. */
  393.     (void)CrackFrom(address, fullname, hp->from);
  394. #ifdef    DO_ADDRESS_CLEANUP
  395.     Strcpy(address, FixAddress(address));
  396. #endif    /* DO_ADDRESS_CLEANUP */
  397.  
  398.     if (AtCount(address) != 1)
  399.     p = NULL;
  400.     else {
  401.     p = IDX(address, '@');
  402.     *p++ = '\0';
  403.  
  404. #ifdef    DO_ADDRESS_CLEANUP
  405.     /* If we can find the host's official name use that. */
  406.     if (host = gethostbyname(p))
  407.         p = host->h_name;
  408. #endif    /* DO_ADDRESS_CLEANUP */
  409.  
  410.     /* We know have the canonical hostname; glue back together. */
  411.     Sprintf(scratch, "%s@%s", address, p);
  412.     Strncpy(address, scratch, sizeof address);
  413.     address[sizeof address - 1] = '\0';
  414.     p = IDX(address, '@');
  415.     *p++ = '\0';
  416.     }
  417.  
  418.     /* Policy decision; what to put in the path? */
  419. #ifdef    FIXED_PATH
  420.     Strcpy(hp->path, FIXED_PATH);
  421. #else
  422. #ifdef    GATEWAY
  423.     Sprintf(scratch, "%s!%s!%s", GATEWAY, p, address);
  424. #else
  425.     Sprintf(scratch, "%s!%s", p, address);
  426. #endif    /* GATEWAY */
  427.     Strncpy(hp->path, scratch, sizeof hp->path);
  428.     hp->path[sizeof hp->path - 1] = '\0';
  429. #endif    /* FIXED_PATH */
  430.  
  431.     /* Restore the @ if we took it out. */
  432.     if (p)
  433.     *--p = '@';
  434.  
  435.     if (fullname[0]) {
  436.     p = address + strlen(address);
  437.     *p++ = ' ';
  438.     *p++ = '(';
  439.     p += APPEND(p, fullname);
  440.     *p++ = ')';
  441.     *p++ = '\0';
  442.     }
  443.  
  444.     /* Stick the canonicalized From: back in. */
  445.     Strcpy(hp->from, address);
  446. }
  447.  
  448.  
  449. #define ERROR "\
  450. Message-ID syntax error.\n\
  451. *** Please refer to page 23, paragraph 4.6.1. and Appendix D\n\
  452. *** of NIC RFC #822 for the correct syntax, and fix your mailer."
  453.  
  454. /*
  455. ** Check an RFC822 header for validity and hack it to RFC1036 spec.
  456. ** returns NULL for everything OK, or a character pointer to an
  457. ** error message.
  458. */
  459. char *
  460. HackHeader(hp, SubjectRequired)
  461.     register HBUF        *hp;
  462.     int                SubjectRequired;
  463. {
  464. #ifdef    REQUIRE_MESSAGE_ID
  465.     /* Sendmail (almost) always has a Message-ID */
  466.     if (hp->ident[0] == '\0')
  467.     return "Message-ID header missing";
  468.     if (!FixMessageID(hp->ident))
  469.     return ERROR;
  470. #else
  471.     /* MMDF doesn't always have a Message-ID. */
  472.     if (hp->ident[0] && !FixMessageID(hp->ident))
  473.     return ERROR;
  474. #endif    /* REQUIRE_MESSAGE_ID */
  475.  
  476.     /* Newsgroups */
  477.     if (hp->nbuf[0] == '\0')
  478.     return "Newsgroups header missing";
  479.  
  480.     /* Subject */
  481.     if (hp->title[0] == '\0') {
  482.     if (SubjectRequired)
  483.         return "Subject header missing";
  484.     Strcpy(hp->title, "(none)");
  485.     }
  486.  
  487.     /* From */
  488.     if (hp->from[0] == '\0')
  489.     return "From header missing";
  490.     FixFrom(hp);
  491.  
  492.     /* References and In-Reply-To */
  493.     if (hp->followid[0]) 
  494.     FixReferences(hp);
  495.  
  496.     return NULL;
  497. }
  498.  
  499.  
  500. #ifdef    TEST
  501. main()
  502. {
  503.     char    buff[256];
  504.     int        i;
  505.  
  506.     if (i = isatty(0))
  507.     (void)printf("Enter addresses:\n");
  508.     for ( ; ; ) {
  509.     if (i)
  510.         (void)printf(">  ");
  511.     if (gets(buff) == NULL || buff[0] == '\0')
  512.         break;
  513.     if (buff[0] != '#')
  514.         (void)printf("\t%s -> %s\n\n", buff, FixAddress(buff));
  515.     }
  516.  
  517.     exit(0);
  518. }
  519. #endif    /* TEST */
  520.